From 141e8322ec472fd86c8a399e594a122ba5d10992 Mon Sep 17 00:00:00 2001 From: bsongis Date: Mon, 15 Sep 2014 12:19:19 +0200 Subject: [PATCH] SD access part from #1644 --- radio/src/targets/taranis/diskio.cpp | 118 +++++++++++------- .../src/targets/taranis/usbd_storage_msd.cpp | 2 +- 2 files changed, 75 insertions(+), 45 deletions(-) diff --git a/radio/src/targets/taranis/diskio.cpp b/radio/src/targets/taranis/diskio.cpp index 6cb17c7f0..c16ecc8d7 100644 --- a/radio/src/targets/taranis/diskio.cpp +++ b/radio/src/targets/taranis/diskio.cpp @@ -246,6 +246,12 @@ BYTE wait_ready (void) } +static void spi_reset() +{ + for(int n=0; n < 520; ++n) { + stm32_spi_rw(0xFF); + } +} /*-----------------------------------------------------------------------*/ /* Deselect the card and release SPI bus */ @@ -475,7 +481,10 @@ BOOL rcvr_datablock ( do { /* Wait for data packet in timeout of 100ms */ token = rcvr_spi(); } while ((token == 0xFF) && Timer1); - if(token != 0xFE) return FALSE; /* If not valid data token, return with error */ + if(token != 0xFE) { + spi_reset(); + return FALSE; /* If not valid data token, return with error */ + } #ifdef STM32_SD_USE_DMA stm32_dma_transfer( TRUE, buff, btr ); @@ -500,6 +509,8 @@ BOOL rcvr_datablock ( /* Send a data packet to MMC */ /*-----------------------------------------------------------------------*/ +#define DATA_RESPONSE_TIMEOUT 10 + static BOOL xmit_datablock ( const BYTE *buff, /* 512 byte data block to be transmitted */ @@ -511,7 +522,10 @@ BOOL xmit_datablock ( BYTE wc; #endif - if (wait_ready() != 0xFF) return FALSE; + if (wait_ready() != 0xFF) { + spi_reset(); + return FALSE; + } xmit_spi(token); /* transmit data token */ if (token != 0xFD) { /* Is data token */ @@ -528,9 +542,25 @@ BOOL xmit_datablock ( xmit_spi(0xFF); /* CRC (Dummy) */ xmit_spi(0xFF); - resp = rcvr_spi(); /* Receive data response */ - if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */ - return FALSE; + + /* + Despite what the SD card standard says, the reality is that (at least for some SD cards) + the Data Response byte does not come immediately after the last byte of data. + + This delay only happens very rarely, but it does happen. Typical response delay is some 10ms + */ + Timer2 = DATA_RESPONSE_TIMEOUT; + do { + resp = rcvr_spi(); /* Receive data response */ + if ((resp & 0x1F) == 0x05) { /* If not accepted, return with error */ + return TRUE; + } + if (resp != 0xFF) { + spi_reset(); + return FALSE; + } + } while (Timer2); + } return TRUE; @@ -559,6 +589,7 @@ BYTE send_cmd ( /* Select the card and wait for ready */ SELECT(); if (wait_ready() != 0xFF) { + spi_reset(); return 0xFF; } @@ -577,9 +608,9 @@ BYTE send_cmd ( if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */ n = 10; /* Wait for a valid response in timeout of 10 attempts */ - do + do { res = rcvr_spi(); - while ((res & 0x80) && --n); + } while ((res & 0x80) && --n); return res; /* Return with the response value */ } @@ -675,6 +706,9 @@ int8_t SD_ReadSectors(uint8_t *buff, uint32_t sector, uint32_t count) count = 0; } } + else { + spi_reset(); + } } else { /* Multiple block read */ if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ @@ -686,11 +720,14 @@ int8_t SD_ReadSectors(uint8_t *buff, uint32_t sector, uint32_t count) } while (--count); send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ } + else { + spi_reset(); + } } release_spi(); - return 0; + return count ? -1 : 0; } DRESULT disk_read ( @@ -702,10 +739,8 @@ DRESULT disk_read ( { if (drv || !count) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; - - SD_ReadSectors(buff, sector, count); - - return RES_OK; + int8_t res = SD_ReadSectors(buff, sector, count); + return (res != 0) ? RES_ERROR : RES_OK; } @@ -715,22 +750,37 @@ DRESULT disk_read ( /*-----------------------------------------------------------------------*/ // TODO quick & dirty -int8_t SD_WriteSectors(uint8_t *buff, uint32_t sector, uint32_t count) +int8_t SD_WriteSectors(const uint8_t *buff, uint32_t sector, uint32_t count) { if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ - 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; + if (count == 1) { /* Single block write */ + if (send_cmd(CMD24, sector) == 0) { /* WRITE_BLOCK */ + if (xmit_datablock(buff, 0xFE)) { + count = 0; + } + } + else { + spi_reset(); + } + } + else { + 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; + } + else { + spi_reset(); + } } release_spi(); - return 0; + return count ? -1 : 0; } #if _FS_READONLY == 0 @@ -745,28 +795,8 @@ DRESULT disk_write ( if (drv || !count) return RES_PARERR; if (Stat & STA_NOINIT) return RES_NOTRDY; if (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; - } - } - release_spi(); - - return count ? RES_ERROR : RES_OK; + int8_t res = SD_WriteSectors(buff, sector, count); + return (res != 0) ? RES_ERROR : RES_OK; } #endif /* _READONLY == 0 */ diff --git a/radio/src/targets/taranis/usbd_storage_msd.cpp b/radio/src/targets/taranis/usbd_storage_msd.cpp index 4aa0c3fb3..4e7704d63 100644 --- a/radio/src/targets/taranis/usbd_storage_msd.cpp +++ b/radio/src/targets/taranis/usbd_storage_msd.cpp @@ -265,7 +265,7 @@ int8_t STORAGE_Read (uint8_t lun, * @retval Status */ -int8_t SD_WriteSectors(uint8_t *buf, uint32_t sector, uint32_t count); +int8_t SD_WriteSectors(const uint8_t *buf, uint32_t sector, uint32_t count); int8_t STORAGE_Write (uint8_t lun, uint8_t *buf,