test

How can I remove this one?

Files at this revision

API Documentation at this revision

Comitter:
dzbios
Date:
Tue Mar 19 14:47:28 2019 +0000
Commit message:
test

Changed in this revision

sdcard.c Show annotated file Show diff for this revision Revisions of this file
sdcard.h Show annotated file Show diff for this revision Revisions of this file
--- /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;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdcard.h	Tue Mar 19 14:47:28 2019 +0000
@@ -0,0 +1,36 @@
+/* vim: set ai et ts=4 sw=4: */
+#ifndef __SDCARD_H__
+#define __SDCARD_H__
+
+#include "stm32f4xx_hal.h"
+
+#define SDCARD_SPI_PORT      hspi1
+#define SDCARD_CS_Pin        GPIO_PIN_3 // Arduino shield: D3
+#define SDCARD_CS_GPIO_Port  GPIOB
+
+extern SPI_HandleTypeDef SDCARD_SPI_PORT;
+
+// call before initializing any SPI devices
+void SDCARD_Unselect();
+
+// all procedures return 0 on success, < 0 on failure
+
+extern int SDCARD_Init(void);
+int SDCARD_GetBlocksNumber(uint32_t* num);
+int SDCARD_ReadSingleBlock(uint32_t blockNum, uint8_t* buff); // sizeof(buff) == 512!
+int SDCARD_WriteSingleBlock(uint32_t blockNum, const uint8_t* buff); // sizeof(buff) == 512!
+
+// Read Multiple Blocks
+int SDCARD_ReadBegin(uint32_t blockNum);
+int SDCARD_ReadData(uint8_t* buff); // sizeof(buff) == 512!
+int SDCARD_ReadEnd();
+
+// Write Multiple Blocks
+int SDCARD_WriteBegin(uint32_t blockNum);
+int SDCARD_WriteData(const uint8_t* buff); // sizeof(buff) == 512!
+int SDCARD_WriteEnd();
+
+// TODO: read lock flag? CMD13, SEND_STATUS
+
+#endif // __SDCARD_H__
+