diff --git a/sdcard.c b/sdcard.c index 50a3e04..d76f797 100644 --- a/sdcard.c +++ b/sdcard.c @@ -1,7 +1,7 @@ -/* +/* * File: sdcard.c * Author: torsten.roemer@luniks.net - * + * * Thanks to http://rjhcoding.com/avrc-sd-interface-1.php ff. * * Created on 24. Februar 2024, 00:13 @@ -11,7 +11,7 @@ /** * Transmits the given command, argument and CRC value. - * + * * @param command * @param argument * @param crc @@ -31,17 +31,17 @@ /** * Reads an R1 response and returns it. - * + * * @return R1 */ static uint8_t readR1(void) { - uint8_t i = 0; + uint8_t i = 0; uint8_t response; - // poll up to 8 times for response + // poll up to 8 times for response while ((response = transmit(0xff)) == 0xff) { i++; - if (i > 8) { + if (i > 8) { break; } } @@ -51,7 +51,7 @@ /** * Reads an R3/R7 response into the given array of 5 bytes. - * + * * @param R3/R7 */ static void readR3_7(uint8_t *response) { @@ -70,7 +70,7 @@ } /** - * SPI selects the sd card with extra clocks before and after. + * SPI selects the SD card with extra clocks before and after. */ static void select(void) { transmit(0xff); @@ -79,7 +79,7 @@ } /** - * SPI deselects the sd card with extra clocks before and after. + * SPI deselects the SD card with extra clocks before and after. */ static void deselect(void) { transmit(0xff); @@ -92,22 +92,17 @@ */ static void powerOn(void) { _delay_ms(100); - deselect(); - _delay_ms(1); - // supply at least 74 clocks for (uint8_t i = 0; i < 10; i++) { transmit(0xff); } - - deselect(); } /** * Sends CMD0 to set idle SPI mode and returns the R1 response. - * + * * @return R1 */ static uint8_t sendIdle(void) { @@ -124,7 +119,7 @@ /** * Sends CMD8 to check version and voltage and reads the R7 response * into the given array of 5 bytes. - * + * * @param R7 */ static void sendIfCond(uint8_t *response) { @@ -138,7 +133,7 @@ /** * Sends CMD55 to tell that an app command is next and returns the R1 response. - * + * * @return R1 */ static uint8_t sendApp(void) { @@ -155,7 +150,7 @@ /** * Sends CMD58 to read the OCR register and reads the R3 response * into the given array of 5 bytes. - * + * * @param R3 */ static void sendOCR(uint8_t *response) { @@ -169,7 +164,7 @@ /** * Sends ACMD41 to start initialization and returns the R1 response. - * + * * @return R1 */ static uint8_t sendOpCond(void) { @@ -183,9 +178,69 @@ return response; } +bool initSDCard(void) { + uint8_t response[5]; + + // power on + powerOn(); + + // CMD0 - go to idle state + response[0] = sendIdle(); + if (response[0] > 0x01) { + printString("SD card error 0\r\n"); + return false; + } + + // CMD8 - send interface condition + sendIfCond(response); + if (response[0] & (1 << SD_CMD_ILLEGAL)) { + printString("SD card is V1.x or not SD card\r\n"); + return false; + } else if (response[0] > 0x01) { + printString("SD card error 8\r\n"); + return false; + } else if (response[4] != 0xaa) { + printString("SD card echo pattern mismatch\r\n"); + return false; + } + + // initialize to ready state + uint8_t attempts = 0; + do { + if (attempts > 100) { + printString("SD card did not become ready\r\n"); + return false; + } + + // CMD55 - send app command + response[0] = sendApp(); + if (response[0] < 0x02) { + // ACMD41 - start initialization + response[0] = sendOpCond(); + } + + _delay_ms(10); + attempts++; + } while (response[0] != SD_SUCCESS); + + // CMD58 - send operation conditions register + sendOCR(response); + if (response[0] > 0x01) { + printString("SD card error 58\r\n"); + return false; + } else if (!(response[1] & 0x80)) { + printString("SD card not ready\r\n"); + return false; + } + + printString("SD card ready\r\n"); + + return true; +} + bool readSingleBlock(uint32_t address, uint8_t *block) { select(); - + command(CMD17, address, CMD17_CRC); uint8_t response = readR1(); uint8_t token = 0xff; @@ -202,17 +257,17 @@ for (uint16_t i = 0; i < SD_BLOCK_SIZE; i++) { block[i] = transmit(0xff); } - + // 16-bit CRC (ignore for now) transmit(0xff); transmit(0xff); - + success = true; } } - + deselect(); - + return success; } @@ -294,78 +349,18 @@ for (uint16_t attempt = 0; attempt < SD_MAX_WRITE && token == 0xff; attempt++) { token = transmit(0xff); } - + if ((token & 0x0f) == 0x05) { // data was accepted, wait while busy programming data for (uint16_t attempt = 0; attempt < SD_MAX_WRITE && token == 0x00; attempt++) { token = transmit(0xff); } - + success = true; } } - + deselect(); - + return success; } - -bool initSDCard(void) { - uint8_t response[5]; - - // power on - powerOn(); - - // go to idle state - response[0] = sendIdle(); - if (response[0] > 0x01) { - printString("sd card error 0\r\n"); - return false; - } - - // send interface condition - sendIfCond(response); - if (response[0] & (1 << SD_CMD_ILLEGAL)) { - printString("sd card is V1.x or not sd card\r\n"); - return false; - } else if (response[0] > 0x01) { - printString("sd card error 8\r\n"); - return false; - } else if (response[4] != 0xaa) { - printString("sd card echo pattern mismatch\r\n"); - return false; - } - - // initialize to ready state - uint8_t attempts = 0; - do { - if (attempts > 100) { - printString("sd card did not become ready\r\n"); - return false; - } - - // send app command - response[0] = sendApp(); - if (response[0] < 0x02) { - // start initialization - response[0] = sendOpCond(); - } - - _delay_ms(10); - attempts++; - } while (response[0] != SD_SUCCESS); - - // send operation conditions register - sendOCR(response); - if (response[0] > 0x01) { - printString("sd card error 58\r\n"); - return false; - } else if (!(response[1] & 0x80)) { - printString("sd card not ready\r\n"); - return false; - } - - printString("sd card ready\r\n"); - - return true; -} diff --git a/sdcard.h b/sdcard.h index 93899b2..24fe0ee 100644 --- a/sdcard.h +++ b/sdcard.h @@ -1,4 +1,4 @@ -/* +/* * File: sdcard.h * Author: torsten.roemer@luniks.net * @@ -25,7 +25,7 @@ #define CMD12 12 #define CMD12_ARG 0x00000000 -#define CMD12_CRC 0x00 +#define CMD12_CRC 0x60 #define CMD17 17 #define CMD17_CRC 0x00 @@ -38,18 +38,20 @@ #define CMD55 55 #define CMD55_ARG 0x00000000 -#define CMD55_CRC 0x00 +#define CMD55_CRC 0x64 #define CMD58 58 #define CMD58_ARG 0x00000000 -#define CMD58_CRC 0x00 +#define CMD58_CRC 0xfc #define ACMD41 41 #define ACMD41_ARG 0x40000000 -#define ACMD41_CRC 0x00 +#define ACMD41_CRC 0x76 +// TODO depends on SPI SCK frequency #define SD_MAX_READ 50000 // SPI clock ticks in 100 ms #define SD_MAX_WRITE 125000 // SPI clock ticks in 250 ms + #define SD_BLOCK_SIZE 512 #define SD_CMD_ILLEGAL 2 @@ -59,15 +61,15 @@ /** * Initializes the SD Card and returns true on success, false otherwise. - * + * * @return true on success, false otherwise */ bool initSDCard(void); /** - * Reads a single block of 512 bytes at the given address into + * Reads a single block of 512 bytes at the given address into * the given buffer and returns true on success, false otherwise. - * + * * @param address address in 512 byte units * @param block 512 byte buffer * @return success @@ -78,7 +80,7 @@ * Reads multiple blocks of 512 bytes starting at the given address * and, for each block, passes the buffer to the given function. * By returning false, the function can request to stop reading blocks. - * + * * @param address * @param consume * @return success @@ -86,9 +88,9 @@ bool readMultiBlock(uint32_t address, Consumer consume); /** - * Writes a single block of 512 bytes starting at the given address + * Writes a single block of 512 bytes starting at the given address * from the given buffer and returns true on success, false otherwise. - * + * * @param address address in 512 byte units * @param block 512 byte buffer * @return success