summaryrefslogtreecommitdiff
path: root/avr
diff options
context:
space:
mode:
authorLeo C2014-11-22 13:07:04 +0100
committerLeo C2014-11-22 13:07:04 +0100
commit7f552300815ccadd45ebb3e7f0ae72a3b2e0c4e5 (patch)
tree1bb9ac83ce7fb1f6a99c6dd3445b2758330dcc95 /avr
parent05994bd90cb36f10ff72c6a70d7cecc61b67fb2f (diff)
downloadz180-stamp-7f552300815ccadd45ebb3e7f0ae72a3b2e0c4e5.zip
Integrate fatfs. Add some sd card test commands.
Diffstat (limited to 'avr')
-rw-r--r--avr/cmd_sd.c289
-rw-r--r--avr/command_tbl.c18
-rw-r--r--avr/main.c11
-rw-r--r--avr/mmc.c637
-rw-r--r--avr/timer.c4
5 files changed, 944 insertions, 15 deletions
diff --git a/avr/cmd_sd.c b/avr/cmd_sd.c
new file mode 100644
index 0000000..55acf2f
--- /dev/null
+++ b/avr/cmd_sd.c
@@ -0,0 +1,289 @@
+#include "common.h"
+#include <stdlib.h>
+
+#include "diskio.h"
+#include "ff.h"
+#include "command.h"
+#include "print-utils.h"
+
+
+static const FLASH char * const FLASH rc_names[] = {
+ FSTR("OK"),
+ FSTR("DISK_ERR"),
+ FSTR("INT_ERR"),
+ FSTR("NOT_READY"),
+ FSTR("NO_FILE"),
+ FSTR("NO_PATH"),
+ FSTR("INVALID_NAME"),
+ FSTR("DENIED"),
+ FSTR("EXIST"),
+ FSTR("INVALID_OBJECT"),
+ FSTR("WRITE_PROTECTED"),
+ FSTR("INVALID_DRIVE"),
+ FSTR("NOT_ENABLED"),
+ FSTR("NO_FILE_SYSTEM"),
+ FSTR("MKFS_ABORTED"),
+ FSTR("TIMEOUT"),
+ FSTR("LOCKED"),
+ FSTR("NOT_ENOUGH_CORE"),
+ FSTR("TOO_MANY_OPEN_FILES")
+ };
+
+static
+void put_rc (FRESULT rc)
+{
+#if 0
+ printf_P(PSTR("rc=%u FR_%S\n"), rc, rc_names[rc]);
+#else
+ printf_P(PSTR("rc=%u FR_"), rc);
+ my_puts_P(rc_names[rc]);
+ printf_P(PSTR("\n"));
+
+#endif
+
+}
+
+#define BUFF_SIZE 1024
+BYTE Buff[BUFF_SIZE]; /* Working buffer */
+
+static DWORD last_sect;
+
+
+/*
+ * dd <pd#> [<sector>] - Dump sector
+ *
+ */
+command_ret_t do_dd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ FRESULT res;
+ BYTE dev;
+ unsigned long sec;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ dev = (BYTE) strtoul(argv[1], 0, 10);
+
+ if (argc > 2)
+ sec = strtoul(argv[2], 0, 10);
+ else
+ sec = last_sect;
+
+ res = disk_read(dev, Buff, sec, 1);
+
+ if (res) {
+ printf_P(PSTR("rc=%.2x\n"), res);
+ return CMD_RET_FAILURE;
+ }
+
+ last_sect = sec + 1;
+ printf_P(PSTR("Sector:%lu\n"), sec);
+ dump_ram((uint32_t) (size_t) Buff, 0, 0x200, NULL);
+
+ return CMD_RET_SUCCESS;
+}
+
+/*
+ * di <pd#> - Initialize disk
+ *
+ */
+command_ret_t do_di(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ FRESULT res;
+ BYTE dev;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ dev = (BYTE) strtoul(argv[1], 0, 10);
+ res = disk_status(dev);
+ printf_P(PSTR("disk_status=%.2x\n"), res);
+
+ if ((res & STA_NODISK) == 0) {
+ res = disk_initialize(dev);
+ }
+ printf_P(PSTR("rc=%.2x\n"), res);
+ if (res) {
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+/*
+ * ds <pd#> - Show disk status
+ *
+ */
+command_ret_t do_ds(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ BYTE dev;
+
+ union {
+ unsigned long lval;
+ unsigned char cval;
+ } dat;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ dev = (BYTE) strtoul(argv[1], 0, 10);
+
+
+ if (disk_ioctl(dev, GET_SECTOR_COUNT, &dat.lval) == RES_OK)
+ printf_P(PSTR("Drive size: %lu sectors\n"), dat.lval);
+
+ if (disk_ioctl(dev, GET_BLOCK_SIZE, &dat.lval) == RES_OK)
+ printf_P(PSTR("Erase block: %lu sectors\n"), dat.lval);
+
+ if (disk_ioctl(dev, MMC_GET_TYPE, &dat.cval) == RES_OK)
+ printf_P(PSTR("Card type: %u\n"), dat.cval);
+
+ if (disk_ioctl(dev, MMC_GET_CSD, Buff) == RES_OK)
+ dump_ram((uint32_t) (size_t) Buff, 0, 16, "CSD:");
+
+ if (disk_ioctl(dev, MMC_GET_CID, Buff) == RES_OK)
+ dump_ram((uint32_t) (size_t) Buff, 0, 16, "CID:");
+
+ if (disk_ioctl(dev, MMC_GET_OCR, Buff) == RES_OK)
+ dump_ram((uint32_t) (size_t) Buff, 0, 4, "OCR:");
+
+ if (disk_ioctl(dev, MMC_GET_SDSTAT, Buff) == RES_OK)
+ dump_ram((uint32_t) (size_t) Buff, 0, 64, "SD Status:");
+
+ if (disk_ioctl(dev, ATA_GET_MODEL, Buff) == RES_OK) {
+ Buff[40] = '\0';
+ printf_P(PSTR("Model: %s\n"), Buff);
+ }
+ if (disk_ioctl(dev, ATA_GET_SN, Buff) == RES_OK) {
+ Buff[20] = '\0'; printf_P(PSTR("S/N: %s\n"), Buff);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+
+
+/*
+ * Disk ioctl
+ * dcs <pd#> - CTRL_SYNC
+ *
+ */
+command_ret_t do_dcs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ BYTE dev;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ dev = (BYTE) strtoul(argv[1], 0, 10);
+ printf_P(PSTR("rc=%.2x\n"), disk_ioctl(dev, CTRL_SYNC, 0));
+
+ return CMD_RET_SUCCESS;
+}
+
+
+
+command_ret_t do_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ (void) cmdtp; (void) flag;
+ (void) argc; (void) argv;
+
+ printf_P(_USE_LFN ? PSTR("LFN Enabled") : PSTR("LFN Disabled"));
+ printf_P(PSTR(", Code page: %u\n"), _CODE_PAGE);
+
+ for (FRESULT i=0; i<19; i++)
+ put_rc(i);
+
+
+ return CMD_RET_SUCCESS;
+}
+
+extern command_ret_t do_echo(cmd_tbl_t *, int, int, char * const []);
+
+
+static
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+cmd_tbl_t cmd_sd_sub[] = {
+CMD_TBL_ITEM(
+ dd, CONFIG_SYS_MAXARGS, 1, do_dd,
+ "Dump sector",
+ ""
+),
+CMD_TBL_ITEM(
+ di, 2, 1, do_di,
+ "Initialize disk",
+ ""
+),
+CMD_TBL_ITEM(
+ ds, 2, 1, do_ds,
+ "Disk status",
+ ""
+),
+CMD_TBL_ITEM(
+ dcs, 2, 1, do_dcs,
+ "Device control: SYNC",
+ ""
+),
+CMD_TBL_ITEM(
+ echo, CONFIG_SYS_MAXARGS, 1, do_echo,
+ "sane as echo (simple test)", ""
+),
+CMD_TBL_ITEM(
+ test, CONFIG_SYS_MAXARGS, 1, do_test,
+ "print some compiled in parameters", ""
+),
+CMD_TBL_ITEM(
+ help, CONFIG_SYS_MAXARGS, 1, do_help,
+ "print sub command description/usage",
+ "\n"
+ " - print brief description of all sub commands\n"
+ "sd help command ...\n"
+ " - print detailed usage of sub cmd 'command'"
+),
+
+/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
+ {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
+ FSTR("alias for 'help'"),
+#ifdef CONFIG_SYS_LONGHELP
+ FSTR(""),
+#endif /* CONFIG_SYS_LONGHELP */
+#ifdef CONFIG_AUTO_COMPLETE
+ 0,
+#endif
+},
+};
+
+static
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return _do_help(cmd_sd_sub, ARRAY_SIZE(cmd_sd_sub), cmdtp, flag, argc, argv);
+}
+
+
+command_ret_t do_sd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *cp;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ /* drop initial "sd" arg */
+ argc--;
+ argv++;
+
+ cp = find_cmd_tbl(argv[0], cmd_sd_sub, ARRAY_SIZE(cmd_sd_sub));
+
+ if (cp)
+ return cp->cmd(cmdtp, flag, argc, argv);
+
+ return CMD_RET_USAGE;
+}
diff --git a/avr/command_tbl.c b/avr/command_tbl.c
index 97110fd..6b53fad 100644
--- a/avr/command_tbl.c
+++ b/avr/command_tbl.c
@@ -231,6 +231,13 @@ CMD_TBL_ITEM(
),
#endif /* CONFIG_MX_CYCLIC */
+CMD_TBL_ITEM(
+ sd, CONFIG_SYS_MAXARGS, 1, do_sd,
+ "SD/MMC card handling commands",
+ "<subcommand> args ...\n"
+ "sd help\n"
+ " - print help on subcommands"
+),
CMD_TBL_ITEM(
help, CONFIG_SYS_MAXARGS, 1, do_help,
@@ -241,17 +248,6 @@ CMD_TBL_ITEM(
" - print detailed usage of 'command'"
),
-/* TODO: make macro CMD_TBL_ITEM work with this */
- {FSTR("sd"), CONFIG_SYS_MAXARGS, 1, do_sd,
- FSTR("SD/MMC card handling commands"),
-#ifdef CONFIG_SYS_LONGHELP
- sd_help_text,
-#endif /* CONFIG_SYS_LONGHELP */
-#ifdef CONFIG_AUTO_COMPLETE
- 0,
-#endif
-},
-
/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
{FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
FSTR("alias for 'help'"),
diff --git a/avr/main.c b/avr/main.c
index 2f9a62f..af082a3 100644
--- a/avr/main.c
+++ b/avr/main.c
@@ -18,6 +18,7 @@
#include "cli.h"
#include "env.h"
#include "z180-serv.h"
+#include "spi.h"
static uint8_t mcusr;
@@ -108,8 +109,15 @@ void setup_avr(void)
TCCR3B = (0b01<<WGM32)|(0b001<<CS30); /* CTC Mode, Prescaler 1 */
TIMSK3 = _BV(OCIE3A); /* Enable TC2.oca interrupt */
+ /* SPI as master */
+ PRR0 &= ~_BV(PRSPI);
+ SPI_DDR = (SPI_DDR & ~_BV(SPI_MISO))
+ | _BV(SPI_MOSI) | _BV(SPI_SCK) | _BV(SPI_SS);
+ SPI_PORT = (SPI_PORT & ~(_BV(SPI_MOSI) | _BV(SPI_SCK)))
+ | _BV(SPI_SS);
+
/* INT5, INT6: falling edge */
- EICRB = (EICRB & ~((0b11 << ISC50) | (0b11 << ISC60))) |
+ EICRB = (EICRB & ~((0b11 << ISC50) | (0b11 << ISC60))) |
(0b10 << ISC50) | (0b10 << ISC60);
/* Reset pending ints */
EIFR |= _BV(INTF5) | _BV(INTF6);
@@ -219,7 +227,6 @@ void main_loop(void)
int main(void)
{
-
setup_avr();
z80_setup_bus();
diff --git a/avr/mmc.c b/avr/mmc.c
new file mode 100644
index 0000000..eb10ea6
--- /dev/null
+++ b/avr/mmc.c
@@ -0,0 +1,637 @@
+/*-----------------------------------------------------------------------*/
+/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2007 */
+/*-----------------------------------------------------------------------*/
+/* Only spi_rcvr(), spi_xmit(), disk_timerproc() and some macros */
+/* are platform dependent. */
+/*-----------------------------------------------------------------------*/
+
+#include <avr/io.h>
+#include <stdbool.h>
+#include "timer.h"
+#include "spi.h"
+#include "diskio.h"
+#include "debug.h"
+#include "print-utils.h"
+
+
+/* Definitions for MMC/SDC command */
+#define CMD0 (0) /* GO_IDLE_STATE */
+#define CMD1 (1) /* SEND_OP_COND (MMC) */
+#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
+#define CMD8 (8) /* SEND_IF_COND */
+#define CMD9 (9) /* SEND_CSD */
+#define CMD10 (10) /* SEND_CID */
+#define CMD12 (12) /* STOP_TRANSMISSION */
+#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
+#define CMD16 (16) /* SET_BLOCKLEN */
+#define CMD17 (17) /* READ_SINGLE_BLOCK */
+#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
+#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
+#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
+#define CMD24 (24) /* WRITE_BLOCK */
+#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
+#define CMD55 (55) /* APP_CMD */
+#define CMD58 (58) /* READ_OCR */
+
+
+/* SD card socket connections */
+#if 0
+//#define MMC_PORT PORTG /* Socket contact port */
+//#define MMC_INPORT PING
+//#define SD_WP_PIN 5 /* Write protect switch */
+#endif
+
+/* SD card SPI access */
+#define SD_CD_PORT PORTG
+#define SD_CD_DDR DDRG
+#define SD_CD_INPORT PING
+#define SD_CD_PIN 3 /* Card detect switch */
+
+#define SD_WP_PORT PORTG
+#define SD_WP_DDR DDRG
+#define SD_WP_INPORT PING
+//#define SD_WP_PIN 5 /* Write protect switch */
+
+#define SD_CS_PORT PORTG
+#define SD_CS_DDR DDRG
+#define SD_CS_PIN 4 /* Chip select pin */
+
+
+/* Port Controls (Platform dependent) */
+
+#ifdef SD_CD_PIN
+static inline
+bool sd_cd(void)
+{
+ return (SD_CD_INPORT & _BV(SD_CD_PIN)) == 0;
+}
+#endif
+
+#ifdef SD_WP_PIN
+static inline
+bool sd_wp(void)
+{
+ return (SD_WP_INPORT & _BV(SD_WP_PIN)) == 0;
+}
+#endif
+
+#define CS_LOW() SD_CS_PORT &= ~(1<<SD_CS_PIN) /* MMC CS = L */
+#define CS_HIGH() SD_CS_PORT |= (1<<SD_CS_PIN) /* MMC CS = H */
+
+#define FCLK_SLOW() SPISetMMCInitClock() /* Set slow clock (100k-400k) */
+#define FCLK_FAST() SPISetFastClock() /* Set fast clock (depends on the CSD) */
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+ ---------------------------------------------------------------------------*/
+
+static volatile
+DSTATUS disk_stat = STA_NOINIT; /* Disk status */
+
+static
+BYTE CardType; /* Card type flags */
+
+/*-----------------------------------------------------------------------*/
+/* Wait for card ready */
+/*-----------------------------------------------------------------------*/
+
+static
+int wait_ready (void) /* 1:OK, 0:Timeout */
+{
+ uint32_t to = get_timer(0);
+
+ /* Wait for ready in timeout of 500ms */
+ do {
+ if (spi_rcvr() == 0xFF) {
+ return 1;
+ }
+ } while (get_timer(to) < 500);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Deselect the card and release SPI bus */
+/*-----------------------------------------------------------------------*/
+
+static
+void deselect (void)
+{
+// debug("*** enter deselect()\n");
+ CS_HIGH();
+ /* Dummy clock (TODO: force DO hi-z for multiple slave SPI) */
+ spi_rcvr();
+// debug("*** exit deselect()\n");
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Select the card and wait for ready */
+/*-----------------------------------------------------------------------*/
+
+static
+int select (void) /* 1:Successful, 0:Timeout */
+{
+// debug("*** enter select()\n");
+ CS_LOW();
+ /* Dummy clock (force DO enabled) */
+ spi_rcvr();
+
+ if (wait_ready()) {
+// debug("*** exit select() == 1\n");
+ return 1; /* OK */
+ }
+ deselect();
+// debug("*** exit select() == 0\n");
+
+ return 0; /* Timeout */
+}
+
+/*-----------------------------------------------------------------------*/
+/* Power Control (Platform dependent) */
+/*-----------------------------------------------------------------------*/
+/* When the target system does not support socket power control, there */
+/* is nothing to do in these functions and chk_power always returns 1. */
+
+static
+void power_on(void)
+{
+// debug("*** enter power_on()\n");
+
+#ifdef SD_PWR_PIN
+ SD_PWR_DDR |= _BV(SD_PWR_PIN); // Turns on PWR pin as output
+ SD_PWR_PORT &= ~_BV(SD_PWR_PIN); // Drives PWR pin high
+
+ for (uint32_t to = get_timer(0); get_timer(to) < 30;)
+ ; /* Wait for 30ms */
+#endif
+
+#ifdef SD_CD_PIN
+ /* Card detect, input with pullup */
+ SD_CD_DDR &= ~_BV(SD_CD_PIN);
+ SD_CD_PORT |= _BV(SD_CD_PIN);
+#endif
+#ifdef SD_WP_PIN
+ SD_WP_DDR &= ~_BV(SD_WP_PIN);
+ SD_WP_PORT |= _BV(SD_WP_PIN);
+#endif
+ SD_CS_PORT |= _BV(SD_CS_PIN);
+ SD_CS_DDR |= _BV(SD_CS_PIN); // Turns on CS pin as output
+
+// debug("*** exit power_on()\n");
+}
+
+static
+void power_off (void)
+{
+// debug("*** enter power_off()\n");
+ select(); /* Wait for card ready */
+ deselect();
+
+#ifdef SD_PWR_PIN
+ SD_PWR_PORT |= (1 << SD_PWR_PIN); /* Socket power OFF */
+#endif
+ disk_stat |= STA_NOINIT; /* Set STA_NOINIT */
+// debug("*** exit power_off()\n");
+}
+
+#if 0
+static
+int chk_power(void) /* Socket power state: 0=off, 1=on */
+{
+#ifdef SD_PWR_PIN
+ return (SD_PWR_PORT & (1 << SD_PWR_PIN)) ? 0 : 1;
+#else
+ return 1;
+#endif /* SD_PWR_PIN */
+}
+#endif
+
+/*-----------------------------------------------------------------------*/
+/* Receive a data packet from MMC */
+/*-----------------------------------------------------------------------*/
+
+static
+int rcvr_datablock (
+ BYTE *buff, /* Data buffer to store received data */
+UINT btr /* Byte count (must be multiple of 4) */
+) {
+ BYTE token, tmp;
+ uint32_t to = get_timer(0);
+
+ /* Wait for data packet in timeout of 200ms */
+ do {
+ token = spi_rcvr();
+ } while ((token == 0xFF) && get_timer(to) < 200);
+ if(token != 0xFE) return 0; /* If not valid data token, retutn with error */
+
+ tmp = spi_rcvr(); /* shift in first byte */
+ spi_write(0xff); /* start shift in next byte */
+ while (--btr) {
+ *buff++ = tmp;
+ asm volatile (""::"r"(buff), "r"(btr));
+ spi_wait();
+ tmp = SPDR;
+ spi_write(0xff);
+ }
+ *buff = tmp; /* store last byte in buffer while SPI module shifts in crc part1 */
+ spi_wait();
+ spi_rcvr(); /* second crc */
+
+ return 1; /* Return with success */
+}
+
+/*-----------------------------------------------------------------------*/
+/* Send a data packet to MMC */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_WRITE
+static
+int xmit_datablock (
+ const BYTE *buff, /* 512 byte data block to be transmitted */
+ BYTE token /* Data/Stop token */
+)
+{
+ BYTE resp, tmp;
+ UINT btr;
+
+ if (!wait_ready()) return 0;
+
+ spi_write(token); /* Xmit data token */
+ if (token != 0xFD) { /* Is data token */
+ btr = 512;
+ do {
+ tmp = *buff++;
+ spi_wait();
+ spi_write(tmp);
+ }while (--btr);
+ spi_wait();
+ spi_xmit(0xff); /* CRC (Dummy) */
+ spi_xmit(0xff);
+ resp = spi_rcvr(); /* Reveive data response */
+ return ((resp & 0x1F) != 0x05) ? 0 : 1; /* If not accepted, return with error */
+ }
+
+ spi_wait();
+ return 1;
+}
+#endif /* _USE_WRITE */
+
+/*-----------------------------------------------------------------------*/
+/* Send a command packet to MMC */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */
+ BYTE cmd, /* Command index */
+ DWORD arg /* Argument */
+) {
+ union {
+ DWORD as32;
+ BYTE as8[4];
+ } argtmp;
+ BYTE n, res;
+
+// debug("*** send_cmd( %.2x )\n", cmd);
+
+ if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
+ cmd &= 0x7F;
+ res = send_cmd(CMD55, 0);
+ if (res > 1)
+ return res;
+ }
+
+ /* Select the card and wait for ready except to stop multiple block read */
+ if (cmd != CMD12) {
+ deselect();
+ if (!select())
+ return 0xFF;
+ }
+
+ /* Send command packet */
+ spi_xmit(0x40 | cmd); /* Start + Command index */
+ argtmp.as32 = arg;
+ spi_xmit(argtmp.as8[3]); /* Argument[31..24] */
+ spi_xmit(argtmp.as8[2]); /* Argument[23..16] */
+ spi_xmit(argtmp.as8[1]); /* Argument[15..8] */
+ spi_xmit(argtmp.as8[0]); /* Argument[7..0] */
+
+ n = 0x01; /* Dummy CRC + Stop */
+ if (cmd == CMD0)
+ n = 0x95; /* Valid CRC for CMD0(0) */
+ if (cmd == CMD8)
+ n = 0x87; /* Valid CRC for CMD8(0x1AA) */
+ spi_xmit(n);
+
+ /* Receive command response */
+ if (cmd == CMD12)
+ spi_rcvr(); /* Skip a stuff byte when stop reading */
+ n = 10; /* Wait for a valid response in timeout of 10 attempts */
+ do
+ res = spi_rcvr();
+ while ((res & 0x80) && --n);
+
+ return res; /* Return with the response value */
+}
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+ ---------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive */
+/*-----------------------------------------------------------------------*/
+
+#define MMC_INIT_TO 1000 /* 1s */
+
+DSTATUS disk_initialize (
+ BYTE drv /* Physical drive nmuber (0) */
+)
+{
+ BYTE n, cmd, ty, ocr[4];
+
+ if (drv)
+ return STA_NOINIT; /* Supports only single drive */
+ if (disk_stat & STA_NODISK)
+ return disk_stat; /* No card in the socket */
+
+ power_on(); /* Force socket power on */
+ FCLK_SLOW();
+ for (n = 10; n; n--)
+ spi_rcvr(); /* 80 dummy clocks */
+
+ ty = 0;
+ if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
+ /* Init timeout timer */
+ uint32_t timer = get_timer(0);
+
+ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
+ for (n = 0; n < 4; n++) ocr[n] = spi_rcvr(); /* Get trailing return value of R7 resp */
+ if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
+ while (get_timer(timer) < MMC_INIT_TO && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
+ if (get_timer(timer) < MMC_INIT_TO && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
+ for (n = 0; n < 4; n++) ocr[n] = spi_rcvr();
+ ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
+ }
+ }
+ } else { /* SDv1 or MMCv3 */
+ if (send_cmd(ACMD41, 0) <= 1) {
+ ty = CT_SD1; cmd = ACMD41; /* SDv1 */
+ } else {
+ ty = CT_MMC; cmd = CMD1; /* MMCv3 */
+ }
+
+ /* Wait for leaving idle state */
+ while (get_timer(timer) < MMC_INIT_TO && send_cmd(cmd, 0));
+
+ /* Set R/W block length to 512 */
+ if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(CMD16, 512) != 0)
+ ty = 0;
+ }
+ }
+ CardType = ty;
+ deselect();
+
+ if (ty) { /* Initialization succeded */
+ disk_stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
+ FCLK_FAST();
+ } else { /* Initialization failed */
+ power_off();
+ }
+
+ return disk_stat;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Get Disk Status */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_status (
+ BYTE drv /* Physical drive nmuber (0) */
+)
+{
+ if (drv) return STA_NOINIT; /* Supports only single drive */
+ return disk_stat;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Read Sector(s) */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_read (
+ BYTE drv, /* Physical drive nmuber (0) */
+ BYTE *buff, /* Pointer to the data buffer to store read data */
+ DWORD sector, /* Start sector number (LBA) */
+ UINT count /* Sector count (1..255) */
+)
+{
+ BYTE cmd;
+
+ if (drv || !count) return RES_PARERR;
+ if (disk_stat & STA_NOINIT) return RES_NOTRDY;
+
+ if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
+
+ cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
+ if (send_cmd(cmd, sector) == 0) {
+ do {
+ if (!rcvr_datablock(buff, 512))
+ break;
+ buff += 512;
+ } while (--count);
+ if (cmd == CMD18)
+ send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
+ }
+ deselect();
+
+ return count ? RES_ERROR : RES_OK;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Write Sector(s) */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_WRITE
+DRESULT disk_write (
+ BYTE drv, /* Physical drive nmuber (0) */
+ const BYTE *buff, /* Pointer to the data to be written */
+ DWORD sector, /* Start sector number (LBA) */
+ UINT count /* Sector count (1..255) */
+)
+{
+ if (drv || !count) return RES_PARERR;
+ if (disk_stat & STA_NOINIT) return RES_NOTRDY;
+ if (disk_stat & STA_PROTECT) return RES_WRPRT;
+
+ if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
+
+ if (count == 1) { /* Single block write */
+ if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
+ && xmit_datablock(buff, 0xFE))
+ count = 0;
+ }
+ else { /* Multiple block write */
+ if (CardType & CT_SDC) send_cmd(ACMD23, count);
+ if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
+ do {
+ if (!xmit_datablock(buff, 0xFC)) break;
+ buff += 512;
+ }while (--count);
+ if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
+ count = 1;
+ }
+ }
+ deselect();
+
+ return count ? RES_ERROR : RES_OK;
+}
+#endif /* _USE_WRITE */
+
+/*-----------------------------------------------------------------------*/
+/* Miscellaneous Functions */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_IOCTL
+DRESULT disk_ioctl (
+ BYTE drv, /* Physical drive nmuber (0) */
+ BYTE cmd, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ DRESULT res;
+ BYTE n, csd[16], *ptr = buff;
+ DWORD csize;
+
+ if (drv)
+ return RES_PARERR;
+
+ res = RES_ERROR;
+
+ if (disk_stat & STA_NOINIT) return RES_NOTRDY;
+
+ switch (cmd) {
+ case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
+ if (select())
+ res = RES_OK;
+ break;
+
+ case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
+ if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
+ if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
+ csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
+ *(DWORD*)buff = csize << 10;
+ } else { /* SDC ver 1.XX or MMC*/
+ n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
+ csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
+ *(DWORD*)buff = csize << (n - 9);
+ }
+ res = RES_OK;
+ }
+ break;
+
+ case GET_BLOCK_SIZE: /* Get erase block size in unit of sector (DWORD) */
+ if (CardType & CT_SD2) { /* SDv2? */
+ if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
+ spi_rcvr();
+ if (rcvr_datablock(csd, 16)) { /* Read partial block */
+ for (n = 64 - 16; n; n--)
+ spi_rcvr(); /* Purge trailing data */
+ *(DWORD*) buff = 16UL << (csd[10] >> 4);
+ res = RES_OK;
+ }
+ }
+ } else { /* SDv1 or MMCv3 */
+ if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
+ if (CardType & CT_SD1) { /* SDv1 */
+ *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
+ } else { /* MMCv3 */
+ *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
+ }
+ res = RES_OK;
+ }
+ }
+ break;
+
+ /* Following commands are never used by FatFs module */
+
+ case MMC_GET_TYPE: /* Get card type flags (1 byte) */
+ *ptr = CardType;
+ res = RES_OK;
+ break;
+
+ case MMC_GET_CSD: /* Receive CSD as a data block (16 bytes) */
+ if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
+ && rcvr_datablock(ptr, 16))
+ res = RES_OK;
+ break;
+
+ case MMC_GET_CID: /* Receive CID as a data block (16 bytes) */
+ if (send_cmd(CMD10, 0) == 0 /* READ_CID */
+ && rcvr_datablock(ptr, 16))
+ res = RES_OK;
+ break;
+
+ case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
+ if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
+ for (n = 4; n; n--)
+ *ptr++ = spi_rcvr();
+ res = RES_OK;
+ }
+ break;
+
+ case MMC_GET_SDSTAT: /* Receive SD status as a data block (64 bytes) */
+ if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
+ spi_rcvr();
+ if (rcvr_datablock(ptr, 64))
+ res = RES_OK;
+ }
+ break;
+
+ case CTRL_POWER_OFF : /* Power off */
+ power_off();
+ disk_stat |= STA_NOINIT;
+ res = RES_OK;
+ break;
+
+ default:
+ res = RES_PARERR;
+ }
+
+ deselect();
+
+ return res;
+}
+#endif /* _USE_IOCTL */
+
+/*-----------------------------------------------------------------------*/
+/* Device Timer Interrupt Procedure (Platform dependent) */
+/*-----------------------------------------------------------------------*/
+/* This function must be called in period of 10ms */
+
+void disk_timerproc (void)
+{
+ BYTE s;
+
+ s = disk_stat;
+
+#ifdef SD_WP_PIN
+ if (sd_wp()) /* Write protected */
+ s |= STA_PROTECT;
+ else /* Write enabled */
+ s &= ~STA_PROTECT;
+#endif
+
+#ifdef SD_CD_PIN
+ if (sd_cd()) /* Card inserted */
+ s &= ~STA_NODISK;
+ else /* Socket empty */
+ s |= (STA_NODISK | STA_NOINIT);
+#endif
+
+ disk_stat = s; /* Update MMC status */
+}
diff --git a/avr/timer.c b/avr/timer.c
index 67b4a49..6fb19a8 100644
--- a/avr/timer.c
+++ b/avr/timer.c
@@ -25,6 +25,7 @@ ISR(TIMER3_COMPA_vect)
static int_fast8_t tick_10ms;
int_fast8_t i;
+ extern void disk_timerproc(void);
timestamp++;
@@ -34,7 +35,7 @@ ISR(TIMER3_COMPA_vect)
Stat |= S_10MS_TO;
/* Drive timer procedure of low level disk I/O module */
- //disk_timerproc();
+ disk_timerproc();
}
tick_10ms = i;
@@ -83,4 +84,3 @@ uint32_t get_timer(uint32_t base)
}
return ret - base;
}
-