X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/blobdiff_plain/7f552300815ccadd45ebb3e7f0ae72a3b2e0c4e5..78c900276102731b2832eb623b6d7216a32bd500:/avr/mmc.c diff --git a/avr/mmc.c b/avr/mmc.c index eb10ea6..d45cdf5 100644 --- a/avr/mmc.c +++ b/avr/mmc.c @@ -5,16 +5,54 @@ /* are platform dependent. */ /*-----------------------------------------------------------------------*/ -#include +#include "common.h" #include +#include #include "timer.h" #include "spi.h" #include "diskio.h" #include "debug.h" -#include "print-utils.h" +#define MAX_DRV 2 + +/* Port Controls (Platform dependent) */ +/* SD card socket connections */ + +/* TODO: config.h cofig macros */ + +//#define SD_CD_0 SBIT(PORT,) /* Card detect switch */ +//#define SD_CD_0_IN SBIT(PIN,) +//#define SD_CD_0_DDR SBIT(DDR,) + +//#define SD_WP_0 SBIT(PORT,) /* Write protect switch */ +//#define SD_WP_0_IN SBIT(PIN,) +//#define SD_WP_0_DDR SBIT(DDR,) + +#define SD_CS_0 SBIT(PORTB,0) /* Chip select/Card sense pin */ +//#define SD_CS_0_IN SBIT(PINB,0) +#define SD_CS_0_DDR SBIT(DDRB,0) + + +#define SD_CD_1 SBIT(PORTG,3) /* Card detect switch */ +#define SD_CD_1_IN SBIT(PING,3) +#define SD_CD_1_DDR SBIT(DDRG,3) + +//#define SD_WP_1 SBIT(PORTG,5) /* Write protect switch */ +//#define SD_WP_1_IN SBIT(PING,5) +//#define SD_WP_1_DDR SBIT(DDRG,5) + +#define SD_CS_1 SBIT(PORTG,4) /* Chip select/Card sense pin */ +//#define SD_CS_1_IN SBIT(PING,4) +#define SD_CS_1_DDR SBIT(DDRG,4) + + +#define SPI_CLK_SLOW() SPISetMMCInitClock() /* Set slow clock (100k-400k) */ +#define SPI_CLK_FAST() SPISetFastClock() /* Set fast clock (depends on the CSD) */ + +/*-------------------------------------------------------------------------- + Definitions for MMC/SDC command + ---------------------------------------------------------------------------*/ -/* 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) */ @@ -34,64 +72,23 @@ #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< is the command sequense of CMD55-CMD */ cmd &= 0x7F; - res = send_cmd(CMD55, 0); + res = send_cmd(drv, CMD55, 0); if (res > 1) return res; } + //debug("*** send_cmd( %.2x )", cmd); + /* Select the card and wait for ready except to stop multiple block read */ if (cmd != CMD12) { - deselect(); - if (!select()) + deselect(drv); + if (!select(drv)) { + //debug(" == %.2x\n", 0xff); return 0xFF; + } } /* Send command packet */ @@ -334,6 +382,7 @@ BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */ res = spi_rcvr(); while ((res & 0x80) && --n); + //debug(" == %.2x\n", res); return res; /* Return with the response value */ } @@ -343,6 +392,57 @@ BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */ ---------------------------------------------------------------------------*/ +void setup_mmc(void) +{ +#ifdef SD_PWR_0 + SD_PWR_1 = 1; /* Drives PWR pin low */ + SD_PWR_0_DDR = 1; /* Turns on PWR pin as output */ +#endif +#ifdef SD_WP_0 + SD_WP_0_DDR = 0; + SD_WP_0 = 1; /* Pullup */ +#endif + +#ifdef SD_PWR_1 + SD_PWR_1 = 1; /* Drives PWR pin low */ + SD_PWR_1_DDR = 1; /* Turns on PWR pin as output */ +#endif +#ifdef SD_WP_1 + SD_WP_1_DDR = 0; + SD_WP_1 = 1; /* Pullup */ +#endif + + /* SPI as master */ + PRR0 &= ~_BV(PRSPI); + SPI_DDR = (SPI_DDR & ~(_BV(SPI_MISO) | _BV(SPI_SS))) + | _BV(SPI_MOSI) | _BV(SPI_SCK); + SPI_PORT = SPI_PORT & ~(_BV(SPI_MOSI) | _BV(SPI_SCK)); + +#if defined SD_CD_0 + SD_CD_0_DDR = 0; + SD_CD_0 = 1; /* Pullup */ +#elif defined SD_CS_0_IN + SD_CS_0_DDR = 0; + SD_CS_0 = 0; +#endif +#if defined SD_CD_0 || !defined SD_CS_0_IN + SD_CS_0 = 1; + SD_CS_0_DDR = 1; +#endif + +#if defined SD_CD_1 + SD_CD_1_DDR = 0; + SD_CD_1 = 1; /* Pullup */ +#elif defined SD_CS_1_IN + SD_CS_1_DDR = 0; + SD_CS_1 = 0; /* No Pullup */ +#endif +#if defined SD_CD_1 || !defined SD_CS_1_IN + SD_CS_1 = 1; /* Set High */ + SD_CS_1_DDR = 1; +#endif +} + /*-----------------------------------------------------------------------*/ /* Initialize Disk Drive */ /*-----------------------------------------------------------------------*/ @@ -354,57 +454,73 @@ DSTATUS disk_initialize ( ) { BYTE n, cmd, ty, ocr[4]; + DSTATUS res; - 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(); + if (drv >= MAX_DRV) + return STA_NOINIT; + res = socket[drv].stat; + if (res & STA_NODISK) { + return res & STAT_MASK; /* No card in the socket */ + } + power_on(drv); /* Force socket power on */ + ATOMIC_BLOCK(ATOMIC_FORCEON) { + socket[drv].stat &= ~STA_FAST; + } + SPI_CLK_SLOW(); for (n = 10; n; n--) spi_rcvr(); /* 80 dummy clocks */ ty = 0; - if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + if (send_cmd(drv, 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(); + if (send_cmd(drv, CMD8, 0x1AA) == 1) { /* SDv2? */ + /* Get trailing return value of R7 resp */ + for (n = 0; n < 4; n++) + ocr[n] = spi_rcvr(); + 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(drv, ACMD41, 1UL << 30)) + ; /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, 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) { + if (send_cmd(drv, 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)); + while (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, cmd, 0)) + ; /* Set R/W block length to 512 */ - if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(CMD16, 512) != 0) + if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(drv, CMD16, 512) != 0) ty = 0; } } - CardType = ty; - deselect(); + socket[drv].CardType = ty; + deselect(drv); if (ty) { /* Initialization succeded */ - disk_stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ - FCLK_FAST(); + /* Clear STA_NOINIT */ + ATOMIC_BLOCK(ATOMIC_FORCEON) { + res = (socket[drv].stat & ~STA_NOINIT) | STA_FAST; + socket[drv].stat = res; + } } else { /* Initialization failed */ - power_off(); + power_off(drv); } - return disk_stat; + return socket[drv].stat & STAT_MASK; } /*-----------------------------------------------------------------------*/ @@ -412,11 +528,19 @@ DSTATUS disk_initialize ( /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( - BYTE drv /* Physical drive nmuber (0) */ + BYTE drv /* Physical drive nmuber (0) */ ) { - if (drv) return STA_NOINIT; /* Supports only single drive */ - return disk_stat; + DSTATUS res; + + //debug("***** disk_status(%.2x)", drv); + if (drv >= MAX_DRV) + res = STA_NOINIT; + else + res = socket[drv].stat & STAT_MASK; + + //debug(" == %.2x\n", res); + return res; } /*-----------------------------------------------------------------------*/ @@ -424,30 +548,35 @@ DSTATUS disk_status ( /*-----------------------------------------------------------------------*/ 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 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 (drv >= MAX_DRV || !count) + return RES_PARERR; + if (socket[drv].stat & STA_NOINIT) + return RES_NOTRDY; - if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ + /* Convert to byte address if needed */ + if (!(socket[drv].CardType & CT_BLOCK)) + sector *= 512; - cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ - if (send_cmd(cmd, sector) == 0) { + /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ + cmd = count > 1 ? CMD18 : CMD17; + if (send_cmd(drv, cmd, sector) == 0) { do { if (!rcvr_datablock(buff, 512)) break; buff += 512; } while (--count); if (cmd == CMD18) - send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + send_cmd(drv, CMD12, 0); /* STOP_TRANSMISSION */ } - deselect(); + deselect(drv); return count ? RES_ERROR : RES_OK; } @@ -458,35 +587,47 @@ DRESULT disk_read ( #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) */ + 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 */ + DSTATUS res; - if (count == 1) { /* Single block write */ - if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ + if (drv >= MAX_DRV || !count) + return RES_PARERR; + res = socket[drv].stat; + if ( res & STA_NOINIT) + return RES_NOTRDY; + if (res & STA_PROTECT) + return RES_WRPRT; + + /* Convert to byte address if needed */ + if (!(socket[drv].CardType & CT_BLOCK)) + sector *= 512; + + if (count == 1) { + /* Single block write */ + if ((send_cmd(drv, 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 */ + } else { + /* Multiple block write */ + if (socket[drv].CardType & CT_SDC) + send_cmd(drv, ACMD23, count); + if (send_cmd(drv, CMD25, sector) == 0) { + /* WRITE_MULTIPLE_BLOCK */ do { - if (!xmit_datablock(buff, 0xFC)) break; + if (!xmit_datablock(buff, 0xFC)) + break; buff += 512; - }while (--count); + } while (--count); if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ - count = 1; + count = 1; } } - deselect(); + deselect(drv); return count ? RES_ERROR : RES_OK; } @@ -507,21 +648,24 @@ DRESULT disk_ioctl ( BYTE n, csd[16], *ptr = buff; DWORD csize; - if (drv) + if (drv >= MAX_DRV) return RES_PARERR; res = RES_ERROR; - if (disk_stat & STA_NOINIT) return RES_NOTRDY; + if (socket[drv].stat & STA_NOINIT) + return RES_NOTRDY; + + /* TODO: SPI clock? */ 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()) + if (select(drv)) 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 ((send_cmd(drv, 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; @@ -535,8 +679,8 @@ DRESULT disk_ioctl ( 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 */ + if (socket[drv].CardType & CT_SD2) { /* SDv2? */ + if (send_cmd(drv, ACMD13, 0) == 0) { /* Read SD status */ spi_rcvr(); if (rcvr_datablock(csd, 16)) { /* Read partial block */ for (n = 64 - 16; n; n--) @@ -546,8 +690,8 @@ DRESULT disk_ioctl ( } } } else { /* SDv1 or MMCv3 */ - if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ - if (CardType & CT_SD1) { /* SDv1 */ + if ((send_cmd(drv, CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ + if (socket[drv].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); @@ -560,24 +704,24 @@ DRESULT disk_ioctl ( /* Following commands are never used by FatFs module */ case MMC_GET_TYPE: /* Get card type flags (1 byte) */ - *ptr = CardType; + *ptr = socket[drv].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 */ + if (send_cmd(drv, 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 */ + if (send_cmd(drv, 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 */ + if (send_cmd(drv, CMD58, 0) == 0) { /* READ_OCR */ for (n = 4; n; n--) *ptr++ = spi_rcvr(); res = RES_OK; @@ -585,7 +729,7 @@ DRESULT disk_ioctl ( break; case MMC_GET_SDSTAT: /* Receive SD status as a data block (64 bytes) */ - if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ + if (send_cmd(drv, ACMD13, 0) == 0) { /* SD_STATUS */ spi_rcvr(); if (rcvr_datablock(ptr, 64)) res = RES_OK; @@ -593,8 +737,7 @@ DRESULT disk_ioctl ( break; case CTRL_POWER_OFF : /* Power off */ - power_off(); - disk_stat |= STA_NOINIT; + power_off(drv); res = RES_OK; break; @@ -602,7 +745,7 @@ DRESULT disk_ioctl ( res = RES_PARERR; } - deselect(); + deselect(drv); return res; } @@ -617,21 +760,49 @@ void disk_timerproc (void) { BYTE s; - s = disk_stat; - -#ifdef SD_WP_PIN - if (sd_wp()) /* Write protected */ + s = socket[0].stat; +#ifdef SD_WP_0 + if (SD_WP_0_IN == 0) /* Write protected */ s |= STA_PROTECT; - else /* Write enabled */ + else /* Write enabled */ s &= ~STA_PROTECT; #endif -#ifdef SD_CD_PIN - if (sd_cd()) /* Card inserted */ +#if defined SD_CD_0 + if (SD_CD_0_IN == 0) /* Card inserted */ s &= ~STA_NODISK; - else /* Socket empty */ + else /* Socket empty */ s |= (STA_NODISK | STA_NOINIT); +#elif defined SD_CS_0_IN + if (SD_CS_0_DDR == 0) { + if (SD_CS_0_IN == 1) /* Card inserted */ + s &= ~STA_NODISK; + else /* Socket empty */ + s |= (STA_NODISK | STA_NOINIT); + } +#endif + socket[0].stat = s; /* Update MMC status */ + + s = socket[1].stat; +#ifdef SD_WP_1 + if (SD_WP_1_IN == 0) /* Write protected */ + s |= STA_PROTECT; + else /* Write enabled */ + s &= ~STA_PROTECT; #endif - disk_stat = s; /* Update MMC status */ +#if defined SD_CD_1 + if (SD_CD_1_IN == 0) /* Card inserted */ + s &= ~STA_NODISK; + else /* Socket empty */ + s |= (STA_NODISK | STA_NOINIT); +#elif defined SD_CS_1_IN + if (SD_CS_1_DDR == 0) { + if (SD_CS_1_IN == 1) /* Card inserted */ + s &= ~STA_NODISK; + else /* Socket empty */ + s |= (STA_NODISK | STA_NOINIT); + } +#endif + socket[1].stat = s; /* Update MMC status */ }