1 | /*
|
2 | SDcard.c - functions to read content of an SD card
|
3 | utilizes FATfs (include in project, all but diskio.c, functions are implemented here, just add diskio.h)
|
4 | get it here: http://elm-chan.org/fsw/ff/00index_e.html
|
5 |
|
6 | Created by Damian Schneider, March 29th, 2013.
|
7 |
|
8 | code taken from "ronan" and adapted for CooCox STMf0, original posted here
|
9 | https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Discovery%2FDriver%20to%20use%20MicroSD%20card%20with%20SPI&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=2201
|
10 |
|
11 | also mixed in with some ST-library parts and stuff of my own "until it works".
|
12 | */
|
13 |
|
14 | #include "stm32f0xx_spi.h"
|
15 | #include "stm32f0xx_gpio.h"
|
16 | #include "stm32f0xx_rcc.h"
|
17 | #include "stm32f0xx.h"
|
18 | #include "ffconf.h"
|
19 | #include "ff.h"
|
20 | #include "xprintf.h"
|
21 | #include "string.h"
|
22 | #include "diskio.h"
|
23 |
|
24 |
|
25 |
|
26 | /* SPIx Communication boards Interface */
|
27 | #define GPIO_AF_SPI2 GPIO_AF_0
|
28 | #define SPIx_SD SPI2
|
29 | #define SPIx_SD_CLK RCC_APB1Periph_SPI2
|
30 | #define SPIx_SD_CLK_INIT RCC_APB1PeriphClockCmd
|
31 | #define SPIx_SD_IRQn SPI2_IRQn
|
32 | #define SPIx_SD_IRQHANDLER SPI2_IRQHandler
|
33 |
|
34 | #define SPIx_SD_SCK_PIN GPIO_Pin_13
|
35 | #define SPIx_SD_SCK_GPIO_PORT GPIOB
|
36 | #define SPIx_SD_SCK_GPIO_CLK RCC_AHBPeriph_GPIOB
|
37 | #define SPIx_SD_SCK_SOURCE GPIO_PinSource13
|
38 | #define SPIx_SD_SCK_AF GPIO_AF_SPI2
|
39 |
|
40 | #define SPIx_SD_MISO_PIN GPIO_Pin_14
|
41 | #define SPIx_SD_MISO_GPIO_PORT GPIOB
|
42 | #define SPIx_SD_MISO_GPIO_CLK RCC_AHBPeriph_GPIOB
|
43 | #define SPIx_SD_MISO_SOURCE GPIO_PinSource14
|
44 | #define SPIx_SD_MISO_AF GPIO_AF_SPI2
|
45 |
|
46 | #define SPIx_SD_MOSI_PIN GPIO_Pin_15
|
47 | #define SPIx_SD_MOSI_GPIO_PORT GPIOB
|
48 | #define SPIx_SD_MOSI_GPIO_CLK RCC_AHBPeriph_GPIOB
|
49 | #define SPIx_SD_MOSI_SOURCE GPIO_PinSource15
|
50 | #define SPIx_SD_MOSI_AF GPIO_AF_SPI2
|
51 |
|
52 | #define SPIx_SD_NSS_PIN GPIO_Pin_12
|
53 | #define SPIx_SD_NSS_GPIO_PORT GPIOB
|
54 | #define SPIx_SD_NSS_GPIO_CLK RCC_AHBPeriph_GPIOB
|
55 | #define SPIx_SD_NSS_SOURCE GPIO_PinSource12
|
56 | #define SPIx_SD_NSS_AF GPIO_AF_SPI2
|
57 |
|
58 | #define SPIx_SD_BAUDRATE_SLOW SPI_BaudRatePrescaler_128
|
59 | #define SPIx_SD_BAUDRATE_FAST SPI_BaudRatePrescaler_2
|
60 |
|
61 | /* Definitions for SDC command --------------------------------------------*/
|
62 | #define CMD0 (0x40+0) /* GO_IDLE_STATE */
|
63 | #define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
|
64 | #define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
|
65 | #define CMD8 (0x40+8) /* SEND_IF_COND */
|
66 | #define CMD9 (0x40+9) /* SEND_CSD */
|
67 | #define CMD10 (0x40+10) /* SEND_CID */
|
68 | #define CMD12 (0x40+12) /* STOP_TRANSMISSION */
|
69 | #define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
|
70 | #define CMD16 (0x40+16) /* SET_BLOCKLEN */
|
71 | #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
|
72 | #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
|
73 | #define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
|
74 | #define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
75 | #define CMD24 (0x40+24) /* WRITE_BLOCK */
|
76 | #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
|
77 | #define CMD55 (0x40+55) /* APP_CMD */
|
78 | #define CMD58 (0x40+58) /* READ_OCR */
|
79 |
|
80 | /* Definitions for card type --------------------------------------------*/
|
81 | #define SD2_BYTE 0x04 /* SD Ver.2 (Byte address) */
|
82 | #define SD2_BLOCK 0x0C /* SD Ver.2 (Block address) */
|
83 |
|
84 | //pin select
|
85 | #define SDSELECT() GPIOB->BRR = (1<<12) //pin low, MMC CS = L
|
86 | #define SDDESELECT() GPIOB->BSRR = (1<<12) //pin high,MMC CS = H
|
87 | /*--------------------------------------------------------------------------
|
88 |
|
89 | Module Private Functions and Variables
|
90 |
|
91 | ---------------------------------------------------------------------------*/
|
92 |
|
93 | static const uint32_t socket_state_mask_cp = (1 << 0);
|
94 | static const uint32_t socket_state_mask_wp = (1 << 1);
|
95 |
|
96 | static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
|
97 | static volatile uint32_t Timer1, Timer2; /* 100Hz decrement timers */
|
98 | static uint8_t CardType; /* Card type flags */
|
99 |
|
100 | enum speed_setting {
|
101 | INTERFACE_SLOW, INTERFACE_FAST
|
102 | };
|
103 |
|
104 | /*-----------------------------------------------------------------------*/
|
105 | /* @descr INTERFACE SPEED */
|
106 | /* @param speed INTERFACE_SLOW OR INTERFACE_FAST */
|
107 | /* @retval none */
|
108 | /*-----------------------------------------------------------------------*/
|
109 | static void interface_speed(enum speed_setting speed) {
|
110 | uint32_t tmp;
|
111 |
|
112 | /* Lecture du registre CR1 ------------------------------- */
|
113 | tmp = SPIx_SD->CR1;
|
114 |
|
115 | /* Test la configuration --- ----------------------------- */
|
116 | if (speed == INTERFACE_SLOW) {
|
117 | /* Set slow clock (100k-400k) ------------------------ */
|
118 | tmp = (tmp | SPIx_SD_BAUDRATE_SLOW);
|
119 | } else {
|
120 | /* Set fast clock (depends on the CSD) --------------- */
|
121 | tmp = (tmp & ~SPIx_SD_BAUDRATE_SLOW) | SPIx_SD_BAUDRATE_FAST;
|
122 | }
|
123 |
|
124 | /* Ecriture de la nouvelle config. sur le registre CR1 --- */
|
125 | SPIx_SD->CR1 = tmp;
|
126 | }
|
127 |
|
128 | /*-----------------------------------------------------------------------*/
|
129 | /* @descr TRANSMIT & RECEIVE BYTE via SPI */
|
130 | /* @param out octet à transemttre */
|
131 | /* @retval stm32_spi_rw octet reçu */
|
132 | /*-----------------------------------------------------------------------*/
|
133 | uint8_t stm32_spi_rw(uint8_t out) {
|
134 |
|
135 | /*!< Wait until the transmit buffer is empty */
|
136 | while (SPI_I2S_GetFlagStatus(SPIx_SD, SPI_I2S_FLAG_TXE) == RESET) {
|
137 | }
|
138 |
|
139 | /*!< Send the byte */
|
140 | SPI_SendData8(SPIx_SD, out);
|
141 |
|
142 | /*!< Wait to receive a byte*/
|
143 | while (SPI_I2S_GetFlagStatus(SPIx_SD, SPI_I2S_FLAG_RXNE) == RESET) {
|
144 | }
|
145 |
|
146 | /*!< Return the byte read from the SPI bus */
|
147 | return SPI_ReceiveData8(SPIx_SD);
|
148 |
|
149 | }
|
150 |
|
151 | /*-----------------------------------------------------------------------*/
|
152 | /* @descr RECEIVE A BYTE via SPI */
|
153 | /* @param None */
|
154 | /* @retval rcvr_spi octet reçu */
|
155 | /*-----------------------------------------------------------------------*/
|
156 | uint8_t rcvr_spi(void) {
|
157 | uint8_t Data = 0;
|
158 |
|
159 | /*!< Wait until the transmit buffer is empty */
|
160 | while (SPI_I2S_GetFlagStatus(SPIx_SD, SPI_I2S_FLAG_TXE) == RESET) {
|
161 | }
|
162 | /*!< Send the byte */
|
163 | SPI_SendData8(SPIx_SD, 0xFF);
|
164 |
|
165 | /*!< Wait until a data is received */
|
166 | while (SPI_I2S_GetFlagStatus(SPIx_SD, SPI_I2S_FLAG_RXNE) == RESET) {
|
167 | }
|
168 | /*!< Get the received data */
|
169 | Data = SPI_ReceiveData8(SPIx_SD);
|
170 |
|
171 | /*!< Return the shifted data */
|
172 | return Data;
|
173 | }
|
174 |
|
175 | /* Alternative macro to receive data fast */
|
176 | #define rcvr_spi_m(dst) *(dst)=stm32_spi_rw(0xff)
|
177 |
|
178 | /*-----------------------------------------------------------------------*/
|
179 | /* @descr Wait for card ready */
|
180 | /* @param None */
|
181 | /* @retval wait_ready octet reçu */
|
182 | /*-----------------------------------------------------------------------*/
|
183 | static uint8_t wait_ready(void) {
|
184 | uint8_t res;
|
185 | uint16_t timeout = 100; //try 100 times max.
|
186 | //Timer2 = 50; /* Wait for ready in timeout of 500ms */
|
187 | rcvr_spi();
|
188 |
|
189 | do {
|
190 | res = rcvr_spi();
|
191 | } while ((res != 0xFF && timeout--)); // && Timer2);
|
192 |
|
193 | return res;
|
194 | }
|
195 |
|
196 | /*-----------------------------------------------------------------------*/
|
197 | /* @descr Deselect the card and release SPI bus */
|
198 | /* @param None */
|
199 | /* @retval None */
|
200 | /*-----------------------------------------------------------------------*/
|
201 | static void release_spi(void) {
|
202 |
|
203 | SDDESELECT();
|
204 | rcvr_spi();
|
205 | }
|
206 |
|
207 | /*-----------------------------------------------------------------------*/
|
208 | /* @descr Power Control and interface-initialization */
|
209 | /* @param None */
|
210 | /* @retval None */
|
211 | /*-----------------------------------------------------------------------*/
|
212 | static void power_on(void) {
|
213 |
|
214 | SPI_InitTypeDef SPI_InitStructure;
|
215 | GPIO_InitTypeDef GPIO_InitStructure;
|
216 |
|
217 | /* Enable GPIO clocks */
|
218 | RCC_AHBPeriphClockCmd(
|
219 | SPIx_SD_SCK_GPIO_CLK | SPIx_SD_MISO_GPIO_CLK | SPIx_SD_MOSI_GPIO_CLK
|
220 | | SPIx_SD_NSS_GPIO_CLK, ENABLE);
|
221 |
|
222 | /* Enable the SPI clock */SPIx_SD_CLK_INIT(SPIx_SD_CLK, ENABLE);
|
223 |
|
224 | /* SPI GPIO Configuration --------------------------------------------------*/
|
225 |
|
226 | /* Configure I/O for Flash Chip select */
|
227 | GPIO_InitStructure.GPIO_Pin = SPIx_SD_NSS_PIN;
|
228 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
229 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
230 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
231 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
232 | GPIO_Init(SPIx_SD_NSS_GPIO_PORT, &GPIO_InitStructure);
|
233 |
|
234 | /* SPI SCK pin configuration */
|
235 | GPIO_InitStructure.GPIO_Pin = SPIx_SD_SCK_PIN;
|
236 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
237 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
238 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
239 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
240 | GPIO_Init(SPIx_SD_SCK_GPIO_PORT, &GPIO_InitStructure);
|
241 |
|
242 | /* SPI MOSI pin configuration */
|
243 | GPIO_InitStructure.GPIO_Pin = SPIx_SD_MOSI_PIN;
|
244 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
245 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
246 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
247 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
248 | GPIO_Init(SPIx_SD_MOSI_GPIO_PORT, &GPIO_InitStructure);
|
249 |
|
250 | /* SPI MISO pin configuration */
|
251 | GPIO_InitStructure.GPIO_Pin = SPIx_SD_MISO_PIN;
|
252 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
253 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
254 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
255 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
256 | GPIO_Init(SPIx_SD_MISO_GPIO_PORT, &GPIO_InitStructure);
|
257 |
|
258 | /* Connect SPI pins to AF0 */
|
259 | GPIO_PinAFConfig(SPIx_SD_SCK_GPIO_PORT, SPIx_SD_SCK_SOURCE, SPIx_SD_SCK_AF);
|
260 | GPIO_PinAFConfig(SPIx_SD_MOSI_GPIO_PORT, SPIx_SD_MOSI_SOURCE,
|
261 | SPIx_SD_MOSI_AF);
|
262 | GPIO_PinAFConfig(SPIx_SD_MISO_GPIO_PORT, SPIx_SD_MISO_SOURCE,
|
263 | SPIx_SD_MOSI_AF);
|
264 |
|
265 | /* SPI configuration */
|
266 | SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
267 | SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
|
268 | SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
|
269 | SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
|
270 | SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
|
271 | SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
|
272 | SPI_InitStructure.SPI_BaudRatePrescaler = SPIx_SD_BAUDRATE_SLOW; // 42000kHz/128=328kHz < 400kHz
|
273 | SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
|
274 | SPI_InitStructure.SPI_CRCPolynomial = 7;
|
275 |
|
276 | SPI_Init(SPIx_SD, &SPI_InitStructure);
|
277 | SPI_RxFIFOThresholdConfig(SPIx_SD, SPI_RxFIFOThreshold_QF);
|
278 |
|
279 | SPI_CalculateCRC(SPIx_SD, DISABLE);
|
280 | SPI_Cmd(SPIx_SD, ENABLE);
|
281 |
|
282 | /* drain SPI TX buffer,just in case*/
|
283 | while (SPI_I2S_GetFlagStatus(SPIx_SD, SPI_I2S_FLAG_TXE) == RESET) {
|
284 | ;
|
285 | }
|
286 | SPI_ReceiveData8(SPIx_SD);
|
287 |
|
288 | /* De-select the Card: Chip Select high */
|
289 | SDDESELECT();
|
290 |
|
291 | /*
|
292 | //DMA setup, in case dma is ever needed, code snipped, not working
|
293 | DMA_StructInit(&DMA_InitStructure);
|
294 | RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
295 | // reset DMA configuration
|
296 |
|
297 | //configure DMA
|
298 | DMA_InitStructure.DMA_MemoryBaseAddr = 0;
|
299 | DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(SPI2->DR);
|
300 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
301 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
302 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
303 | DMA_InitStructure.DMA_BufferSize = 1;
|
304 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
305 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
306 | DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
307 | DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
308 | DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
309 | DMA_Init(SPI_PORT_TX_DMA_STREAM, &DMA_InitStructure);
|
310 |
|
311 | // Enable the DMA transfer complete interrupt
|
312 | DMA_ITConfig(SPI_PORT_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
|
313 |
|
314 | // Enable SPI dma tx request.
|
315 | SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
|
316 |
|
317 | // Enable the interrupt in the NVIC
|
318 | NVIC_InitStructure.NVIC_IRQChannel = SPI_PORT_DMA_TX_IRQn;
|
319 | NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
|
320 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
321 | NVIC_Init(&NVIC_InitStructure);
|
322 | */
|
323 |
|
324 | }
|
325 |
|
326 | /*-----------------------------------------------------------------------*/
|
327 | /* @descr Power Off */
|
328 | /* @param None */
|
329 | /* @retval None */
|
330 | /*-----------------------------------------------------------------------*/
|
331 | static void power_off(void) {
|
332 |
|
333 | GPIO_InitTypeDef GPIO_InitStructure;
|
334 |
|
335 | if (!(Stat & STA_NOINIT)) {
|
336 | SDSELECT();
|
337 | wait_ready();
|
338 | release_spi();
|
339 | }
|
340 |
|
341 | SPI_I2S_DeInit(SPIx_SD);
|
342 | SPI_Cmd(SPIx_SD, DISABLE);
|
343 | SPIx_SD_CLK_INIT(SPIx_SD_CLK, DISABLE);
|
344 |
|
345 | /* All SPI-Pins to input with weak internal pull-downs */
|
346 | GPIO_InitStructure.GPIO_Pin = SPIx_SD_SCK_PIN | SPIx_SD_MISO_PIN
|
347 | | SPIx_SD_MOSI_PIN;
|
348 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
|
349 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
|
350 | GPIO_Init(SPIx_SD_SCK_GPIO_PORT, &GPIO_InitStructure);
|
351 |
|
352 | Stat |= STA_NOINIT; /* Set STA_NOINIT */
|
353 |
|
354 | }
|
355 |
|
356 | /*-----------------------------------------------------------------------*/
|
357 | /* @descr Receive a data packet from MMC */
|
358 | /* @param *buff Data buffer to store received data */
|
359 | /* @param btr Byte count (must be multiple of 4) */
|
360 | /* @retval None */
|
361 | /*-----------------------------------------------------------------------*/
|
362 | static uint8_t rcvr_datablock(uint8_t *buff, uint16_t btr) {
|
363 | uint8_t token;
|
364 |
|
365 | Timer1 = 10;
|
366 | do { /* Wait for data packet in timeout of 100ms */
|
367 | token = rcvr_spi();
|
368 | } while ((token == 0xFF) && Timer1);
|
369 |
|
370 | if (token != 0xFE)
|
371 | return 0; /* If not valid data token, return with error */
|
372 |
|
373 | do { /* Receive the data block into buffer */
|
374 | rcvr_spi_m(buff++);
|
375 | rcvr_spi_m(buff++);
|
376 | rcvr_spi_m(buff++);
|
377 | rcvr_spi_m(buff++);
|
378 | } while (btr -= 4);
|
379 |
|
380 | rcvr_spi(); /* Discard CRC */
|
381 | rcvr_spi();
|
382 |
|
383 | return 1; /* Return with success */
|
384 | }
|
385 |
|
386 | /*-----------------------------------------------------------------------*/
|
387 | /* @descr end a data packet to MMC */
|
388 | /* @param *buff 512 byte data block to be transmitted */
|
389 | /* @param token Data/Stop token */
|
390 | /* @retval None */
|
391 | /*-----------------------------------------------------------------------*/
|
392 | static uint8_t xmit_datablock(const uint8_t *buff, uint8_t token) {
|
393 | uint8_t resp;
|
394 | uint8_t wc;
|
395 |
|
396 | if (wait_ready() != 0xFF)
|
397 | return 0;
|
398 | stm32_spi_rw(token); /* transmit data token */
|
399 | if (token != 0xFD) { /* Is data token */
|
400 |
|
401 | wc = 0;
|
402 | do { /* transmit the 512 byte data block to MMC */
|
403 | stm32_spi_rw(*buff++);
|
404 | stm32_spi_rw(*buff++);
|
405 | } while (--wc);
|
406 |
|
407 | stm32_spi_rw(0xFF); /* CRC (Dummy) */
|
408 | stm32_spi_rw(0xFF);
|
409 | resp = rcvr_spi(); /* Receive data response */
|
410 | if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
411 | return 0;
|
412 | }
|
413 |
|
414 | return 1;
|
415 | }
|
416 |
|
417 | /*-----------------------------------------------------------------------*/
|
418 | /* @descr SEND A COMMAND PACKET (6 BYTES) */
|
419 | /* @param cmd Command byte */
|
420 | /* @param arg Argument */
|
421 | /* @retval None */
|
422 | /*-----------------------------------------------------------------------*/
|
423 | static uint8_t send_cmd(uint8_t cmd, uint32_t arg) {
|
424 |
|
425 | /* Declaration des variables ----------------------------- */
|
426 | uint8_t n, res;
|
427 |
|
428 | /* Test si c'est cmd ACDM -------------------------------- */
|
429 | if (cmd & 0x80) {
|
430 | cmd &= 0x7F;
|
431 | res = send_cmd(CMD55, 0); // envoie de la CMD55
|
432 | if (res > 1)
|
433 | return res;
|
434 | }
|
435 |
|
436 | /* Select the card --------------------------------------- */
|
437 | // SDDESELECT();
|
438 | SDSELECT();
|
439 |
|
440 | /* wait for ready ---------------------------------------- */
|
441 | if (wait_ready() != 0xFF) {
|
442 | return 0xFF;
|
443 | }
|
444 |
|
445 | /* Send command packet ----------------------------------- */
|
446 | stm32_spi_rw(cmd); // Send command index
|
447 |
|
448 | stm32_spi_rw((uint8_t)(arg >> 24)); // Send argument[31..24]
|
449 | stm32_spi_rw((uint8_t)(arg >> 16)); // Send argument[23..16]
|
450 | stm32_spi_rw((uint8_t)(arg >> 8)); // Send argument[15..8]
|
451 | stm32_spi_rw((uint8_t) arg); // Send argument[7..0]
|
452 |
|
453 | n = 0x01; // Stop : Dummy CRC
|
454 | if (cmd == CMD0)
|
455 | n = 0x95; // Valid CRC for CMD0(0)
|
456 | if (cmd == CMD8)
|
457 | n = 0x87; // Valid CRC for CMD8(0x1AA)
|
458 | stm32_spi_rw(n); // Send CRC
|
459 |
|
460 | /* Receive command response ------------------------------ */
|
461 | if (cmd == CMD12)
|
462 | rcvr_spi(); // Skip a stuff byte when stop reading
|
463 |
|
464 | /* Wait for a valid response in timeout of 10 attempts --- */
|
465 | n = 10;
|
466 | do
|
467 | res = rcvr_spi();
|
468 | while ((res & 0x80) && --n);
|
469 |
|
470 | /* Return with the response value ------------------------ */
|
471 | return res;
|
472 | }
|
473 |
|
474 | /*-----------------------------------------------------------------------*/
|
475 | /* @descr INITIALIZE DISK DRIVE */
|
476 | /* @param drv Physical drive numbre (0) */
|
477 | /* @retval DSTATUS Status of Disk Functions (BYTE) */
|
478 | /*-----------------------------------------------------------------------*/
|
479 | DSTATUS disk_initialize(uint8_t drv) {
|
480 |
|
481 | /* Declaration des variables ----------------------------- */
|
482 | uint8_t i, ocr[4], SDType;
|
483 |
|
484 | /* Supports only single drive ---------------------------- */
|
485 | if (drv)
|
486 | return STA_NOINIT;
|
487 |
|
488 | /* No card in the socket --------------------------------- */
|
489 | if (Stat & STA_NODISK)
|
490 | return Stat;
|
491 |
|
492 | /* Configure les broches & alimente la carte si necessaire */
|
493 | power_on();
|
494 |
|
495 | SDDESELECT();
|
496 |
|
497 | /* 80 dummy clocks --------------------------------------- */
|
498 | for (i = 10; i; i--) {
|
499 | stm32_spi_rw(0xff);
|
500 | }
|
501 |
|
502 | /* Initialise SDType ------------------------------------- */
|
503 | SDType = 0;
|
504 |
|
505 | /* Initialise la SDCard en mode SPI ---------------------- */
|
506 | if (send_cmd(CMD0, 0) == 1) {
|
507 |
|
508 | /* Verifie les conditions (tension,...) -------------- */
|
509 | if (send_cmd(CMD8, 0x1AA) == 1) {
|
510 | /* lecture des trames de réponses ---------------- */
|
511 | for (i = 0; i < 4; i++)
|
512 | ocr[i] = rcvr_spi();
|
513 |
|
514 | /* Verifie les tensions autorisées --------------- */
|
515 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
|
516 | /* Attend de quitter l'état repos ------------ */
|
517 | while (send_cmd(ACMD41, 0x40000000))
|
518 | ;
|
519 |
|
520 | /* Envoie de la commande OCR ----------------- */
|
521 | if (send_cmd(CMD58, 0) == 0) {
|
522 | for (i = 0; i < 4; i++)
|
523 | ocr[i] = rcvr_spi();
|
524 |
|
525 | /* Control bit CCS dans le registre OCR -- */
|
526 | if (ocr[0] & 0x40) {
|
527 | SDType = SD2_BLOCK;
|
528 |
|
529 | } else {
|
530 | SDType = SD2_BYTE;
|
531 |
|
532 | }
|
533 | }
|
534 | }
|
535 | }
|
536 | }
|
537 |
|
538 | /* Erreur d'initialisation ------------------------------- */
|
539 | else {
|
540 | SDType = 0;
|
541 | }
|
542 |
|
543 | /* Deselectionne la liaison SPI -------------------------- */
|
544 | release_spi();
|
545 |
|
546 | /* Affecte le type de la carte a CardType ---------------- */
|
547 | CardType = SDType;
|
548 |
|
549 | /* Test si l'initialisation est valide ------------------- */
|
550 | if (SDType) {
|
551 | /* Initialization succeeded -------------------------- */
|
552 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
553 | interface_speed(INTERFACE_FAST);
|
554 | LED_ON;
|
555 |
|
556 | } else {
|
557 | /* Initialization failed ----------------------------- */
|
558 | power_off();
|
559 | }
|
560 |
|
561 | return Stat;
|
562 |
|
563 | }
|
564 |
|
565 | /*-----------------------------------------------------------------------*/
|
566 | /* @descr GET DISK STATUS */
|
567 | /* @param drv Physical drive numbre (0) */
|
568 | /* @retval DSTATUS Status of Disk Functions (BYTE) */
|
569 | /*-----------------------------------------------------------------------*/
|
570 | DSTATUS disk_status(uint8_t drv) {
|
571 | if (drv)
|
572 | return STA_NOINIT; /* Supports only single drive */
|
573 | return Stat;
|
574 | }
|
575 |
|
576 | /*-----------------------------------------------------------------------*/
|
577 | /* @descr READ SECTOR(S) */
|
578 | /* @param drv Physical drive numbre (0) */
|
579 | /* @param *buff Pointer to the data buffer to store read data */
|
580 | /* @param sector Start sector number (LBA) */
|
581 | /* @param count Sector count (1..255) */
|
582 | /* @retval DRESULT Results of Disk Functions */
|
583 | /*-----------------------------------------------------------------------*/
|
584 | DRESULT disk_read(uint8_t drv, uint8_t *buff, uint32_t sector, uint8_t count) {
|
585 | /* Check parameters -------------------------------------- */
|
586 | if (drv || !count)
|
587 | return RES_PARERR;
|
588 | if (Stat & STA_NOINIT)
|
589 | return RES_NOTRDY;
|
590 |
|
591 | /* Convert to byte address if needed --------------------- */
|
592 | if (!(CardType & CT_BLOCK))
|
593 | sector *= 512;
|
594 |
|
595 | /* Test : Single or Multiple block read ------------------ */
|
596 | if (count == 1) {
|
597 | /* Single block read */
|
598 | if (send_cmd(CMD17, sector) == 0) {
|
599 | /* READ_SINGLE_BLOCK */
|
600 | if (rcvr_datablock(buff, 512)) {
|
601 | count = 0;
|
602 | }
|
603 | }
|
604 | } else {
|
605 | /* Multiple block read */
|
606 | if (send_cmd(CMD18, sector) == 0) {
|
607 | /* READ_MULTIPLE_BLOCK */
|
608 | do {
|
609 | if (!rcvr_datablock(buff, 512)) {
|
610 | break;
|
611 | }
|
612 | buff += 512;
|
613 | } while (--count);
|
614 |
|
615 | /* STOP_TRANSMISSION */
|
616 | send_cmd(CMD12, 0);
|
617 | }
|
618 | }
|
619 | release_spi();
|
620 |
|
621 | return count ? RES_ERROR : RES_OK;
|
622 | }
|
623 |
|
624 | /*-----------------------------------------------------------------------*/
|
625 | /* @descr WRITE SECTOR(S) */
|
626 | /* @param drv Physical drive numbre (0) */
|
627 | /* @param *buff Pointer to the data to be written */
|
628 | /* @param sector Start sector number (LBA) */
|
629 | /* @param count Sector count (1..255) */
|
630 | /* @retval DRESULT Results of Disk Functions */
|
631 | /*-----------------------------------------------------------------------*/
|
632 | DRESULT disk_write(uint8_t drv, const uint8_t *buff, uint32_t sector,
|
633 | uint8_t count) {
|
634 | /* Check parameters -------------------------------------- */
|
635 | if (drv || !count)
|
636 | return RES_PARERR;
|
637 | if (Stat & STA_NOINIT)
|
638 | return RES_NOTRDY;
|
639 | if (Stat & STA_PROTECT)
|
640 | return RES_WRPRT;
|
641 |
|
642 | /* Convert to byte address if needed --------------------- */
|
643 | if (!(CardType & CT_BLOCK))
|
644 | sector *= 512;
|
645 |
|
646 | /* Test : Single or Multiple block write ----------------- */
|
647 | if (count == 1) {
|
648 | /* Single block write -------------------------------- */
|
649 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
650 | && xmit_datablock(buff, 0xFE))
|
651 | count = 0;
|
652 | } else {
|
653 | /* Multiple block write */
|
654 | if (CardType & CT_SDC)
|
655 | send_cmd(ACMD23, count);
|
656 | if (send_cmd(CMD25, sector) == 0) {
|
657 | /* WRITE_MULTIPLE_BLOCK */
|
658 | do {
|
659 | if (!xmit_datablock(buff, 0xFC))
|
660 | break;
|
661 | buff += 512;
|
662 | } while (--count);
|
663 |
|
664 | /* STOP_TRAN token */
|
665 | if (!xmit_datablock(0, 0xFD))
|
666 | count = 1;
|
667 | }
|
668 | }
|
669 | release_spi();
|
670 |
|
671 | return count ? RES_ERROR : RES_OK;
|
672 | }
|
673 |
|
674 | /*-----------------------------------------------------------------------*/
|
675 | /* @descr GET CURRENT TIME INTO A uint32_t VALUE */
|
676 | /* @param drv Physical drive number (0) */
|
677 | /* @param ctrl Control code */
|
678 | /* @param *buff Buffer to send/receive control data */
|
679 | /* @param DRESULT Results of Disk Functions */
|
680 | /*-----------------------------------------------------------------------*/
|
681 | DRESULT disk_ioctl(uint8_t drv, uint8_t ctrl, void *buff) {
|
682 | DRESULT res;
|
683 |
|
684 | res = RES_OK;
|
685 |
|
686 | return res;
|
687 | }
|
688 |
|
689 | /*-----------------------------------------------------------------------*/
|
690 | /* @descr GET CURRENT TIME INTO A uint32_t VALUE , used in FATfs */
|
691 | /* @param none */
|
692 | /* @retval uint32_t Results of Disk Functions */
|
693 | /*-----------------------------------------------------------------------*/
|
694 | uint32_t get_fattime(void) {
|
695 | uint32_t res;
|
696 | res = 42; //dummy time and date, RTC to be implemented
|
697 | /*
|
698 | RTC_TimeTypeDef RTC_TimeStructure;
|
699 | RTC_DateTypeDef RTC_DateStructure;
|
700 |
|
701 | RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
|
702 | RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
|
703 |
|
704 | res = (((uint32_t)RTC_DateStructure.RTC_Year + 20) << 25) // bit31:25 Year from 1980 (0..127)
|
705 | | ((uint32_t)RTC_DateStructure.RTC_Month << 21) // bit24:21 Month (1..12)
|
706 | | ((uint32_t)RTC_DateStructure.RTC_Date << 16) // bit20:16 Day in month(1..31)
|
707 | | (uint16_t)(RTC_TimeStructure.RTC_Hours << 11) // bit15:11 Hour (0..23)
|
708 | | (uint16_t)(RTC_TimeStructure.RTC_Minutes << 5) // bit10:5 Minute (0..59)
|
709 | | (uint16_t)(RTC_TimeStructure.RTC_Seconds >> 1); // bit4:0 Second / 2 (0..29)
|
710 | */
|
711 |
|
712 | return res;
|
713 | }
|
714 |
|
715 |
|
716 | /*
|
717 | scan_files() function is an example from the FatFS library.
|
718 | if called with empty string as a path, it prints out all files on the card.
|
719 | */
|
720 |
|
721 | FRESULT scan_files(char* path) {
|
722 | FRESULT res;
|
723 | FILINFO fno;
|
724 | DIR dir;
|
725 | int i;
|
726 | char *fn; /* This function is assuming non-Unicode cfg. */
|
727 | #if _USE_LFN
|
728 | static char lfn[_MAX_LFN + 1];
|
729 | fno.lfname = lfn;
|
730 | fno.lfsize = sizeof lfn;
|
731 | #endif
|
732 |
|
733 | res = f_opendir(&dir, path); /* Open the directory */
|
734 | if (res == FR_OK) {
|
735 | i = strlen(path);
|
736 | for (;;) {
|
737 | xprintf("scan...");
|
738 | res = f_readdir(&dir, &fno); /* Read a directory item */
|
739 | if (res != FR_OK || (fno.fname[0] == 0))
|
740 | break; /* Break on error or end of dir */
|
741 | if (fno.fname[0] == '.')
|
742 | continue; /* Ignore dot entry */
|
743 | xprintf("file found\r\n");
|
744 | #if _USE_LFN
|
745 | fn = *fno.lfname ? fno.lfname : fno.fname;
|
746 | #else
|
747 | fn = fno.fname;
|
748 | #endif
|
749 | if (fno.fattrib & AM_DIR) { /* It is a directory */
|
750 | xsprintf(&path[i], "/%s", fn);
|
751 | res = scan_files(path);
|
752 | if (res != FR_OK)
|
753 | break;
|
754 | path[i] = 0;
|
755 | } else { /* It is a file. */
|
756 | xprintf("%s/%s\n", path, fn);
|
757 | }
|
758 | }
|
759 | }
|
760 |
|
761 | return res;
|
762 | }
|
763 |
|
764 |
|
765 | /*
|
766 | *
|
767 | * basic function test for debugging
|
768 | *
|
769 | */
|
770 | void SDtest(void) {
|
771 |
|
772 | FILINFO Finfo; /* Work register for fs command */
|
773 | FATFS Fatfs; //to mount the sd card
|
774 | DIR Dir; //current directory
|
775 | uint8_t res;
|
776 |
|
777 | // disk_initialize(0);//done when calling mount
|
778 |
|
779 | xprintf("mounting SD card: \r\n");
|
780 |
|
781 | /* Mount Fatfs Drive */
|
782 | f_mount(0, &Fatfs);
|
783 |
|
784 | const char newline[] = "\r\n";
|
785 | const char nullstring[] = "";
|
786 |
|
787 | if (f_opendir(&Dir, (const char*) nullstring) == FR_OK) {
|
788 |
|
789 | xprintf("root dir opened\r\n");
|
790 |
|
791 | while (((res = f_readdir(&Dir, &Finfo)) == FR_OK) && Finfo.fname[0]) {
|
792 | // xprintf("reading directory... ");
|
793 | // xprintf(Finfo.fname);
|
794 | // xprintf(newline);
|
795 | uint8_t i = 0;
|
796 | while (Finfo.fname[i] && Finfo.fname[i + 2]) //scan file name
|
797 | {
|
798 | if (Finfo.fname[i] == 'B' || Finfo.fname[i] == 'b') {
|
799 | if (Finfo.fname[i + 1] == 'M'
|
800 | || Finfo.fname[i + 1] == 'm') {
|
801 | if (Finfo.fname[i + 2] == 'P'
|
802 | || Finfo.fname[i + 2] == 'p') {
|
803 | //xprintf("BMP found! name: ");
|
804 | xprintf(Finfo.fname);
|
805 | xprintf(newline);
|
806 | showimage((char*) Finfo.fname); //display image
|
807 | break;
|
808 | }
|
809 | }
|
810 | }
|
811 | i++;
|
812 | }
|
813 |
|
814 | }
|
815 | }
|
816 |
|
817 | }
|