test

How can I remove this one?

Revision:
0:76d6402d766d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdcard.c	Tue Mar 19 14:47:28 2019 +0000
@@ -0,0 +1,557 @@
+/* vim: set ai et ts=4 sw=4: */
+
+#include "sdcard.h"
+
+static void SDCARD_Select() {
+    HAL_GPIO_WritePin(SDCARD_CS_GPIO_Port, SDCARD_CS_Pin, GPIO_PIN_RESET);
+}
+
+void SDCARD_Unselect() {
+    HAL_GPIO_WritePin(SDCARD_CS_GPIO_Port, SDCARD_CS_Pin, GPIO_PIN_SET);
+}
+
+/*
+R1: 0abcdefg
+     ||||||`- 1th bit (g): card is in idle state
+     |||||`-- 2th bit (f): erase sequence cleared
+     ||||`--- 3th bit (e): illigal command detected
+     |||`---- 4th bit (d): crc check error
+     ||`----- 5th bit (c): error in the sequence of erase commands
+     |`------ 6th bit (b): misaligned addres used in command
+     `------- 7th bit (a): command argument outside allowed range
+             (8th bit is always zero)
+*/
+static uint8_t SDCARD_ReadR1() {
+    uint8_t r1;
+    // make sure FF is transmitted during receive
+    uint8_t tx = 0xFF;
+    for(;;) {
+        HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, &r1, sizeof(r1), HAL_MAX_DELAY);
+        if((r1 & 0x80) == 0) // 8th bit alwyas zero, r1 recevied
+            break;
+    }
+    return r1;
+}
+
+// data token for CMD9, CMD17, CMD18 and CMD24 are the same
+#define DATA_TOKEN_CMD9  0xFE
+#define DATA_TOKEN_CMD17 0xFE
+#define DATA_TOKEN_CMD18 0xFE
+#define DATA_TOKEN_CMD24 0xFE
+#define DATA_TOKEN_CMD25 0xFC
+
+static int SDCARD_WaitDataToken(uint8_t token) {
+    uint8_t fb;
+    // make sure FF is transmitted during receive
+    uint8_t tx = 0xFF;
+    for(;;) {
+        HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, &fb, sizeof(fb), HAL_MAX_DELAY);
+        if(fb == token)
+            break;
+
+        if(fb != 0xFF)
+            return -1;
+    }
+    return 0;
+}
+
+static int SDCARD_ReadBytes(uint8_t* buff, size_t buff_size) {
+    // make sure FF is transmitted during receive
+    uint8_t tx = 0xFF;
+    while(buff_size > 0) {
+        HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, buff, 1, HAL_MAX_DELAY);
+        buff++;
+        buff_size--;
+    }
+
+    return 0;
+}
+
+static int SDCARD_WaitNotBusy() {
+    uint8_t busy;
+    do {
+        if(SDCARD_ReadBytes(&busy, sizeof(busy)) < 0) {
+            return -1;
+        }
+    } while(busy != 0xFF);
+
+    return 0;
+}
+ 
+int SDCARD_Init(void) {
+    /*
+    Step 1.
+
+    Set DI and CS high and apply 74 or more clock pulses to SCLK. Without this
+    step under certain circumstances SD-card will not work. For instance, when
+    multiple SPI devices are sharing the same bus (i.e. MISO, MOSI, CS).
+    */
+    SDCARD_Unselect();
+
+    uint8_t high = 0xFF;
+    for(int i = 0; i < 10; i++) { // 80 clock pulses
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, &high, sizeof(high), HAL_MAX_DELAY);
+    }
+
+    SDCARD_Select();
+
+    /*
+    Step 2.
+    
+    Send CMD0 (GO_IDLE_STATE): Reset the SD card.
+    */
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    {
+        static const uint8_t cmd[] =
+            { 0x40 | 0x00 /* CMD0 */, 0x00, 0x00, 0x00, 0x00 /* ARG = 0 */, (0x4A << 1) | 1 /* CRC7 + end bit */ };
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+    }
+
+    if(SDCARD_ReadR1() != 0x01) {
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /*
+    Step 3.
+
+    After the card enters idle state with a CMD0, send a CMD8 with argument of
+    0x000001AA and correct CRC prior to initialization process. If the CMD8 is
+    rejected with illigal command error (0x05), the card is SDC version 1 or
+    MMC version 3. If accepted, R7 response (R1(0x01) + 32-bit return value)
+    will be returned. The lower 12 bits in the return value 0x1AA means that
+    the card is SDC version 2 and it can work at voltage range of 2.7 to 3.6
+    volts. If not the case, the card should be rejected.
+    */
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    {
+        static const uint8_t cmd[] =
+            { 0x40 | 0x08 /* CMD8 */, 0x00, 0x00, 0x01, 0xAA /* ARG */, (0x43 << 1) | 1 /* CRC7 + end bit */ };
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+    }
+
+    if(SDCARD_ReadR1() != 0x01) {
+        SDCARD_Unselect();
+        return -2; // not an SDHC/SDXC card (i.e. SDSC, not supported)
+    }
+
+    {
+        uint8_t resp[4];
+        if(SDCARD_ReadBytes(resp, sizeof(resp)) < 0) {
+            SDCARD_Unselect();
+            return -3;
+        }
+
+        if(((resp[2] & 0x01) != 1) || (resp[3] != 0xAA)) {
+            SDCARD_Unselect();
+            return -4;
+        }
+    }
+
+    /*
+    Step 4.
+
+    And then initiate initialization with ACMD41 with HCS flag (bit 30).
+    */
+    for(;;) {
+        if(SDCARD_WaitNotBusy() < 0) { // keep this!
+            SDCARD_Unselect();
+            return -1;
+        }
+
+        {
+            static const uint8_t cmd[] =
+                { 0x40 | 0x37 /* CMD55 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ };
+            HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+        }
+
+        if(SDCARD_ReadR1() != 0x01) {
+            SDCARD_Unselect();
+            return -5;
+        }
+
+        if(SDCARD_WaitNotBusy() < 0) { // keep this!
+            SDCARD_Unselect();
+            return -1;
+        }
+
+        {
+            static const uint8_t cmd[] =
+                { 0x40 | 0x29 /* ACMD41 */, 0x40, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ };
+            HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+        }
+
+        uint8_t r1 = SDCARD_ReadR1();
+        if(r1 == 0x00) {
+            break;
+        }
+
+        if(r1 != 0x01) {
+            SDCARD_Unselect();
+            return -6;
+        }
+    }
+
+    /*
+    Step 5.
+
+    After the initialization completed, read OCR register with CMD58 and check
+    CCS flag (bit 30). When it is set, the card is a high-capacity card known
+    as SDHC/SDXC.
+    */
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    {
+        static const uint8_t cmd[] =
+            { 0x40 | 0x3A /* CMD58 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ };
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+    }
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -7;
+    }
+
+    {
+        uint8_t resp[4];
+        if(SDCARD_ReadBytes(resp, sizeof(resp)) < 0) {
+            SDCARD_Unselect();
+            return -8;
+        }
+
+        if((resp[0] & 0xC0) != 0xC0) {
+            SDCARD_Unselect();
+            return -9;
+        }
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+
+int SDCARD_GetBlocksNumber(uint32_t* num) {
+    uint8_t csd[16];
+    uint8_t crc[2];
+
+    SDCARD_Select();
+
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /* CMD9 (SEND_CSD) command */
+    {
+        static const uint8_t cmd[] =
+            { 0x40 | 0x09 /* CMD9 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ };
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+    }
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    if(SDCARD_WaitDataToken(DATA_TOKEN_CMD9) < 0) {
+        SDCARD_Unselect();
+        return -3;
+    }
+
+    if(SDCARD_ReadBytes(csd, sizeof(csd)) < 0) {
+        SDCARD_Unselect();
+        return -4;
+    }
+
+    if(SDCARD_ReadBytes(crc, sizeof(crc)) < 0) {
+        SDCARD_Unselect();
+        return -5;
+    }
+
+    SDCARD_Unselect();
+
+    // first byte is VVxxxxxxxx where VV is csd.version
+    if((csd[0] & 0xC0) != 0x40) // csd.version != 1
+        return -6;
+
+    uint32_t tmp = csd[7] & 0x3F; // two bits are reserved
+    tmp = (tmp << 8) | csd[8];
+    tmp = (tmp << 8) | csd[9];
+    tmp = (tmp + 1) << 10;
+    *num = tmp;
+
+    return 0;
+}
+
+int SDCARD_ReadSingleBlock(uint32_t blockNum, uint8_t* buff) {
+    uint8_t crc[2];
+
+    SDCARD_Select();
+
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /* CMD17 (SEND_SINGLE_BLOCK) command */
+    uint8_t cmd[] = {
+        0x40 | 0x11 /* CMD17 */,
+        (blockNum >> 24) & 0xFF, /* ARG */
+        (blockNum >> 16) & 0xFF,
+        (blockNum >> 8) & 0xFF,
+        blockNum & 0xFF,
+        (0x7F << 1) | 1 /* CRC7 + end bit */
+    };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    if(SDCARD_WaitDataToken(DATA_TOKEN_CMD17) < 0) {
+        SDCARD_Unselect();
+        return -3;
+    }
+
+    if(SDCARD_ReadBytes(buff, 512) < 0) {
+        SDCARD_Unselect();
+        return -4;
+    }
+
+    if(SDCARD_ReadBytes(crc, 2) < 0) {
+        SDCARD_Unselect();
+        return -5;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+
+int SDCARD_WriteSingleBlock(uint32_t blockNum, const uint8_t* buff) {
+    SDCARD_Select();
+
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /* CMD24 (WRITE_BLOCK) command */
+    uint8_t cmd[] = {
+        0x40 | 0x18 /* CMD24 */,
+        (blockNum >> 24) & 0xFF, /* ARG */
+        (blockNum >> 16) & 0xFF,
+        (blockNum >> 8) & 0xFF,
+        blockNum & 0xFF,
+        (0x7F << 1) | 1 /* CRC7 + end bit */
+    };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    uint8_t dataToken = DATA_TOKEN_CMD24;
+    uint8_t crc[2] = { 0xFF, 0xFF };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, &dataToken, sizeof(dataToken), HAL_MAX_DELAY);
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)buff, 512, HAL_MAX_DELAY);
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, crc, sizeof(crc), HAL_MAX_DELAY);
+
+    /*
+        dataResp:
+        xxx0abc1
+            010 - Data accepted
+            101 - Data rejected due to CRC error
+            110 - Data rejected due to write error
+    */
+    uint8_t dataResp;
+    SDCARD_ReadBytes(&dataResp, sizeof(dataResp));
+    if((dataResp & 0x1F) != 0x05) { // data rejected
+        SDCARD_Unselect();
+        return -3;
+    }
+
+    if(SDCARD_WaitNotBusy() < 0) {
+        SDCARD_Unselect();
+        return -4;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+int SDCARD_ReadBegin(uint32_t blockNum) {
+    SDCARD_Select();
+
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /* CMD18 (READ_MULTIPLE_BLOCK) command */
+    uint8_t cmd[] = {
+        0x40 | 0x12 /* CMD18 */,
+        (blockNum >> 24) & 0xFF, /* ARG */
+        (blockNum >> 16) & 0xFF,
+        (blockNum >> 8) & 0xFF,
+        blockNum & 0xFF,
+        (0x7F << 1) | 1 /* CRC7 + end bit */
+    };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+int SDCARD_ReadData(uint8_t* buff) {
+    uint8_t crc[2];
+    SDCARD_Select();
+
+    if(SDCARD_WaitDataToken(DATA_TOKEN_CMD18) < 0) {
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    if(SDCARD_ReadBytes(buff, 512) < 0) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    if(SDCARD_ReadBytes(crc, 2) < 0) {
+        SDCARD_Unselect();
+        return -3;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+
+}
+
+int SDCARD_ReadEnd() {
+    SDCARD_Select();
+
+    /* CMD12 (STOP_TRANSMISSION) */
+    {
+        static const uint8_t cmd[] = { 0x40 | 0x0C /* CMD12 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 };
+        HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+    }
+
+    /*
+    The received byte immediataly following CMD12 is a stuff byte, it should be
+    discarded before receive the response of the CMD12
+    */
+    uint8_t stuffByte;
+    if(SDCARD_ReadBytes(&stuffByte, sizeof(stuffByte)) < 0) {
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+    
+    SDCARD_Unselect();
+    return 0;
+}
+
+
+int SDCARD_WriteBegin(uint32_t blockNum) {
+    SDCARD_Select();
+
+    if(SDCARD_WaitNotBusy() < 0) { // keep this!
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    /* CMD25 (WRITE_MULTIPLE_BLOCK) command */
+    uint8_t cmd[] = {
+        0x40 | 0x19 /* CMD25 */,
+        (blockNum >> 24) & 0xFF, /* ARG */
+        (blockNum >> 16) & 0xFF,
+        (blockNum >> 8) & 0xFF,
+        blockNum & 0xFF,
+        (0x7F << 1) | 1 /* CRC7 + end bit */
+    };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY);
+
+    if(SDCARD_ReadR1() != 0x00) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+int SDCARD_WriteData(const uint8_t* buff) {
+    SDCARD_Select();
+
+    uint8_t dataToken = DATA_TOKEN_CMD25;
+    uint8_t crc[2] = { 0xFF, 0xFF };
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, &dataToken, sizeof(dataToken), HAL_MAX_DELAY);
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)buff, 512, HAL_MAX_DELAY);
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, crc, sizeof(crc), HAL_MAX_DELAY);
+
+    /*
+        dataResp:
+        xxx0abc1
+            010 - Data accepted
+            101 - Data rejected due to CRC error
+            110 - Data rejected due to write error
+    */
+    uint8_t dataResp;
+    SDCARD_ReadBytes(&dataResp, sizeof(dataResp));
+    if((dataResp & 0x1F) != 0x05) { // data rejected
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    if(SDCARD_WaitNotBusy() < 0) {
+        SDCARD_Unselect();
+        return -2;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+int SDCARD_WriteEnd() {
+    SDCARD_Select();
+
+    uint8_t stopTran = 0xFD; // stop transaction token for CMD25
+    HAL_SPI_Transmit(&SDCARD_SPI_PORT, &stopTran, sizeof(stopTran), HAL_MAX_DELAY);
+
+    // skip one byte before readyng "busy"
+    // this is required by the spec and is necessary for some real SD-cards!
+    uint8_t skipByte;
+    SDCARD_ReadBytes(&skipByte, sizeof(skipByte));
+
+    if(SDCARD_WaitNotBusy() < 0) {
+        SDCARD_Unselect();
+        return -1;
+    }
+
+    SDCARD_Unselect();
+    return 0;
+}
+
+