test
How can I remove this one?
sdcard.c@0:76d6402d766d, 2019-03-19 (annotated)
- Committer:
- dzbios
- Date:
- Tue Mar 19 14:47:28 2019 +0000
- Revision:
- 0:76d6402d766d
test
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dzbios | 0:76d6402d766d | 1 | /* vim: set ai et ts=4 sw=4: */ |
dzbios | 0:76d6402d766d | 2 | |
dzbios | 0:76d6402d766d | 3 | #include "sdcard.h" |
dzbios | 0:76d6402d766d | 4 | |
dzbios | 0:76d6402d766d | 5 | static void SDCARD_Select() { |
dzbios | 0:76d6402d766d | 6 | HAL_GPIO_WritePin(SDCARD_CS_GPIO_Port, SDCARD_CS_Pin, GPIO_PIN_RESET); |
dzbios | 0:76d6402d766d | 7 | } |
dzbios | 0:76d6402d766d | 8 | |
dzbios | 0:76d6402d766d | 9 | void SDCARD_Unselect() { |
dzbios | 0:76d6402d766d | 10 | HAL_GPIO_WritePin(SDCARD_CS_GPIO_Port, SDCARD_CS_Pin, GPIO_PIN_SET); |
dzbios | 0:76d6402d766d | 11 | } |
dzbios | 0:76d6402d766d | 12 | |
dzbios | 0:76d6402d766d | 13 | /* |
dzbios | 0:76d6402d766d | 14 | R1: 0abcdefg |
dzbios | 0:76d6402d766d | 15 | ||||||`- 1th bit (g): card is in idle state |
dzbios | 0:76d6402d766d | 16 | |||||`-- 2th bit (f): erase sequence cleared |
dzbios | 0:76d6402d766d | 17 | ||||`--- 3th bit (e): illigal command detected |
dzbios | 0:76d6402d766d | 18 | |||`---- 4th bit (d): crc check error |
dzbios | 0:76d6402d766d | 19 | ||`----- 5th bit (c): error in the sequence of erase commands |
dzbios | 0:76d6402d766d | 20 | |`------ 6th bit (b): misaligned addres used in command |
dzbios | 0:76d6402d766d | 21 | `------- 7th bit (a): command argument outside allowed range |
dzbios | 0:76d6402d766d | 22 | (8th bit is always zero) |
dzbios | 0:76d6402d766d | 23 | */ |
dzbios | 0:76d6402d766d | 24 | static uint8_t SDCARD_ReadR1() { |
dzbios | 0:76d6402d766d | 25 | uint8_t r1; |
dzbios | 0:76d6402d766d | 26 | // make sure FF is transmitted during receive |
dzbios | 0:76d6402d766d | 27 | uint8_t tx = 0xFF; |
dzbios | 0:76d6402d766d | 28 | for(;;) { |
dzbios | 0:76d6402d766d | 29 | HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, &r1, sizeof(r1), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 30 | if((r1 & 0x80) == 0) // 8th bit alwyas zero, r1 recevied |
dzbios | 0:76d6402d766d | 31 | break; |
dzbios | 0:76d6402d766d | 32 | } |
dzbios | 0:76d6402d766d | 33 | return r1; |
dzbios | 0:76d6402d766d | 34 | } |
dzbios | 0:76d6402d766d | 35 | |
dzbios | 0:76d6402d766d | 36 | // data token for CMD9, CMD17, CMD18 and CMD24 are the same |
dzbios | 0:76d6402d766d | 37 | #define DATA_TOKEN_CMD9 0xFE |
dzbios | 0:76d6402d766d | 38 | #define DATA_TOKEN_CMD17 0xFE |
dzbios | 0:76d6402d766d | 39 | #define DATA_TOKEN_CMD18 0xFE |
dzbios | 0:76d6402d766d | 40 | #define DATA_TOKEN_CMD24 0xFE |
dzbios | 0:76d6402d766d | 41 | #define DATA_TOKEN_CMD25 0xFC |
dzbios | 0:76d6402d766d | 42 | |
dzbios | 0:76d6402d766d | 43 | static int SDCARD_WaitDataToken(uint8_t token) { |
dzbios | 0:76d6402d766d | 44 | uint8_t fb; |
dzbios | 0:76d6402d766d | 45 | // make sure FF is transmitted during receive |
dzbios | 0:76d6402d766d | 46 | uint8_t tx = 0xFF; |
dzbios | 0:76d6402d766d | 47 | for(;;) { |
dzbios | 0:76d6402d766d | 48 | HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, &fb, sizeof(fb), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 49 | if(fb == token) |
dzbios | 0:76d6402d766d | 50 | break; |
dzbios | 0:76d6402d766d | 51 | |
dzbios | 0:76d6402d766d | 52 | if(fb != 0xFF) |
dzbios | 0:76d6402d766d | 53 | return -1; |
dzbios | 0:76d6402d766d | 54 | } |
dzbios | 0:76d6402d766d | 55 | return 0; |
dzbios | 0:76d6402d766d | 56 | } |
dzbios | 0:76d6402d766d | 57 | |
dzbios | 0:76d6402d766d | 58 | static int SDCARD_ReadBytes(uint8_t* buff, size_t buff_size) { |
dzbios | 0:76d6402d766d | 59 | // make sure FF is transmitted during receive |
dzbios | 0:76d6402d766d | 60 | uint8_t tx = 0xFF; |
dzbios | 0:76d6402d766d | 61 | while(buff_size > 0) { |
dzbios | 0:76d6402d766d | 62 | HAL_SPI_TransmitReceive(&SDCARD_SPI_PORT, &tx, buff, 1, HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 63 | buff++; |
dzbios | 0:76d6402d766d | 64 | buff_size--; |
dzbios | 0:76d6402d766d | 65 | } |
dzbios | 0:76d6402d766d | 66 | |
dzbios | 0:76d6402d766d | 67 | return 0; |
dzbios | 0:76d6402d766d | 68 | } |
dzbios | 0:76d6402d766d | 69 | |
dzbios | 0:76d6402d766d | 70 | static int SDCARD_WaitNotBusy() { |
dzbios | 0:76d6402d766d | 71 | uint8_t busy; |
dzbios | 0:76d6402d766d | 72 | do { |
dzbios | 0:76d6402d766d | 73 | if(SDCARD_ReadBytes(&busy, sizeof(busy)) < 0) { |
dzbios | 0:76d6402d766d | 74 | return -1; |
dzbios | 0:76d6402d766d | 75 | } |
dzbios | 0:76d6402d766d | 76 | } while(busy != 0xFF); |
dzbios | 0:76d6402d766d | 77 | |
dzbios | 0:76d6402d766d | 78 | return 0; |
dzbios | 0:76d6402d766d | 79 | } |
dzbios | 0:76d6402d766d | 80 | |
dzbios | 0:76d6402d766d | 81 | int SDCARD_Init(void) { |
dzbios | 0:76d6402d766d | 82 | /* |
dzbios | 0:76d6402d766d | 83 | Step 1. |
dzbios | 0:76d6402d766d | 84 | |
dzbios | 0:76d6402d766d | 85 | Set DI and CS high and apply 74 or more clock pulses to SCLK. Without this |
dzbios | 0:76d6402d766d | 86 | step under certain circumstances SD-card will not work. For instance, when |
dzbios | 0:76d6402d766d | 87 | multiple SPI devices are sharing the same bus (i.e. MISO, MOSI, CS). |
dzbios | 0:76d6402d766d | 88 | */ |
dzbios | 0:76d6402d766d | 89 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 90 | |
dzbios | 0:76d6402d766d | 91 | uint8_t high = 0xFF; |
dzbios | 0:76d6402d766d | 92 | for(int i = 0; i < 10; i++) { // 80 clock pulses |
dzbios | 0:76d6402d766d | 93 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, &high, sizeof(high), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 94 | } |
dzbios | 0:76d6402d766d | 95 | |
dzbios | 0:76d6402d766d | 96 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 97 | |
dzbios | 0:76d6402d766d | 98 | /* |
dzbios | 0:76d6402d766d | 99 | Step 2. |
dzbios | 0:76d6402d766d | 100 | |
dzbios | 0:76d6402d766d | 101 | Send CMD0 (GO_IDLE_STATE): Reset the SD card. |
dzbios | 0:76d6402d766d | 102 | */ |
dzbios | 0:76d6402d766d | 103 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 104 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 105 | return -1; |
dzbios | 0:76d6402d766d | 106 | } |
dzbios | 0:76d6402d766d | 107 | |
dzbios | 0:76d6402d766d | 108 | { |
dzbios | 0:76d6402d766d | 109 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 110 | { 0x40 | 0x00 /* CMD0 */, 0x00, 0x00, 0x00, 0x00 /* ARG = 0 */, (0x4A << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 111 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 112 | } |
dzbios | 0:76d6402d766d | 113 | |
dzbios | 0:76d6402d766d | 114 | if(SDCARD_ReadR1() != 0x01) { |
dzbios | 0:76d6402d766d | 115 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 116 | return -1; |
dzbios | 0:76d6402d766d | 117 | } |
dzbios | 0:76d6402d766d | 118 | |
dzbios | 0:76d6402d766d | 119 | /* |
dzbios | 0:76d6402d766d | 120 | Step 3. |
dzbios | 0:76d6402d766d | 121 | |
dzbios | 0:76d6402d766d | 122 | After the card enters idle state with a CMD0, send a CMD8 with argument of |
dzbios | 0:76d6402d766d | 123 | 0x000001AA and correct CRC prior to initialization process. If the CMD8 is |
dzbios | 0:76d6402d766d | 124 | rejected with illigal command error (0x05), the card is SDC version 1 or |
dzbios | 0:76d6402d766d | 125 | MMC version 3. If accepted, R7 response (R1(0x01) + 32-bit return value) |
dzbios | 0:76d6402d766d | 126 | will be returned. The lower 12 bits in the return value 0x1AA means that |
dzbios | 0:76d6402d766d | 127 | the card is SDC version 2 and it can work at voltage range of 2.7 to 3.6 |
dzbios | 0:76d6402d766d | 128 | volts. If not the case, the card should be rejected. |
dzbios | 0:76d6402d766d | 129 | */ |
dzbios | 0:76d6402d766d | 130 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 131 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 132 | return -1; |
dzbios | 0:76d6402d766d | 133 | } |
dzbios | 0:76d6402d766d | 134 | |
dzbios | 0:76d6402d766d | 135 | { |
dzbios | 0:76d6402d766d | 136 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 137 | { 0x40 | 0x08 /* CMD8 */, 0x00, 0x00, 0x01, 0xAA /* ARG */, (0x43 << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 138 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 139 | } |
dzbios | 0:76d6402d766d | 140 | |
dzbios | 0:76d6402d766d | 141 | if(SDCARD_ReadR1() != 0x01) { |
dzbios | 0:76d6402d766d | 142 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 143 | return -2; // not an SDHC/SDXC card (i.e. SDSC, not supported) |
dzbios | 0:76d6402d766d | 144 | } |
dzbios | 0:76d6402d766d | 145 | |
dzbios | 0:76d6402d766d | 146 | { |
dzbios | 0:76d6402d766d | 147 | uint8_t resp[4]; |
dzbios | 0:76d6402d766d | 148 | if(SDCARD_ReadBytes(resp, sizeof(resp)) < 0) { |
dzbios | 0:76d6402d766d | 149 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 150 | return -3; |
dzbios | 0:76d6402d766d | 151 | } |
dzbios | 0:76d6402d766d | 152 | |
dzbios | 0:76d6402d766d | 153 | if(((resp[2] & 0x01) != 1) || (resp[3] != 0xAA)) { |
dzbios | 0:76d6402d766d | 154 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 155 | return -4; |
dzbios | 0:76d6402d766d | 156 | } |
dzbios | 0:76d6402d766d | 157 | } |
dzbios | 0:76d6402d766d | 158 | |
dzbios | 0:76d6402d766d | 159 | /* |
dzbios | 0:76d6402d766d | 160 | Step 4. |
dzbios | 0:76d6402d766d | 161 | |
dzbios | 0:76d6402d766d | 162 | And then initiate initialization with ACMD41 with HCS flag (bit 30). |
dzbios | 0:76d6402d766d | 163 | */ |
dzbios | 0:76d6402d766d | 164 | for(;;) { |
dzbios | 0:76d6402d766d | 165 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 166 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 167 | return -1; |
dzbios | 0:76d6402d766d | 168 | } |
dzbios | 0:76d6402d766d | 169 | |
dzbios | 0:76d6402d766d | 170 | { |
dzbios | 0:76d6402d766d | 171 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 172 | { 0x40 | 0x37 /* CMD55 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 173 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 174 | } |
dzbios | 0:76d6402d766d | 175 | |
dzbios | 0:76d6402d766d | 176 | if(SDCARD_ReadR1() != 0x01) { |
dzbios | 0:76d6402d766d | 177 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 178 | return -5; |
dzbios | 0:76d6402d766d | 179 | } |
dzbios | 0:76d6402d766d | 180 | |
dzbios | 0:76d6402d766d | 181 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 182 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 183 | return -1; |
dzbios | 0:76d6402d766d | 184 | } |
dzbios | 0:76d6402d766d | 185 | |
dzbios | 0:76d6402d766d | 186 | { |
dzbios | 0:76d6402d766d | 187 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 188 | { 0x40 | 0x29 /* ACMD41 */, 0x40, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 189 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 190 | } |
dzbios | 0:76d6402d766d | 191 | |
dzbios | 0:76d6402d766d | 192 | uint8_t r1 = SDCARD_ReadR1(); |
dzbios | 0:76d6402d766d | 193 | if(r1 == 0x00) { |
dzbios | 0:76d6402d766d | 194 | break; |
dzbios | 0:76d6402d766d | 195 | } |
dzbios | 0:76d6402d766d | 196 | |
dzbios | 0:76d6402d766d | 197 | if(r1 != 0x01) { |
dzbios | 0:76d6402d766d | 198 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 199 | return -6; |
dzbios | 0:76d6402d766d | 200 | } |
dzbios | 0:76d6402d766d | 201 | } |
dzbios | 0:76d6402d766d | 202 | |
dzbios | 0:76d6402d766d | 203 | /* |
dzbios | 0:76d6402d766d | 204 | Step 5. |
dzbios | 0:76d6402d766d | 205 | |
dzbios | 0:76d6402d766d | 206 | After the initialization completed, read OCR register with CMD58 and check |
dzbios | 0:76d6402d766d | 207 | CCS flag (bit 30). When it is set, the card is a high-capacity card known |
dzbios | 0:76d6402d766d | 208 | as SDHC/SDXC. |
dzbios | 0:76d6402d766d | 209 | */ |
dzbios | 0:76d6402d766d | 210 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 211 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 212 | return -1; |
dzbios | 0:76d6402d766d | 213 | } |
dzbios | 0:76d6402d766d | 214 | |
dzbios | 0:76d6402d766d | 215 | { |
dzbios | 0:76d6402d766d | 216 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 217 | { 0x40 | 0x3A /* CMD58 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 218 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 219 | } |
dzbios | 0:76d6402d766d | 220 | |
dzbios | 0:76d6402d766d | 221 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 222 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 223 | return -7; |
dzbios | 0:76d6402d766d | 224 | } |
dzbios | 0:76d6402d766d | 225 | |
dzbios | 0:76d6402d766d | 226 | { |
dzbios | 0:76d6402d766d | 227 | uint8_t resp[4]; |
dzbios | 0:76d6402d766d | 228 | if(SDCARD_ReadBytes(resp, sizeof(resp)) < 0) { |
dzbios | 0:76d6402d766d | 229 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 230 | return -8; |
dzbios | 0:76d6402d766d | 231 | } |
dzbios | 0:76d6402d766d | 232 | |
dzbios | 0:76d6402d766d | 233 | if((resp[0] & 0xC0) != 0xC0) { |
dzbios | 0:76d6402d766d | 234 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 235 | return -9; |
dzbios | 0:76d6402d766d | 236 | } |
dzbios | 0:76d6402d766d | 237 | } |
dzbios | 0:76d6402d766d | 238 | |
dzbios | 0:76d6402d766d | 239 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 240 | return 0; |
dzbios | 0:76d6402d766d | 241 | } |
dzbios | 0:76d6402d766d | 242 | |
dzbios | 0:76d6402d766d | 243 | |
dzbios | 0:76d6402d766d | 244 | int SDCARD_GetBlocksNumber(uint32_t* num) { |
dzbios | 0:76d6402d766d | 245 | uint8_t csd[16]; |
dzbios | 0:76d6402d766d | 246 | uint8_t crc[2]; |
dzbios | 0:76d6402d766d | 247 | |
dzbios | 0:76d6402d766d | 248 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 249 | |
dzbios | 0:76d6402d766d | 250 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 251 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 252 | return -1; |
dzbios | 0:76d6402d766d | 253 | } |
dzbios | 0:76d6402d766d | 254 | |
dzbios | 0:76d6402d766d | 255 | /* CMD9 (SEND_CSD) command */ |
dzbios | 0:76d6402d766d | 256 | { |
dzbios | 0:76d6402d766d | 257 | static const uint8_t cmd[] = |
dzbios | 0:76d6402d766d | 258 | { 0x40 | 0x09 /* CMD9 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 /* CRC7 + end bit */ }; |
dzbios | 0:76d6402d766d | 259 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 260 | } |
dzbios | 0:76d6402d766d | 261 | |
dzbios | 0:76d6402d766d | 262 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 263 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 264 | return -2; |
dzbios | 0:76d6402d766d | 265 | } |
dzbios | 0:76d6402d766d | 266 | |
dzbios | 0:76d6402d766d | 267 | if(SDCARD_WaitDataToken(DATA_TOKEN_CMD9) < 0) { |
dzbios | 0:76d6402d766d | 268 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 269 | return -3; |
dzbios | 0:76d6402d766d | 270 | } |
dzbios | 0:76d6402d766d | 271 | |
dzbios | 0:76d6402d766d | 272 | if(SDCARD_ReadBytes(csd, sizeof(csd)) < 0) { |
dzbios | 0:76d6402d766d | 273 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 274 | return -4; |
dzbios | 0:76d6402d766d | 275 | } |
dzbios | 0:76d6402d766d | 276 | |
dzbios | 0:76d6402d766d | 277 | if(SDCARD_ReadBytes(crc, sizeof(crc)) < 0) { |
dzbios | 0:76d6402d766d | 278 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 279 | return -5; |
dzbios | 0:76d6402d766d | 280 | } |
dzbios | 0:76d6402d766d | 281 | |
dzbios | 0:76d6402d766d | 282 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 283 | |
dzbios | 0:76d6402d766d | 284 | // first byte is VVxxxxxxxx where VV is csd.version |
dzbios | 0:76d6402d766d | 285 | if((csd[0] & 0xC0) != 0x40) // csd.version != 1 |
dzbios | 0:76d6402d766d | 286 | return -6; |
dzbios | 0:76d6402d766d | 287 | |
dzbios | 0:76d6402d766d | 288 | uint32_t tmp = csd[7] & 0x3F; // two bits are reserved |
dzbios | 0:76d6402d766d | 289 | tmp = (tmp << 8) | csd[8]; |
dzbios | 0:76d6402d766d | 290 | tmp = (tmp << 8) | csd[9]; |
dzbios | 0:76d6402d766d | 291 | tmp = (tmp + 1) << 10; |
dzbios | 0:76d6402d766d | 292 | *num = tmp; |
dzbios | 0:76d6402d766d | 293 | |
dzbios | 0:76d6402d766d | 294 | return 0; |
dzbios | 0:76d6402d766d | 295 | } |
dzbios | 0:76d6402d766d | 296 | |
dzbios | 0:76d6402d766d | 297 | int SDCARD_ReadSingleBlock(uint32_t blockNum, uint8_t* buff) { |
dzbios | 0:76d6402d766d | 298 | uint8_t crc[2]; |
dzbios | 0:76d6402d766d | 299 | |
dzbios | 0:76d6402d766d | 300 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 301 | |
dzbios | 0:76d6402d766d | 302 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 303 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 304 | return -1; |
dzbios | 0:76d6402d766d | 305 | } |
dzbios | 0:76d6402d766d | 306 | |
dzbios | 0:76d6402d766d | 307 | /* CMD17 (SEND_SINGLE_BLOCK) command */ |
dzbios | 0:76d6402d766d | 308 | uint8_t cmd[] = { |
dzbios | 0:76d6402d766d | 309 | 0x40 | 0x11 /* CMD17 */, |
dzbios | 0:76d6402d766d | 310 | (blockNum >> 24) & 0xFF, /* ARG */ |
dzbios | 0:76d6402d766d | 311 | (blockNum >> 16) & 0xFF, |
dzbios | 0:76d6402d766d | 312 | (blockNum >> 8) & 0xFF, |
dzbios | 0:76d6402d766d | 313 | blockNum & 0xFF, |
dzbios | 0:76d6402d766d | 314 | (0x7F << 1) | 1 /* CRC7 + end bit */ |
dzbios | 0:76d6402d766d | 315 | }; |
dzbios | 0:76d6402d766d | 316 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 317 | |
dzbios | 0:76d6402d766d | 318 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 319 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 320 | return -2; |
dzbios | 0:76d6402d766d | 321 | } |
dzbios | 0:76d6402d766d | 322 | |
dzbios | 0:76d6402d766d | 323 | if(SDCARD_WaitDataToken(DATA_TOKEN_CMD17) < 0) { |
dzbios | 0:76d6402d766d | 324 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 325 | return -3; |
dzbios | 0:76d6402d766d | 326 | } |
dzbios | 0:76d6402d766d | 327 | |
dzbios | 0:76d6402d766d | 328 | if(SDCARD_ReadBytes(buff, 512) < 0) { |
dzbios | 0:76d6402d766d | 329 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 330 | return -4; |
dzbios | 0:76d6402d766d | 331 | } |
dzbios | 0:76d6402d766d | 332 | |
dzbios | 0:76d6402d766d | 333 | if(SDCARD_ReadBytes(crc, 2) < 0) { |
dzbios | 0:76d6402d766d | 334 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 335 | return -5; |
dzbios | 0:76d6402d766d | 336 | } |
dzbios | 0:76d6402d766d | 337 | |
dzbios | 0:76d6402d766d | 338 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 339 | return 0; |
dzbios | 0:76d6402d766d | 340 | } |
dzbios | 0:76d6402d766d | 341 | |
dzbios | 0:76d6402d766d | 342 | |
dzbios | 0:76d6402d766d | 343 | int SDCARD_WriteSingleBlock(uint32_t blockNum, const uint8_t* buff) { |
dzbios | 0:76d6402d766d | 344 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 345 | |
dzbios | 0:76d6402d766d | 346 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 347 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 348 | return -1; |
dzbios | 0:76d6402d766d | 349 | } |
dzbios | 0:76d6402d766d | 350 | |
dzbios | 0:76d6402d766d | 351 | /* CMD24 (WRITE_BLOCK) command */ |
dzbios | 0:76d6402d766d | 352 | uint8_t cmd[] = { |
dzbios | 0:76d6402d766d | 353 | 0x40 | 0x18 /* CMD24 */, |
dzbios | 0:76d6402d766d | 354 | (blockNum >> 24) & 0xFF, /* ARG */ |
dzbios | 0:76d6402d766d | 355 | (blockNum >> 16) & 0xFF, |
dzbios | 0:76d6402d766d | 356 | (blockNum >> 8) & 0xFF, |
dzbios | 0:76d6402d766d | 357 | blockNum & 0xFF, |
dzbios | 0:76d6402d766d | 358 | (0x7F << 1) | 1 /* CRC7 + end bit */ |
dzbios | 0:76d6402d766d | 359 | }; |
dzbios | 0:76d6402d766d | 360 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 361 | |
dzbios | 0:76d6402d766d | 362 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 363 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 364 | return -2; |
dzbios | 0:76d6402d766d | 365 | } |
dzbios | 0:76d6402d766d | 366 | |
dzbios | 0:76d6402d766d | 367 | uint8_t dataToken = DATA_TOKEN_CMD24; |
dzbios | 0:76d6402d766d | 368 | uint8_t crc[2] = { 0xFF, 0xFF }; |
dzbios | 0:76d6402d766d | 369 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, &dataToken, sizeof(dataToken), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 370 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)buff, 512, HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 371 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, crc, sizeof(crc), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 372 | |
dzbios | 0:76d6402d766d | 373 | /* |
dzbios | 0:76d6402d766d | 374 | dataResp: |
dzbios | 0:76d6402d766d | 375 | xxx0abc1 |
dzbios | 0:76d6402d766d | 376 | 010 - Data accepted |
dzbios | 0:76d6402d766d | 377 | 101 - Data rejected due to CRC error |
dzbios | 0:76d6402d766d | 378 | 110 - Data rejected due to write error |
dzbios | 0:76d6402d766d | 379 | */ |
dzbios | 0:76d6402d766d | 380 | uint8_t dataResp; |
dzbios | 0:76d6402d766d | 381 | SDCARD_ReadBytes(&dataResp, sizeof(dataResp)); |
dzbios | 0:76d6402d766d | 382 | if((dataResp & 0x1F) != 0x05) { // data rejected |
dzbios | 0:76d6402d766d | 383 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 384 | return -3; |
dzbios | 0:76d6402d766d | 385 | } |
dzbios | 0:76d6402d766d | 386 | |
dzbios | 0:76d6402d766d | 387 | if(SDCARD_WaitNotBusy() < 0) { |
dzbios | 0:76d6402d766d | 388 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 389 | return -4; |
dzbios | 0:76d6402d766d | 390 | } |
dzbios | 0:76d6402d766d | 391 | |
dzbios | 0:76d6402d766d | 392 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 393 | return 0; |
dzbios | 0:76d6402d766d | 394 | } |
dzbios | 0:76d6402d766d | 395 | |
dzbios | 0:76d6402d766d | 396 | int SDCARD_ReadBegin(uint32_t blockNum) { |
dzbios | 0:76d6402d766d | 397 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 398 | |
dzbios | 0:76d6402d766d | 399 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 400 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 401 | return -1; |
dzbios | 0:76d6402d766d | 402 | } |
dzbios | 0:76d6402d766d | 403 | |
dzbios | 0:76d6402d766d | 404 | /* CMD18 (READ_MULTIPLE_BLOCK) command */ |
dzbios | 0:76d6402d766d | 405 | uint8_t cmd[] = { |
dzbios | 0:76d6402d766d | 406 | 0x40 | 0x12 /* CMD18 */, |
dzbios | 0:76d6402d766d | 407 | (blockNum >> 24) & 0xFF, /* ARG */ |
dzbios | 0:76d6402d766d | 408 | (blockNum >> 16) & 0xFF, |
dzbios | 0:76d6402d766d | 409 | (blockNum >> 8) & 0xFF, |
dzbios | 0:76d6402d766d | 410 | blockNum & 0xFF, |
dzbios | 0:76d6402d766d | 411 | (0x7F << 1) | 1 /* CRC7 + end bit */ |
dzbios | 0:76d6402d766d | 412 | }; |
dzbios | 0:76d6402d766d | 413 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 414 | |
dzbios | 0:76d6402d766d | 415 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 416 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 417 | return -2; |
dzbios | 0:76d6402d766d | 418 | } |
dzbios | 0:76d6402d766d | 419 | |
dzbios | 0:76d6402d766d | 420 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 421 | return 0; |
dzbios | 0:76d6402d766d | 422 | } |
dzbios | 0:76d6402d766d | 423 | |
dzbios | 0:76d6402d766d | 424 | int SDCARD_ReadData(uint8_t* buff) { |
dzbios | 0:76d6402d766d | 425 | uint8_t crc[2]; |
dzbios | 0:76d6402d766d | 426 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 427 | |
dzbios | 0:76d6402d766d | 428 | if(SDCARD_WaitDataToken(DATA_TOKEN_CMD18) < 0) { |
dzbios | 0:76d6402d766d | 429 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 430 | return -1; |
dzbios | 0:76d6402d766d | 431 | } |
dzbios | 0:76d6402d766d | 432 | |
dzbios | 0:76d6402d766d | 433 | if(SDCARD_ReadBytes(buff, 512) < 0) { |
dzbios | 0:76d6402d766d | 434 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 435 | return -2; |
dzbios | 0:76d6402d766d | 436 | } |
dzbios | 0:76d6402d766d | 437 | |
dzbios | 0:76d6402d766d | 438 | if(SDCARD_ReadBytes(crc, 2) < 0) { |
dzbios | 0:76d6402d766d | 439 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 440 | return -3; |
dzbios | 0:76d6402d766d | 441 | } |
dzbios | 0:76d6402d766d | 442 | |
dzbios | 0:76d6402d766d | 443 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 444 | return 0; |
dzbios | 0:76d6402d766d | 445 | |
dzbios | 0:76d6402d766d | 446 | } |
dzbios | 0:76d6402d766d | 447 | |
dzbios | 0:76d6402d766d | 448 | int SDCARD_ReadEnd() { |
dzbios | 0:76d6402d766d | 449 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 450 | |
dzbios | 0:76d6402d766d | 451 | /* CMD12 (STOP_TRANSMISSION) */ |
dzbios | 0:76d6402d766d | 452 | { |
dzbios | 0:76d6402d766d | 453 | static const uint8_t cmd[] = { 0x40 | 0x0C /* CMD12 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 }; |
dzbios | 0:76d6402d766d | 454 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 455 | } |
dzbios | 0:76d6402d766d | 456 | |
dzbios | 0:76d6402d766d | 457 | /* |
dzbios | 0:76d6402d766d | 458 | The received byte immediataly following CMD12 is a stuff byte, it should be |
dzbios | 0:76d6402d766d | 459 | discarded before receive the response of the CMD12 |
dzbios | 0:76d6402d766d | 460 | */ |
dzbios | 0:76d6402d766d | 461 | uint8_t stuffByte; |
dzbios | 0:76d6402d766d | 462 | if(SDCARD_ReadBytes(&stuffByte, sizeof(stuffByte)) < 0) { |
dzbios | 0:76d6402d766d | 463 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 464 | return -1; |
dzbios | 0:76d6402d766d | 465 | } |
dzbios | 0:76d6402d766d | 466 | |
dzbios | 0:76d6402d766d | 467 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 468 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 469 | return -2; |
dzbios | 0:76d6402d766d | 470 | } |
dzbios | 0:76d6402d766d | 471 | |
dzbios | 0:76d6402d766d | 472 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 473 | return 0; |
dzbios | 0:76d6402d766d | 474 | } |
dzbios | 0:76d6402d766d | 475 | |
dzbios | 0:76d6402d766d | 476 | |
dzbios | 0:76d6402d766d | 477 | int SDCARD_WriteBegin(uint32_t blockNum) { |
dzbios | 0:76d6402d766d | 478 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 479 | |
dzbios | 0:76d6402d766d | 480 | if(SDCARD_WaitNotBusy() < 0) { // keep this! |
dzbios | 0:76d6402d766d | 481 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 482 | return -1; |
dzbios | 0:76d6402d766d | 483 | } |
dzbios | 0:76d6402d766d | 484 | |
dzbios | 0:76d6402d766d | 485 | /* CMD25 (WRITE_MULTIPLE_BLOCK) command */ |
dzbios | 0:76d6402d766d | 486 | uint8_t cmd[] = { |
dzbios | 0:76d6402d766d | 487 | 0x40 | 0x19 /* CMD25 */, |
dzbios | 0:76d6402d766d | 488 | (blockNum >> 24) & 0xFF, /* ARG */ |
dzbios | 0:76d6402d766d | 489 | (blockNum >> 16) & 0xFF, |
dzbios | 0:76d6402d766d | 490 | (blockNum >> 8) & 0xFF, |
dzbios | 0:76d6402d766d | 491 | blockNum & 0xFF, |
dzbios | 0:76d6402d766d | 492 | (0x7F << 1) | 1 /* CRC7 + end bit */ |
dzbios | 0:76d6402d766d | 493 | }; |
dzbios | 0:76d6402d766d | 494 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)cmd, sizeof(cmd), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 495 | |
dzbios | 0:76d6402d766d | 496 | if(SDCARD_ReadR1() != 0x00) { |
dzbios | 0:76d6402d766d | 497 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 498 | return -2; |
dzbios | 0:76d6402d766d | 499 | } |
dzbios | 0:76d6402d766d | 500 | |
dzbios | 0:76d6402d766d | 501 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 502 | return 0; |
dzbios | 0:76d6402d766d | 503 | } |
dzbios | 0:76d6402d766d | 504 | |
dzbios | 0:76d6402d766d | 505 | int SDCARD_WriteData(const uint8_t* buff) { |
dzbios | 0:76d6402d766d | 506 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 507 | |
dzbios | 0:76d6402d766d | 508 | uint8_t dataToken = DATA_TOKEN_CMD25; |
dzbios | 0:76d6402d766d | 509 | uint8_t crc[2] = { 0xFF, 0xFF }; |
dzbios | 0:76d6402d766d | 510 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, &dataToken, sizeof(dataToken), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 511 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, (uint8_t*)buff, 512, HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 512 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, crc, sizeof(crc), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 513 | |
dzbios | 0:76d6402d766d | 514 | /* |
dzbios | 0:76d6402d766d | 515 | dataResp: |
dzbios | 0:76d6402d766d | 516 | xxx0abc1 |
dzbios | 0:76d6402d766d | 517 | 010 - Data accepted |
dzbios | 0:76d6402d766d | 518 | 101 - Data rejected due to CRC error |
dzbios | 0:76d6402d766d | 519 | 110 - Data rejected due to write error |
dzbios | 0:76d6402d766d | 520 | */ |
dzbios | 0:76d6402d766d | 521 | uint8_t dataResp; |
dzbios | 0:76d6402d766d | 522 | SDCARD_ReadBytes(&dataResp, sizeof(dataResp)); |
dzbios | 0:76d6402d766d | 523 | if((dataResp & 0x1F) != 0x05) { // data rejected |
dzbios | 0:76d6402d766d | 524 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 525 | return -1; |
dzbios | 0:76d6402d766d | 526 | } |
dzbios | 0:76d6402d766d | 527 | |
dzbios | 0:76d6402d766d | 528 | if(SDCARD_WaitNotBusy() < 0) { |
dzbios | 0:76d6402d766d | 529 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 530 | return -2; |
dzbios | 0:76d6402d766d | 531 | } |
dzbios | 0:76d6402d766d | 532 | |
dzbios | 0:76d6402d766d | 533 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 534 | return 0; |
dzbios | 0:76d6402d766d | 535 | } |
dzbios | 0:76d6402d766d | 536 | |
dzbios | 0:76d6402d766d | 537 | int SDCARD_WriteEnd() { |
dzbios | 0:76d6402d766d | 538 | SDCARD_Select(); |
dzbios | 0:76d6402d766d | 539 | |
dzbios | 0:76d6402d766d | 540 | uint8_t stopTran = 0xFD; // stop transaction token for CMD25 |
dzbios | 0:76d6402d766d | 541 | HAL_SPI_Transmit(&SDCARD_SPI_PORT, &stopTran, sizeof(stopTran), HAL_MAX_DELAY); |
dzbios | 0:76d6402d766d | 542 | |
dzbios | 0:76d6402d766d | 543 | // skip one byte before readyng "busy" |
dzbios | 0:76d6402d766d | 544 | // this is required by the spec and is necessary for some real SD-cards! |
dzbios | 0:76d6402d766d | 545 | uint8_t skipByte; |
dzbios | 0:76d6402d766d | 546 | SDCARD_ReadBytes(&skipByte, sizeof(skipByte)); |
dzbios | 0:76d6402d766d | 547 | |
dzbios | 0:76d6402d766d | 548 | if(SDCARD_WaitNotBusy() < 0) { |
dzbios | 0:76d6402d766d | 549 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 550 | return -1; |
dzbios | 0:76d6402d766d | 551 | } |
dzbios | 0:76d6402d766d | 552 | |
dzbios | 0:76d6402d766d | 553 | SDCARD_Unselect(); |
dzbios | 0:76d6402d766d | 554 | return 0; |
dzbios | 0:76d6402d766d | 555 | } |
dzbios | 0:76d6402d766d | 556 | |
dzbios | 0:76d6402d766d | 557 |