Forum: Projekte & Code SPI interface zu SD karte für STM32F0


von D. S. (schnitzgi)


Lesenswert?

Nachdem ich nun fast ein tag damit verbraten hab, das ding zum laufen zu 
kriegen, will ich das nun funktionierende resultat hier teilen. Hab 
nirgends eine vernünftige Lösung online gefunden, das Beispiel von ST 
war nicht für den CortexM0 verfügbar und ausserdem schwer zu finden.

Codebeschreibung:
-Ansteuerung einer (micro) SD karte über SPI2 (portB, pins 12-15)
-inkl. commands für die SD karte
-Codegerüst zur Einbindung von FatFs für's Filesystem
-Demo-debug funktion für erste Schritte mit FatFs

einfach in deinem Projekt die header files einbinden. Voraussetzung ist, 
dass FatFs im projekt eingebunden ist sowie xprintf (xprintf hab ich mit 
dem USART verknüpft)

ach ja, ich programmier in CooCox in kombination mit GCC. Das Beispiel 
ist jetzt auch im CooCox repository vom STM32F0->SPI verfügbar.

Ganz unten ist eine beispielfunktion wie man files von der karte im root 
Verzeichnis ausliest (war für mich zum lernen was FatFS kann und mehr 
zum debuggen gedacht).

Hat sicher noch den einen oder anderen bug, läuft aber schon ganz 
anständig (getestet auf einem STM32F051C8 auf Eigenbauplatine).
Kommentare leider nur auf englisch (und französisch aus dem original 
code).

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&currentviews=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
}

von Roman (Gast)


Lesenswert?

Habe den Code mal ausgetestet, kriege leider einen Hard Fault sobald 
f_open aufgerufen wird. Außerdem gibt es Namenskonflikte mit der 
diskio.h wo es ebenfalls diese Funktionen gibt. Habe versucht sie durch 
die obigen zu ersetzen aber es kommt erneut zu Hard Fault. Irgendeine 
Idee?
ich meine im Code wird kein f_open gecalled...sondern eine Funktion die 
nicht existiert aufgerufen (showimage)

Beitrag #5606444 wurde von einem Moderator gelöscht.
von D. S. (schnitzgi)


Lesenswert?

na was ich da vor 5 jahren gebastelt hab weiss ich jetzt grad nicht mehr 
auswendig. im kopf hab ich aber geschrieben man soll "FATfs" von elm 
chan ins projekt einbinden aber das file diskio.c nicht. f_open braucht 
natürlich eine gewisse menge an ram, evtl hast du deinen ram nicht 
richtig konfiguriert (stack vs. heap) und bekommst da einen overflow. 
FATfs kann man auch noch konfigurieren, musst mal reinschauen. 
vielleicht hilft die super low ram variante davon, ist irgend so ein 
compiler flag in der config von FATfs.
Hardfault auf den STMs passieren bei mir meistens bei stack overflows, 
da würde ich zuerst mal suchen.
edit:
falls du das root-dir öffnen kannst funktionierts ja bereits. wenn du 
dann beim file öffnen einen hardfault bekommst hat das nichts mit dem 
obigen code zu tun sondern mit der FATfs library

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

D. S. schrieb:
> na was ich da vor 5 jahren gebastelt hab weiss ich jetzt grad nicht mehr
> auswendig.

Daß Du da gerade auf eine vor zweieinhalb Jahren gestellte Frage 
geantwortet hast, ist Dir nicht aufgefallen?

von D. S. (schnitzgi)


Lesenswert?

in der Tat. hab darauf nicht geachtet, wurde per email informiert über 
eine neue antwort, scheint ja wohl ein bug zu sein.
ihr moderatoren seid aber auch nicht grad um einen guten umgangston 
bemüht was?

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
Noch kein Account? Hier anmelden.