From da194e82cf1dde2daa0217b1ad8e2fb5c0cd50d4 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sat, 11 Jul 2020 18:38:03 +0300 Subject: [PATCH] Upload diskio driver for SD cards support --- ili9341.c | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) diff --git a/ili9341.c b/ili9341.c index abbf52f..c03559f 100644 --- a/ili9341.c +++ b/ili9341.c @@ -828,3 +828,677 @@ void ili9341_test(int mode) } #endif +#ifdef __USE_SD_CARD__ +//***************************************************** +//* SD functions and definitions +//***************************************************** +// Definitions for MMC/SDC command +#define CMD0 (0x40+0) // GO_IDLE_STATE +#define CMD1 (0x40+1) // SEND_OP_COND +#define CMD8 (0x40+8) // SEND_IF_COND +#define CMD9 (0x40+9) // SEND_CSD +#define CMD10 (0x40+10) // SEND_CID +#define CMD12 (0x40+12) // STOP_TRANSMISSION +#define CMD13 (0x40+13) // SEND_STATUS +#define CMD16 (0x40+16) // SET_BLOCKLEN +#define CMD17 (0x40+17) // READ_SINGLE_BLOCK +#define CMD18 (0x40+18) // READ_MULTIPLE_BLOCK +#define CMD23 (0x40+23) // SET_BLOCK_COUNT +#define CMD24 (0x40+24) // WRITE_BLOCK +#define CMD25 (0x40+25) // WRITE_MULTIPLE_BLOCK +#define CMD55 (0x40+55) // APP_CMD +#define CMD58 (0x40+58) // READ_OCR +#define CMD59 (0x40+59) // CRC_ON_OFF +// Then send after CMD55 (APP_CMD) interpret as ACMD +#define ACMD41 (0x40+41) // SEND_OP_COND (ACMD) + +// MMC card type flags (MMC_GET_TYPE) +#define CT_MMC 0x01 // MMC v3 +#define CT_SD1 0x02 // SDv1 +#define CT_SD2 0x04 // SDv2 +#define CT_SDC 0x06 // SD +#define CT_BLOCK 0x08 // Block addressing + +// 7.3.2 Responses +// 7.3.2.1 Format R1 (1 byte) +// This response token is sent by the card after every command with the exception of SEND_STATUS commands. +#define SD_R1_IDLE ((uint8_t)0x01) // The card is in idle state +#define SD_R1_ERASE_RESET ((uint8_t)0x02) // erase reset +#define SD_R1_ILLEGAL_CMD ((uint8_t)0x04) // Illegal command +#define SD_R1_CRC_ERROR ((uint8_t)0x08) // The CRC check of the last command failed +#define SD_R1_ERR_ERASE_CLR ((uint8_t)0x10) // error in the sequence of erase commands +#define SD_R1_ADDR_ERROR ((uint8_t)0x20) // Incorrect address specified +#define SD_R1_PARAM_ERROR ((uint8_t)0x40) // Parameter error +#define SD_R1_NOT_R1 ((uint8_t)0x80) // Not R1 register +// 7.3.2.2 Format R1b (R1 + Busy) +// The busy signal token can be any number of bytes. A zero value indicates card is busy. +// A non-zero value indicates the card is ready for the next command. +// 7.3.2.3 Format R2 (2 byte) +// This response token is two bytes long and sent as a response to the SEND_STATUS command. +// 1 byte - some as R1 +// 2 byte - + +// 7.3.2.4 Format R3 (R1 + OCR, 5 bytes) +// This response token is sent by the card when a READ_OCR command is received. +// 1 byte - some as R1 +// 2-5 byte - OCR +// On Send byte order in SendCommand send MSB first!! +// Received byte order MSB last!! +#define _OCR(dword) (((dword&0x000000FF)<<24)|((dword&0x0000FF00)<<8)|((dword&0x00FF0000)>>8)|((dword&0xFF000000)>>24)) +#define SD_OCR_LOW_VOLTAGE ((uint32_t)0x00000080) // Reserved for Low Voltage Range +#define SD_OCR_27_VOLTAGE ((uint32_t)0x00008000) // VDD Voltage Window 2.7-2.8V +#define SD_OCR_28_VOLTAGE ((uint32_t)0x00010000) // VDD Voltage Window 2.8-2.9V +#define SD_OCR_29_VOLTAGE ((uint32_t)0x00020000) // VDD Voltage Window 2.9-3.0V +#define SD_OCR_30_VOLTAGE ((uint32_t)0x00040000) // VDD Voltage Window 3.0-3.1V +#define SD_OCR_31_VOLTAGE ((uint32_t)0x00080000) // VDD Voltage Window 3.1-3.2V +#define SD_OCR_32_VOLTAGE ((uint32_t)0x00100000) // VDD Voltage Window 3.2-3.3V +#define SD_OCR_33_VOLTAGE ((uint32_t)0x00200000) // VDD Voltage Window 3.3-3.4V +#define SD_OCR_34_VOLTAGE ((uint32_t)0x00400000) // VDD Voltage Window 3.4-3.8V +#define SD_OCR_35_VOLTAGE ((uint32_t)0x00800000) // VDD Voltage Window 3.5-3.6V +#define SD_OCR_18_VOLTAGE ((uint32_t)0x01000000) // VDD Voltage switch to 1.8V (UHS-I only) +#define SD_OCR_CAPACITY ((uint32_t)0x40000000) // Card Capacity Status (CCS) +#define SD_OCR_BUSY ((uint32_t)0x80000000) // Card power up status bit (busy) + +// 5.3 CSD Register +// 16GB Kingston 40 0E 00 32 5B 59 00 00 73 A7 7F 80 0A 40 00 EB // 29608 * 512 kB +// 32GB Samsung 40 0E 00 32 5B 59 00 00 EE 7F 7F 80 0A 40 40 55 // 61056 * 512 kB +// 128GB Samsung 40 0E 00 32 5B 59 00 03 B9 FF 7F 80 0A 40 40 AB // 244224 * 512 kB +#define CSD_0_STRUCTURE 0b11000000 +#define CSD_1_TAAC 0b11111111 +#define CSD_2_NSAC 0b11111111 +#define CSD_3_TRAN_SPEED 0b11111111 +#define CSD_4_CCC 0b11111111 +#define CSD_5_CCC 0b11110000 +#define CSD_5_READ_BL_LEN 0b00001111 +#define CSD_6_READ_BL_PARTIAL 0b10000000 +#define CSD_6_WRITE_BLK_MISALIGN 0b01000000 +#define CSD_6_READ_BLK_MISALIGN 0b00100000 +#define CSD_6_DSR_IMP 0b00010000 +#define CSD_7_C_SIZE 0b00111111 +#define CSD_8_C_SIZE 0b11111111 +#define CSD_9_C_SIZE 0b11111111 +#define CSD_10_ERASE_BLK_EN 0b01000000 +#define CSD_10_SECTOR_SIZE 0b00111111 +#define CSD_11_SECTOR_SIZE 0b10000000 +#define CSD_11_WP_GRP_SIZE 0b01111111 +#define CSD_12_WP_GRP_ENABLE 0b10000000 +#define CSD_12_R2W_FACTOR 0b00011100 +#define CSD_12_WRITE_BL_LEN 0b00000011 +#define CSD_13_WRITE_BL_LEN 0b11000000 +#define CSD_13_WRITE_BL_PARTIAL 0b00100000 +#define CSD_14_FILE_FORMAT_GRP 0b10000000 +#define CSD_14_COPY 0b01000000 +#define CSD_14_PERM_WRITE_PROTECT 0b00100000 +#define CSD_14_TMP_WRITE_PROTECT 0b00010000 +#define CSD_14_FILE_FORMAT 0b00001100 +#define CSD_15_CRC 0b11111110 + + +// 7.3.3.1 Data Response Token +#define SD_TOKEN_DATA_ACCEPTED ((uint8_t)0x05) // Data accepted +#define SD_TOKEN_WRITE_CRC_ERROR ((uint8_t)0x0b) // Data rejected due to a CRC error +#define SD_TOKEN_WRITE_ERROR ((uint8_t)0x0d) // Data rejected due to a write error +// 7.3.3.2 Start Block Tokens and Stop Tran Token +#define SD_TOKEN_START_BLOCK ((uint8_t)0xfe) // Start block (single tx, single/multiple rx) +#define SD_TOKEN_START_M_BLOCK ((uint8_t)0xfc) // Start multiple block tx +#define SD_TOKEN_STOP_M_BLOCK ((uint8_t)0xfd) // Stop multiple block tx +// 7.3.3.3 Data Error Token +#define SD_TOKEN_READ_ERROR ((uint8_t)0x01) // Data read error +#define SD_TOKEN_READ_CC_ERROR ((uint8_t)0x02) // Internal card controller error +#define SD_TOKEN_READ_ECC_ERROR ((uint8_t)0x04) // Card ECC failed +#define SD_TOKEN_READ_RANGE_ERROR ((uint8_t)0x08) // Read address out of range + +//***************************************************** +// SD card module settings +//***************************************************** +// Additional state flag definition +#define STA_POWER_ON 0x80 // Power ON flag + +// Use for enable CRC check of Tx and Rx data on SPI +// If enable both CRC check, on initialization send SD command - CRC_ON_OFF vs ON +// And Card begin check received data and answer on CRC errors +//#define SD_USE_COMMAND_CRC +//#define SD_USE_DATA_CRC +// Use DMA on sector data Tx to SD card +#ifdef __USE_DISPLAY_DMA__ +#define __USE_SDCARD_DMA__ +#endif + +// Define sector size +#define SD_SECTOR_SIZE 512 +// Define SD SPI speed on work +#define SD_SPI_SPEED SPI_BR_DIV2 +// div4 give less error and high speed for Rx +#define SD_SPI_RX_SPEED SPI_BR_DIV2 + +// Define SD SPI speed on initialization (100-400kHz need) +#define SD_INIT_SPI_SPEED SPI_BR_DIV256 +// Set number of try read or write sector data (1 only one try) +#define SD_READ_WRITE_REPEAT 1 +// Local values for SD card state +static DSTATUS Stat = STA_NOINIT; // Disk Status +static uint8_t CardType = 0; // Type 0:MMC, 1:SDC, 2:Block addressing + +// Debug +#define DEBUG 0 +int shell_printf(const char *fmt, ...); +#define DEBUG_PRINT(...) do { if (DEBUG) shell_printf(__VA_ARGS__); } while (0) +//uint32_t w_cnt; +//uint32_t w_time; +//uint32_t r_cnt; +//uint32_t r_time; +//uint32_t crc_time; + + +//void testLog(void){ +// DEBUG_PRINT(" Read speed = %d Byte/s (count %d, time %d)\r\n", r_cnt*512*10000/r_time, r_cnt, r_time); +// DEBUG_PRINT(" Write speed = %d Byte/s (count %d, time %d)\r\n", w_cnt*512*10000/w_time, w_cnt, w_time); +// DEBUG_PRINT(" CRC16 time %d\r\n", crc_time); +//} + +//******************************************************* +// SD card SPI functions +//******************************************************* +#define SD_CS_LOW palClearPad(GPIOB, GPIOB_SD_CS) +#define SD_CS_HIGH palSetPad(GPIOB, GPIOB_SD_CS) + +static void SD_Select_SPI(uint32_t speed) { + CS_HIGH; // Unselect LCD + SPI_BR_SET(speed); // Set Baud rate control for SD card + SD_CS_LOW; // Select SD Card +} + +static void SD_Unselect_SPI(void) { + SD_CS_HIGH; // Unselect SD Card + spi_RxByte(); // Dummy read/write one Byte recommend for SD after CS up + SPI_BR_SET(LCD_SPI_SPEED); // Restore Baud rate for LCD +} + +//******************************************************* +//* SD functions +//******************************************************* +// CRC7 used for commands +#ifdef SD_USE_COMMAND_CRC +#define CRC7_POLY 0x89 +#define CRC7_INIT 0x00 +// 7 3 +// CRC7 it's a 7 bit CRC with polynomial x + x + 1 +static uint8_t crc7(const uint8_t *ptr, uint16_t count) { + uint8_t crc = CRC7_INIT; + uint8_t i = 0; + while (count--){ + crc ^= *ptr++; + do{ + if (crc & 0x80) crc^=CRC7_POLY; + crc = crc << 1; + } while((++i)&0x7); + } + return crc; +} +#endif +// CRC16 used for data +#ifdef SD_USE_DATA_CRC +#define CRC16_POLY 0x1021 +#define CRC16_INIT 0x0000 +// 16 12 5 +// This is the CCITT CRC 16 polynomial X + X + X + 1. +static uint16_t crc16(const uint8_t *ptr, uint16_t count) { + uint16_t crc = CRC16_INIT; + #if 0 + uint8_t i = 0; + while(count--){ + crc^= ((uint16_t) *ptr++ << 8); + do{ + if (crc & 0x8000) + crc = (crc << 1) ^ CRC16_POLY; + else + crc = crc << 1; + } while((++i)&0x7); + } + return __REVSH(crc); // swap bytes + #else + while (count--){ + crc^= *ptr++; + crc^= (crc>> 4)&0x000F; + crc^= (crc<<12); + crc^= (crc<< 5)&0x1FE0; + crc = __REVSH(crc); // swap bytes + } + return crc; + #endif +} +#endif + +// Wait and read R1 answer from SD +static inline uint8_t SD_ReadR1(uint32_t cnt) { + uint8_t r1; + // 8th bit R1 always zero, check it + while(((r1=spi_RxByte())&0x80) && --cnt) + ; + return r1; +} + +// Wait SD ready token answer (wait time in systick, 10 systick = 1ms) +static inline bool SD_WaitDataToken(uint8_t token, uint32_t wait_time) { + uint8_t res; + uint32_t time = chVTGetSystemTimeX(); + uint32_t count = 0; + do{ + if ((res = spi_RxByte()) == token) + return true; + count++; + // Check timeout only every 65536 bytes read (~50ms interval) + if ((count&0xFFFF) == 0) + if ((chVTGetSystemTimeX() - time) > wait_time) + break; + }while (res == 0xFF); + return false; +} + +static inline uint8_t SD_WaitDataAccept(uint32_t cnt) { + uint8_t res; + while ((res = spi_RxByte()) == 0xFF && --cnt) + ; + return res&0x1F; +} + +// Wait no Busy answer from SD (wait time in systick, 10 systick = 1ms) +static uint8_t SD_WaitNotBusy(uint32_t wait_time) { + uint8_t res; + uint32_t time = chVTGetSystemTimeX(); + uint32_t count = 0; + do{ + if ((res = spi_RxByte()) == 0xFF) + return res; + count++; + // Check timeout only every 65536 bytes read (~50ms interval) + if ((count&0xFFFF) == 0) + if ((chVTGetSystemTimeX() - time) > wait_time) + break; + }while (1); + return 0; +} + +// Receive data block from SD +static bool SD_RxDataBlock(uint8_t *buff, uint16_t len, uint8_t token) { + // loop until receive read response token or timeout ~50ms + if (!SD_WaitDataToken(token, 500)) { + DEBUG_PRINT(" rx SD_WaitDataToken err\r\n"); + return FALSE; + } + // Receive data (Not use rx DMA) +#if 1 + spi_RxBuffer(buff, len); +#else + spi_DMARxBuffer(buff, len); +#endif + // Read and check CRC (if enabled) + uint16_t crc; spi_RxBuffer((uint8_t*)&crc, 2); +#ifdef SD_USE_DATA_CRC + uint16_t bcrc = crc16(buff, len); + if (crc!=bcrc){ + DEBUG_PRINT("CRC = %04x , hcalc = %04x, calc = %04x\r\n", (uint32_t)crc, (uint32_t)bcrc, (uint32_t)crc16(buff, len)); + return FALSE; + } +#endif + return TRUE; +} + +// Transmit data block to SD +static bool SD_TxDataBlock(const uint8_t *buff, uint8_t token) { + uint8_t resp; + // Transmit token + spi_TxByte(token); +#if 0 // Not use multiple block tx + // if it's not STOP token, transmit data, in multiple block Tx + if (token == SD_TOKEN_STOP_BLOCK) return TRUE; +#endif + +#ifdef __USE_SDCARD_DMA__ + spi_DMATxBuffer((uint8_t*)buff, SD_SECTOR_SIZE); +#else + spi_TxBuffer((uint8_t*)buff, SD_SECTOR_SIZE); +#endif + spi_DropRx(); + // Send CRC +#ifdef SD_USE_DATA_CRC + uint16_t bcrc = crc16(buff, SD_SECTOR_SIZE); + spi_TxWord(bcrc); +#else + spi_TxWord(0xFFFF); +#endif + // Receive transmit data response token on next 10 bytes + resp = SD_WaitDataAccept(10); + if (resp != SD_TOKEN_DATA_ACCEPTED){ + goto error_tx; + } +#if 0 + // Wait busy (recommended timeout is 250ms (500ms for SDXC) set 250ms + resp = SD_WaitNotBusy(2500); + if (resp == 0xFF) + return TRUE; +#else + // Continue execute, wait not busy on next command + return TRUE; +#endif + DEBUG_PRINT(" Tx busy error = %04\r\n", (uint32_t)resp); + return FALSE; +error_tx: + DEBUG_PRINT(" Tx accept error = %04x\r\n", (uint32_t)resp); + return FALSE; +} + +// Transmit command to SD +static uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) { + uint8_t buf[6]; + uint8_t r1; + // wait SD ready after last Tx (recommended timeout is 250ms (500ms for SDXC) set 250ms + if ((r1 = SD_WaitNotBusy(2500)) != 0xFF) { + DEBUG_PRINT(" SD_WaitNotBusy CMD%d err, %02x\r\n", cmd-0x40, (uint32_t)r1); + return 0xFF; + } + // Transmit command + buf[0] = cmd; + buf[1] = (arg >> 24)&0xFF; + buf[2] = (arg >> 16)&0xFF; + buf[3] = (arg >> 8)&0xFF; + buf[4] = (arg >> 0)&0xFF; +#ifdef SD_USE_COMMAND_CRC + buf[5] = crc7(buf, 5)|0x01; +#else + uint8_t crc = 0x01; // Dummy CRC + Stop + if (cmd == CMD0) crc = 0x95;// Valid CRC for CMD0(0) + else if (cmd == CMD8) crc = 0x87;// Valid CRC for CMD8(0x1AA) + buf[5] = crc; +#endif + spi_TxBuffer(buf, 6); + spi_DropRx(); +// Skip a stuff byte when STOP_TRANSMISSION +//if (cmd == CMD12) SPI_RxByte(); + // Receive response register r1 + r1 = SD_ReadR1(10); +#if 1 + if (r1&(SD_R1_NOT_R1|SD_R1_CRC_ERROR|SD_R1_ERASE_RESET|SD_R1_ERR_ERASE_CLR)){ + DEBUG_PRINT(" SD_SendCmd err CMD%d, 0x%x, 0x%08x\r\n", (uint32_t)cmd-0x40, (uint32_t)r1, arg); + return r1; + } + if (r1&(~SD_R1_IDLE)) + DEBUG_PRINT(" SD_SendCmd CMD%d, 0x%x, 0x%08x\r\n", (uint32_t)cmd-0x40, (uint32_t)r1, arg); +#endif + return r1; +} + +// Power on SD +static void SD_PowerOn(void) { + uint16_t n; + CS_HIGH; + // Dummy TxRx 80 bits for power up SD + for (n=0;n<10;n++) + spi_RxByte(); + SD_Select_SPI(SD_INIT_SPI_SPEED); + // Set SD card to idle state + if (SD_SendCmd(CMD0, 0) == SD_R1_IDLE) + Stat|= STA_POWER_ON; + else{ + Stat = STA_NOINIT; + } + SD_Unselect_SPI(); +} + +// Power off SD +static inline void SD_PowerOff(void) { + Stat &= ~STA_POWER_ON; +} + +// Check power flag +static inline uint8_t SD_CheckPower(void) { + return Stat & STA_POWER_ON; +} + +//******************************************************* +// diskio.c functions for file system library +//******************************************************* +// If enable RTC - get RTC time +#if FF_FS_NORTC == 0 +DWORD get_fattime (void) { + return rtc_get_FAT(); +} +#endif + +// diskio.c - Initialize SD +DSTATUS disk_initialize(BYTE pdrv) { +// Debug counters +// w_cnt = 0; +// w_time = 0; +// r_cnt = 0; +// r_time = 0; + if (pdrv != 0) return STA_NOINIT; + // power on, try detect on bus, set card to idle state + SD_PowerOn(); + // check disk type + uint8_t type = 0; + uint32_t cnt = 100; + // Set low SPI bus speed = PLL/256 (on 72MHz =281.250kHz) + SD_Select_SPI(SD_INIT_SPI_SPEED); + // send GO_IDLE_STATE command + if (SD_SendCmd(CMD0, 0) == SD_R1_IDLE) + { + DEBUG_PRINT(" CMD0 Ok\r\n"); + // SDC V2+ accept CMD8 command, http://elm-chan.org/docs/mmc/mmc_e.html + if (SD_SendCmd(CMD8, 0x00001AAU) == SD_R1_IDLE) + { + DEBUG_PRINT(" CMD8 Ok\r\n"); + uint32_t ocr; spi_RxBuffer((uint8_t *)&ocr, 4); + DEBUG_PRINT(" CMD8 0x%x\r\n", ocr); + // operation condition register voltage range 2.7-3.6V + if (ocr == _OCR(0x00001AAU)) + { + // ACMD41 with HCS bit can be up to 200ms wait + do { + if (SD_SendCmd(CMD55, 0) <= 1 && // APP_CMD Get Ok or idle state + SD_SendCmd(ACMD41, SD_OCR_CAPACITY) == 0) // Check OCR + break; + chThdSleepMilliseconds(10); + } while (--cnt); + DEBUG_PRINT(" CMD55 + ACMD41 %d\r\n", cnt); + // READ_OCR + if (cnt && SD_SendCmd(CMD58, 0) == 0) + { + DWORD ocr; spi_RxBuffer((uint8_t *)&ocr, 4); + DEBUG_PRINT(" CMD58 OCR = 0x%08X\r\n", _OCR(ocr)); + // Check CCS bit, SDv2 (HC or SC) + type = (ocr & _OCR(SD_OCR_CAPACITY)) ? CT_SD2 | CT_BLOCK : CT_SD2; + } + } +#ifdef SD_USE_COMMAND_CRC +#ifdef SD_USE_DATA_CRC + SD_SendCmd(CMD59, 1); // Enable CRC check on card +#endif +#endif +// uint8_t csd[16]; +// if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(csd, 16, SD_TOKEN_START_BLOCK)){ +// DEBUG_PRINT(" CSD ="); +// for (int i = 0; i<16; i++) +// DEBUG_PRINT(" %02X", csd[i]); +// DEBUG_PRINT("\r\n"); +// } + } else { + DEBUG_PRINT(" CMD8 Fail\r\n"); + // SDC V1 or MMC + type = (SD_SendCmd(CMD55, 0) <= 1 && // APP_CMD + SD_SendCmd(ACMD41, 0) <= 1) ? CT_SD1 : CT_MMC; + DEBUG_PRINT(" CMD55 %d\r\n", type); + do{ + if (type == CT_SD1) + { + if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(ACMD41, 0) == 0) break; // ACMD41 + } + else if (SD_SendCmd(CMD1, 0) == 0) break; // CMD1 + chThdSleepMilliseconds(10); + } while (--cnt); + // SET_BLOCKLEN + if (!cnt || SD_SendCmd(CMD16, SD_SECTOR_SIZE) != 0) type = 0; + DEBUG_PRINT(" CMD16 %d %d\r\n", cnt, type); + } + } + SD_Unselect_SPI(); + CardType = type; + DEBUG_PRINT("CardType %d\r\n", type); + // Clear STA_NOINIT and set Power on + if (type){ + Stat&= ~STA_NOINIT; + Stat|= STA_POWER_ON; + } + else // Initialization failed + SD_PowerOff(); + return Stat; +} + +// diskio.c - Return disk status +DSTATUS disk_status(BYTE pdrv) { + if (pdrv != 0) return STA_NOINIT; + return Stat; +} + +// diskio.c - Read sector +DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { + // No disk or wrong block count + if (pdrv != 0 || count != 1 || (Stat & STA_NOINIT)) return RES_NOTRDY; + // convert to byte address + if (!(CardType & CT_BLOCK)) sector *= SD_SECTOR_SIZE; +// r_cnt++; +// r_time-= chVTGetSystemTimeX(); + SD_Select_SPI(SD_SPI_RX_SPEED); + // READ_SINGLE_BLOCK + uint8_t cnt = SD_READ_WRITE_REPEAT; // read repeat count + do{ + if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, SD_SECTOR_SIZE, SD_TOKEN_START_BLOCK)){ + count = 0; + break; + } + }while (--cnt); + SD_Unselect_SPI(); +// r_time+= chVTGetSystemTimeX(); + if (count) + DEBUG_PRINT(" err READ_BLOCK %d 0x%08X\r\n", count, sector); +#if 0 + else{ + DEBUG_PRINT("Sector read 0x%08X %d \r\n", sector, cnt); + for (UINT j = 0; j < 32; j++){ + for (UINT i = 0; i < 16; i++) + DEBUG_PRINT(" 0x%02x", buff[j*16 + i]); + DEBUG_PRINT("\r\n"); + } + } +#endif + return count ? RES_ERROR : RES_OK; +} + +// diskio.c - Write sector +DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { + // No disk or wrong count + if (pdrv != 0 || count != 1 || (Stat & STA_NOINIT)) return RES_NOTRDY; + // Write protection + if (Stat & STA_PROTECT) return RES_WRPRT; + // Convert to byte address if no Block mode + if (!(CardType & CT_BLOCK)) sector*= SD_SECTOR_SIZE; +#if 0 + DEBUG_PRINT("Sector write 0x%08X, %d\r\n", sector, count); + for (UINT j = 0; j < 32; j++){ + for (UINT i = 0; i < 16; i++) + DEBUG_PRINT(" 0x%02X", buff[j*16 + i]); + DEBUG_PRINT("\r\n"); + } +#endif +// w_cnt++; +// w_time-= chVTGetSystemTimeX(); + SD_Select_SPI(SD_SPI_SPEED); + // WRITE_SINGLE_BLOCK + uint8_t cnt = SD_READ_WRITE_REPEAT; // write repeat count + do{ + if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, SD_TOKEN_START_BLOCK)){ + count = 0; + break; + } + } while (--cnt); + SD_Unselect_SPI(); +// w_time+= chVTGetSystemTimeX(); + if (count) + DEBUG_PRINT(" WRITE_BLOCK %d 0x%08X\r\n", count, sector); + return count ? RES_ERROR : RES_OK; +} + +// The disk_ioctl function is called to control device specific features and miscellaneous functions other than generic read/write. +// Implement only five device independent commands used by FatFS module +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) { + (void)buff; + DRESULT res = RES_PARERR; + // No disk or not ready + if (pdrv != 0 || Stat & STA_NOINIT) return RES_NOTRDY; + SD_Select_SPI(SD_SPI_RX_SPEED); + switch (cmd){ + // Makes sure that the device has finished pending write process. + // If the disk I/O layer or storage device has a write-back cache, + // the dirty cache data must be committed to media immediately. + // Nothing to do for this command if each write operation to the media is completed + // within the disk_write function. + case CTRL_SYNC: + if (SD_WaitNotBusy(2000) == 0xFF) res = RES_OK; + break; +#if FF_USE_TRIM == 1 + // Informs the device the data on the block of sectors is no longer needed and it can be erased. + // The sector block is specified in an LBA_t array {, } pointed by buff. + // This is an identical command to Trim of ATA device. Nothing to do for this command if this function + // is not supported or not a flash memory device. FatFs does not check the result code and the file function + // is not affected even if the sector block was not erased well. This command is called on remove a cluster chain + // and in the f_mkfs function. It is required when FF_USE_TRIM == 1. + case CTRL_TRIM: + break; +#endif +#if FF_MAX_SS > FF_MIN_SS + // Retrieves sector size used for read/write function into the WORD variable pointed by buff. + // Valid sector sizes are 512, 1024, 2048 and 4096. This command is required only if FF_MAX_SS > FF_MIN_SS. + // When FF_MAX_SS == FF_MIN_SS, this command will be never used and the read/write function must work in FF_MAX_SS bytes/sector only. + case GET_SECTOR_SIZE: + *(uint16_t*) buff = SD_SECTOR_SIZE; + res = RES_OK; + break; +#endif +#if FF_USE_MKFS == 1 + // Retrieves erase block size of the flash memory media in unit of sector into the DWORD variable pointed by buff. + // The allowable value is 1 to 32768 in power of 2. Return 1 if the erase block size is unknown or non flash memory media. + // This command is used by only f_mkfs function and it attempts to align data area on the erase block boundary. + // It is required when FF_USE_MKFS == 1. + case GET_BLOCK_SIZE: + *(uint16_t*) buff = ;//SD_SECTOR_SIZE; + res = RES_OK; + break; + // Retrieves number of available sectors, the largest allowable LBA + 1, on the drive into the LBA_t variable pointed by buff. + // This command is used by f_mkfs and f_fdisk function to determine the size of volume/partition to be created. + // It is required when FF_USE_MKFS == 1. + case GET_SECTOR_COUNT: + { + // SEND_CSD + uint8_t csd[16]; + if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(csd, 16, SD_TOKEN_START_BLOCK)) { + uint32_t n, csize; + if ((csd[0] >> 6) == 1) { // SDC V2 + csize = ((uint32_t)csd[7]<<16)|((uint32_t)csd[8]<< 8)|((uint32_t)csd[9]<< 0); + n = 10; + } + else { // MMC or SDC V1 + csize = ((uint32_t)csd[8]>>6)|((uint32_t)csd[7]<<2)|((uint32_t)(csd[6]&0x03)<<10); + n = ((csd[5]&0x0F)|((csd[10]&0x80)>>7)|((csd[9]&0x03)<<1)) + 2 - 9; + } + *(uint32_t*)buff = (csize+1)<