Hallo! Ich weiß es gibt schon genug Threads bzgl. SD Karten, nur habe ich nichts gefunden was mir bei meinem Problem helfen würde: Ich habe an mein STM32F4 Discovery Board ein SD-Karten Breakout Board via SPI nach der allgemein Bekannten Vorgangsweise angeschlossen: [[http://elm-chan.org/docs/mmc/mmc_e.html]] Dazu habe ich eines der Beispiele hergenommen und auf den STM32 portiert. Im Prinzip funktioniert das auch wunderbar. Ich kann Daten von der SD-Karte einlesen und daten darauf schreiben. Jetzt zum eigentlichen Problem: Ich habe das ganze mit 5 Karten verschiedener Größe (256Mb - 4Gb) getestet. Es funktioniert mit allen karten wunderbar, nur bei der Karte mit 256Mb zeigt sich folgendes Verhalten: Die Karte wird prinzipiell erkannt, also disk_initialize() gibt keinen Fehler zurück, nur kann ich weder Daten von der Karte lesen noch Daten darauf schreiben. Beim Schreiben kommt nicht mal ein Fehler zurück, jedoch werden die Daten nicht geschrieben. Die Karte funktioniert sonst einwandfrei, mit dem USB-Kartenleser funktionierts. Eigentlich hätte ich mir beim disk_initialize() einen Fehler erwartet, so wies bei den meisten der Fall ist, wenn die Karte nicht funktioniert. Hat vlt. irgendwer eine Idee was hier das Problem sein könnte? Lg, Franz
Zum Debuggen könntest du einen Logic Analyzer ans SPI hängen und genauer schauen was da passiert.
Franz schrieb: > Beim Schreiben kommt nicht mal ein Fehler zurück, jedoch > werden die Daten nicht geschrieben. Die Karte funktioniert sonst > einwandfrei, mit dem USB-Kartenleser funktionierts. Sind die Daten auch noch da, wenn Du die Karte aus dem Lesegerät entnommen und wieder eingesteckt hast?
Hallo! Danke erstmal für die Antworten! @asdf: Logicanalyzer hab ich leider keinen, nur ein Oszi und damit ist es leider nicht so leicht die gesamte Kommunikation zu analysieren. Jim Meba schrieb: > Franz schrieb: >> Beim Schreiben kommt nicht mal ein Fehler zurück, jedoch >> werden die Daten nicht geschrieben. Die Karte funktioniert sonst >> einwandfrei, mit dem USB-Kartenleser funktionierts. > > Sind die Daten auch noch da, wenn Du die Karte aus dem Lesegerät > entnommen und wieder eingesteckt hast? Ja die Daten sind dann auch noch da. Das habe ich natürlich getestet. Ich habe die Karte auch nicht anders formatiert. Alle sind FAT16 formatiert. holger schrieb: > SPI zu schnell? Die Baudrate ist auf ca. 164Khz eingestellt, diese wird in meinem Code auch nicht erhöht nach der Initialisierung. SD Karten sollten ja mehrere MHz vertragen, das sollte also nicht das Problem sein. Im Prinzip wäre es mir ja egal, da ich ja des öfteren davon gehört habe, dass manche SD-Karten einfach nicht funktionieren. Nur lässt sich bei diesen Fällen die Karte erst gar nicht initialisieren, was bei mir aber einwandfrei funktioniert. Sonst noch ideen? Lg, Franz PS: Werde euch später noch den Code hochladen, vlt sieht ja da gleich jmd einen Fehler.
Hallo! Hier die SPI-initialisierung
1 | void SPI_Configuration(void) |
2 | {
|
3 | SPI_InitTypeDef SPI_InitStructure; |
4 | |
5 | /* SPI configuration -------------------------------------------------------*/
|
6 | SPI_I2S_DeInit(SPI2); |
7 | SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; |
8 | SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; |
9 | SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; |
10 | SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; |
11 | SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; |
12 | SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; |
13 | SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; |
14 | SPI_InitStructure.SPI_CRCPolynomial = 7; |
15 | SPI_InitStructure.SPI_Mode = SPI_Mode_Master; |
16 | |
17 | SPI_Init(SPI2, &SPI_InitStructure); |
18 | SPI_CalculateCRC(SPI2, DISABLE); |
19 | /* Enable the SPI peripheral */
|
20 | SPI_Cmd(SPI2, ENABLE); |
21 | }
|
Und hier die funktionen in diskio.c:
1 | /*
|
2 | * low_level_functions.c
|
3 | *
|
4 | * Created on: Jul 12, 2013
|
5 | * Author: franz
|
6 | */
|
7 | |
8 | #include <stm32f4xx.h> |
9 | #include <stm32_configuration.h> |
10 | #include <diskio.h> |
11 | #include <helperFunctions.h> |
12 | |
13 | /*-----------------------------------------------------------------------*/
|
14 | /* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */
|
15 | /*-----------------------------------------------------------------------*/
|
16 | |
17 | |
18 | #define CS_HIGH() {GPIO_SetBits(GPIOB, GPIO_Pin_12); Delay(10);}
|
19 | #define CS_LOW() {GPIO_ResetBits(GPIOB, GPIO_Pin_12);Delay(10);}
|
20 | |
21 | #define FCLK_SLOW() ;
|
22 | #define FCLK_FAST() ;
|
23 | |
24 | |
25 | /**
|
26 | * @brief Detect if SD card is correctly plugged in the memory slot.
|
27 | * @param None
|
28 | * @retval Return if SD is detected or not
|
29 | */
|
30 | uint8_t SD_Detect(void) |
31 | {
|
32 | __IO uint8_t status = SD_PRESENT; |
33 | |
34 | /*!< Check GPIO to detect SD */
|
35 | if (GPIO_ReadInputDataBit(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) != Bit_RESET) |
36 | {
|
37 | status = SD_NOT_PRESENT; |
38 | }
|
39 | return status; |
40 | }
|
41 | |
42 | |
43 | /*--------------------------------------------------------------------------
|
44 | |
45 | Module Private Functions
|
46 | |
47 | ---------------------------------------------------------------------------*/
|
48 | |
49 | /* Definitions for MMC/SDC command */
|
50 | #define CMD0 (0) /* GO_IDLE_STATE */ |
51 | #define CMD1 (1) /* SEND_OP_COND (MMC) */ |
52 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ |
53 | #define CMD8 (8) /* SEND_IF_COND */ |
54 | #define CMD9 (9) /* SEND_CSD */ |
55 | #define CMD10 (10) /* SEND_CID */ |
56 | #define CMD12 (12) /* STOP_TRANSMISSION */ |
57 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ |
58 | #define CMD16 (16) /* SET_BLOCKLEN */ |
59 | #define CMD17 (17) /* READ_SINGLE_BLOCK */ |
60 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ |
61 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ |
62 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ |
63 | #define CMD24 (24) /* WRITE_BLOCK */ |
64 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ |
65 | #define CMD32 (32) /* ERASE_ER_BLK_START */ |
66 | #define CMD33 (33) /* ERASE_ER_BLK_END */ |
67 | #define CMD38 (38) /* ERASE */ |
68 | #define CMD55 (55) /* APP_CMD */ |
69 | #define CMD58 (58) /* READ_OCR */ |
70 | |
71 | |
72 | static volatile |
73 | DSTATUS Stat = STA_NOINIT; /* Disk status */ |
74 | |
75 | static volatile |
76 | BYTE Timer1, Timer2; /* 100Hz decrement timer */ |
77 | |
78 | static
|
79 | BYTE CardType; /* Card type flags */ |
80 | |
81 | |
82 | /*-----------------------------------------------------------------------*/
|
83 | /* Power Control (Platform dependent) */
|
84 | /*-----------------------------------------------------------------------*/
|
85 | /* When the target system does not support socket power control, there */
|
86 | /* is nothing to do in these functions and chk_power always returns 1. */
|
87 | |
88 | static
|
89 | int power_status (void) /* Socket power state: 0=off, 1=on */ |
90 | {
|
91 | return 1; |
92 | }
|
93 | |
94 | static
|
95 | void power_on (void) |
96 | {
|
97 | /*Nothing to do here, hardware initialization is already done*/
|
98 | return; |
99 | }
|
100 | |
101 | static
|
102 | void power_off (void) |
103 | {
|
104 | /* We do not turn power off*/
|
105 | return; |
106 | }
|
107 | |
108 | |
109 | |
110 | /*-----------------------------------------------------------------------*/
|
111 | /* Transmit/Receive data from/to MMC via SPI (Platform dependent) */
|
112 | /*-----------------------------------------------------------------------*/
|
113 | |
114 | /* Exchange a byte */
|
115 | static
|
116 | BYTE xchg_spi ( /* Returns received data */ |
117 | BYTE dat /* Data to be sent */ |
118 | )
|
119 | {
|
120 | /* Loop while DR register in not empty */
|
121 | while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) |
122 | {
|
123 | }
|
124 | |
125 | /* Send a Byte through the SPI peripheral */
|
126 | SPI_I2S_SendData(SPI2, dat); |
127 | |
128 | /* Wait to receive a Byte */
|
129 | while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) |
130 | {
|
131 | }
|
132 | |
133 | /* Return the Byte read from the SPI bus */
|
134 | return (uint8_t)SPI_I2S_ReceiveData(SPI2); |
135 | }
|
136 | |
137 | |
138 | /*-----------------------------------------------------------------------*/
|
139 | /* Wait for card ready */
|
140 | /*-----------------------------------------------------------------------*/
|
141 | |
142 | static
|
143 | int wait_ready ( /* 1:Ready, 0:Timeout */ |
144 | UINT wt /* Timeout [ms] */ |
145 | )
|
146 | {
|
147 | BYTE d; |
148 | |
149 | |
150 | Timer2 = wt / 10; |
151 | do
|
152 | d = xchg_spi(0xFF); |
153 | while (d != 0xFF && Timer2); |
154 | |
155 | return (d == 0xFF) ? 1 : 0; |
156 | }
|
157 | |
158 | |
159 | |
160 | /*-----------------------------------------------------------------------*/
|
161 | /* Deselect the card and release SPI bus */
|
162 | /*-----------------------------------------------------------------------*/
|
163 | |
164 | static
|
165 | void deselect (void) |
166 | {
|
167 | CS_HIGH(); |
168 | xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */ |
169 | }
|
170 | |
171 | |
172 | |
173 | /*-----------------------------------------------------------------------*/
|
174 | /* Select the card and wait for ready */
|
175 | /*-----------------------------------------------------------------------*/
|
176 | |
177 | static
|
178 | int select (void) /* 1:Successful, 0:Timeout */ |
179 | {
|
180 | CS_LOW(); |
181 | xchg_spi(0xFF); /* Dummy clock (force DO enabled) */ |
182 | |
183 | if (wait_ready(500)) return 1; /* OK */ |
184 | deselect(); |
185 | return 0; /* Timeout */ |
186 | }
|
187 | |
188 | |
189 | |
190 | /*-----------------------------------------------------------------------*/
|
191 | /* Receive a data packet from MMC */
|
192 | /*-----------------------------------------------------------------------*/
|
193 | |
194 | static
|
195 | int rcvr_datablock ( |
196 | BYTE *buff, /* Data buffer to store received data */ |
197 | UINT btr /* Byte count (must be multiple of 4) */ |
198 | )
|
199 | {
|
200 | BYTE token; |
201 | |
202 | |
203 | Timer1 = 20; |
204 | do { /* Wait for data packet in timeout of 200ms */ |
205 | token = xchg_spi(0xFF); |
206 | } while ((token == 0xFF) && Timer1); |
207 | if (token != 0xFE) return 0; /* If not valid data token, retutn with error */ |
208 | |
209 | do
|
210 | {
|
211 | *buff++ =xchg_spi(0xFF); |
212 | *buff++ =xchg_spi(0xFF); |
213 | }while(btr -= 2); |
214 | xchg_spi(0xFF); /* Discard CRC */ |
215 | xchg_spi(0xFF); |
216 | |
217 | return 1; /* Return with success */ |
218 | }
|
219 | |
220 | |
221 | |
222 | /*-----------------------------------------------------------------------*/
|
223 | /* Send a data packet to MMC */
|
224 | /*-----------------------------------------------------------------------*/
|
225 | |
226 | #if _USE_WRITE
|
227 | static
|
228 | int xmit_datablock ( |
229 | const BYTE *buff, /* 512 byte data block to be transmitted */ |
230 | BYTE token /* Data/Stop token */ |
231 | )
|
232 | {
|
233 | BYTE resp; |
234 | uint16_t wc; |
235 | |
236 | if (!wait_ready(500)) return 0; |
237 | |
238 | xchg_spi(token); /* Xmit data token */ |
239 | if (token != 0xFD) { /* Is data token */ |
240 | wc = 512; |
241 | do { /* transmit the 512 byte data block to MMC */ |
242 | xchg_spi(*buff++); |
243 | xchg_spi(*buff++); |
244 | } while (wc-=2); |
245 | xchg_spi(0xFF); /* CRC (Dummy) */ |
246 | xchg_spi(0xFF); |
247 | resp = xchg_spi(0xFF); /* Reveive data response */ |
248 | //debug(USART2, "xchg_spi: %d", resp);
|
249 | if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */ |
250 | return 0; |
251 | }
|
252 | |
253 | return 1; |
254 | }
|
255 | #endif
|
256 | |
257 | |
258 | |
259 | /*-----------------------------------------------------------------------*/
|
260 | /* Send a command packet to MMC */
|
261 | /*-----------------------------------------------------------------------*/
|
262 | |
263 | static
|
264 | BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */ |
265 | BYTE cmd, /* Command index */ |
266 | DWORD arg /* Argument */ |
267 | )
|
268 | {
|
269 | BYTE n, res; |
270 | |
271 | |
272 | if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */ |
273 | cmd &= 0x7F; |
274 | res = send_cmd(CMD55, 0); |
275 | if (res > 1) return res; |
276 | }
|
277 | |
278 | /* Select the card and wait for ready */
|
279 | deselect(); |
280 | if (!select()) return 0xFF; |
281 | |
282 | /* Send command packet */
|
283 | xchg_spi(0x40 | cmd); /* Start + Command index */ |
284 | xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ |
285 | xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ |
286 | xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ |
287 | xchg_spi((BYTE)arg); /* Argument[7..0] */ |
288 | n = 0x01; /* Dummy CRC + Stop */ |
289 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) + Stop */ |
290 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) Stop */ |
291 | xchg_spi(n); |
292 | |
293 | /* Receive command response */
|
294 | if (cmd == CMD12) xchg_spi(0xFF); /* Skip a stuff byte when stop reading */ |
295 | n = 10; /* Wait for a valid response in timeout of 10 attempts */ |
296 | do
|
297 | res = xchg_spi(0xFF); |
298 | while ((res & 0x80) && --n); |
299 | |
300 | return res; /* Return with the response value */ |
301 | }
|
302 | |
303 | |
304 | |
305 | /*--------------------------------------------------------------------------
|
306 | |
307 | Public Functions
|
308 | |
309 | ---------------------------------------------------------------------------*/
|
310 | |
311 | |
312 | /*-----------------------------------------------------------------------*/
|
313 | /* Initialize Disk Drive */
|
314 | /*-----------------------------------------------------------------------*/
|
315 | |
316 | DSTATUS disk_initialize ( |
317 | BYTE pdrv /* Physical drive nmuber (0) */ |
318 | )
|
319 | {
|
320 | BYTE n, cmd, ty, ocr[4]; |
321 | |
322 | |
323 | if (pdrv) return STA_NOINIT; /* Supports only single drive */ |
324 | power_off(); /* Turn off the socket power to reset the card */ |
325 | if (Stat & STA_NODISK) return Stat; /* No card in the socket */ |
326 | power_on(); /* Turn on the socket power */ |
327 | FCLK_SLOW(); |
328 | for (n = 10; n; n--) xchg_spi(0xFF); /* 80 dummy clocks */ |
329 | |
330 | ty = 0; |
331 | if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ |
332 | Timer1 = 100; /* Initialization timeout of 1000 msec */ |
333 | if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ |
334 | debug(USART2, "SDv2\n\r"); |
335 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get trailing return value of R7 resp */ |
336 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ |
337 | while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ |
338 | if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ |
339 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); |
340 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */ |
341 | }
|
342 | }
|
343 | } else { /* SDv1 or MMCv3 */ |
344 | if (send_cmd(ACMD41, 0) <= 1) { |
345 | debug(USART2, "SDv1\n\r"); |
346 | ty = CT_SD1; cmd = ACMD41; /* SDv1 */ |
347 | } else { |
348 | debug(USART2, "MMCv3\n\r"); |
349 | ty = CT_MMC; cmd = CMD1; /* MMCv3 */ |
350 | }
|
351 | while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */ |
352 | if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ |
353 | ty = 0; |
354 | }
|
355 | }
|
356 | CardType = ty; |
357 | deselect(); |
358 | |
359 | if (ty) { /* Initialization succeded */ |
360 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ |
361 | FCLK_FAST(); |
362 | } else { /* Initialization failed */ |
363 | power_off(); |
364 | }
|
365 | |
366 | return Stat; |
367 | }
|
368 | |
369 | |
370 | |
371 | /*-----------------------------------------------------------------------*/
|
372 | /* Get Disk Status */
|
373 | /*-----------------------------------------------------------------------*/
|
374 | |
375 | DSTATUS disk_status ( |
376 | BYTE pdrv /* Physical drive nmuber (0) */ |
377 | )
|
378 | {
|
379 | if (pdrv) return STA_NOINIT; /* Supports only single drive */ |
380 | return Stat; |
381 | }
|
382 | |
383 | |
384 | |
385 | /*-----------------------------------------------------------------------*/
|
386 | /* Read Sector(s) */
|
387 | /*-----------------------------------------------------------------------*/
|
388 | |
389 | DRESULT disk_read ( |
390 | BYTE pdrv, /* Physical drive nmuber (0) */ |
391 | BYTE *buff, /* Pointer to the data buffer to store read data */ |
392 | DWORD sector, /* Start sector number (LBA) */ |
393 | BYTE count /* Sector count (1..255) */ |
394 | )
|
395 | {
|
396 | if (pdrv || !count) return RES_PARERR; |
397 | if (Stat & STA_NOINIT) return RES_NOTRDY; |
398 | |
399 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ |
400 | |
401 | if (count == 1) { /* Single block read */ |
402 | if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */ |
403 | && rcvr_datablock(buff, 512)) |
404 | count = 0; |
405 | }
|
406 | else { /* Multiple block read */ |
407 | if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ |
408 | do { |
409 | if (!rcvr_datablock(buff, 512)) break; |
410 | buff += 512; |
411 | } while (--count); |
412 | send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ |
413 | }
|
414 | }
|
415 | deselect(); |
416 | |
417 | return count ? RES_ERROR : RES_OK; |
418 | }
|
419 | |
420 | |
421 | |
422 | /*-----------------------------------------------------------------------*/
|
423 | /* Write Sector(s) */
|
424 | /*-----------------------------------------------------------------------*/
|
425 | |
426 | #if _USE_WRITE
|
427 | DRESULT disk_write ( |
428 | BYTE pdrv, /* Physical drive nmuber (0) */ |
429 | const BYTE *buff, /* Pointer to the data to be written */ |
430 | DWORD sector, /* Start sector number (LBA) */ |
431 | BYTE count /* Sector count (1..255) */ |
432 | )
|
433 | {
|
434 | if (pdrv || !count) return RES_PARERR; |
435 | if (Stat & STA_NOINIT) return RES_NOTRDY; |
436 | if (Stat & STA_PROTECT) return RES_WRPRT; |
437 | |
438 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ |
439 | |
440 | if (count == 1) { /* Single block write */ |
441 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ |
442 | && xmit_datablock(buff, 0xFE)) |
443 | count = 0; |
444 | }
|
445 | else { /* Multiple block write */ |
446 | if (CardType & CT_SDC) send_cmd(ACMD23, count); |
447 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ |
448 | do { |
449 | if (!xmit_datablock(buff, 0xFC)) break; |
450 | buff += 512; |
451 | } while (--count); |
452 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ |
453 | count = 1; |
454 | }
|
455 | }
|
456 | deselect(); |
457 | |
458 | return count ? RES_ERROR : RES_OK; |
459 | }
|
460 | #endif
|
461 | |
462 | |
463 | /*-----------------------------------------------------------------------*/
|
464 | /* Miscellaneous Functions */
|
465 | /*-----------------------------------------------------------------------*/
|
466 | |
467 | #if _USE_IOCTL
|
468 | DRESULT disk_ioctl ( |
469 | BYTE pdrv, /* Physical drive nmuber (0) */ |
470 | BYTE cmd, /* Control code */ |
471 | void *buff /* Buffer to send/receive control data */ |
472 | )
|
473 | {
|
474 | DRESULT res; |
475 | BYTE n, csd[16], *ptr = buff; |
476 | DWORD *dp, st, ed, csize; |
477 | |
478 | |
479 | if (pdrv) return RES_PARERR; |
480 | |
481 | res = RES_ERROR; |
482 | |
483 | if (cmd == CTRL_POWER) { |
484 | switch (ptr[0]) { |
485 | case 0: /* Sub control code (POWER_OFF) */ |
486 | power_off(); /* Power off */ |
487 | res = RES_OK; |
488 | break; |
489 | case 1: /* Sub control code (POWER_GET) */ |
490 | ptr[1] = (BYTE)power_status(); |
491 | res = RES_OK; |
492 | break; |
493 | default : |
494 | res = RES_PARERR; |
495 | }
|
496 | }
|
497 | else { |
498 | if (Stat & STA_NOINIT) return RES_NOTRDY; |
499 | |
500 | switch (cmd) { |
501 | case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */ |
502 | if (select()) res = RES_OK; |
503 | break; |
504 | |
505 | case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ |
506 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { |
507 | if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ |
508 | csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; |
509 | *(DWORD*)buff = csize << 10; |
510 | } else { /* SDC ver 1.XX or MMC*/ |
511 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; |
512 | csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; |
513 | *(DWORD*)buff = csize << (n - 9); |
514 | }
|
515 | res = RES_OK; |
516 | }
|
517 | break; |
518 | |
519 | case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ |
520 | if (CardType & CT_SD2) { /* SDv2? */ |
521 | if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ |
522 | xchg_spi(0xFF); |
523 | if (rcvr_datablock(csd, 16)) { /* Read partial block */ |
524 | for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */ |
525 | *(DWORD*)buff = 16UL << (csd[10] >> 4); |
526 | res = RES_OK; |
527 | }
|
528 | }
|
529 | } else { /* SDv1 or MMCv3 */ |
530 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ |
531 | if (CardType & CT_SD1) { /* SDv1 */ |
532 | *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); |
533 | } else { /* MMCv3 */ |
534 | *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); |
535 | }
|
536 | res = RES_OK; |
537 | }
|
538 | }
|
539 | break; |
540 | |
541 | /* Following commands are never used by FatFs module */
|
542 | |
543 | case MMC_GET_TYPE : /* Get card type flags (1 byte) */ |
544 | *ptr = CardType; |
545 | res = RES_OK; |
546 | break; |
547 | |
548 | case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ |
549 | if (send_cmd(CMD9, 0) == 0 /* READ_CSD */ |
550 | && rcvr_datablock(ptr, 16)) |
551 | res = RES_OK; |
552 | break; |
553 | |
554 | case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ |
555 | if (send_cmd(CMD10, 0) == 0 /* READ_CID */ |
556 | && rcvr_datablock(ptr, 16)) |
557 | res = RES_OK; |
558 | break; |
559 | |
560 | case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ |
561 | if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ |
562 | for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF); |
563 | res = RES_OK; |
564 | }
|
565 | break; |
566 | |
567 | case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */ |
568 | if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ |
569 | xchg_spi(0xFF); |
570 | if (rcvr_datablock(ptr, 64)) |
571 | res = RES_OK; |
572 | }
|
573 | break; |
574 | |
575 | default:
|
576 | res = RES_PARERR; |
577 | }
|
578 | |
579 | deselect(); |
580 | }
|
581 | |
582 | return res; |
583 | }
|
584 | #endif
|
585 | |
586 | |
587 | /*-----------------------------------------------------------------------*/
|
588 | /* Device Timer Interrupt Procedure */
|
589 | /*-----------------------------------------------------------------------*/
|
590 | /* This function must be called in period of 10ms */
|
591 | |
592 | void disk_timerproc (void) |
593 | {
|
594 | BYTE n, s; |
595 | |
596 | |
597 | n = Timer1; /* 100Hz decrement timer */ |
598 | if (n) Timer1 = --n; |
599 | n = Timer2; |
600 | if (n) Timer2 = --n; |
601 | |
602 | s = Stat; |
603 | |
604 | // if (SOCKWP) /* Write protected */
|
605 | // s |= STA_PROTECT;
|
606 | // else /* Write enabled */
|
607 | // s &= ~STA_PROTECT;
|
608 | |
609 | if (SD_Detect() == SD_PRESENT) /* Card inserted */ |
610 | s &= ~STA_NODISK; |
611 | else /* Socket empty */ |
612 | s |= (STA_NODISK | STA_NOINIT); |
613 | |
614 | Stat = s; /* Update MMC status */ |
615 | }
|
616 | |
617 | |
618 | DWORD get_fattime(void) |
619 | {
|
620 | return 0; |
621 | }
|
Vlt fällt ja jemanden was auf. Danke. Lg Franz
Hallo! Die besagte SD-Karte hat gestern den Geist aufgegeben. D.h sie funktioniert auch nicht mehr mit dem USB-Card Reader. Außerdem sind bei einem Filesystem Check einige Fehler aufgetreten, bevor sie tatsächlich kaputtgegangen ist. Evtl. hing der Fehler damit zusammen. Ich werde dem jedenfalls nicht weiter nachgehen. Vlt kann den Code oben ja trotzdem jmd gebrauchen :) Lg, Franz
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.