EFR32 Blue Gecko 1 Software Documentation  efr32bg1-doc-5.1.2
microsd.c
Go to the documentation of this file.
1 /**************************************************************************/
19 #include "diskio.h"
20 #include "microsd.h"
21 #include "em_cmu.h"
22 #include "em_usart.h"
23 
24 /**************************************************************************/
30 static uint32_t timeOut, xfersPrMsec;
31 
32 /**************************************************************************/
36 static uint8_t WaitReady(void)
37 {
38  uint8_t res;
39  uint32_t retryCount;
40 
41  /* Wait for ready in timeout of 500ms */
42  retryCount = 500 * xfersPrMsec;
43  do
44  res = MICROSD_XferSpi(0xff);
45  while ((res != 0xFF) && --retryCount);
46 
47  return res;
48 }
51 /**************************************************************************/
56 void MICROSD_Init(void)
57 {
59 
60  /* Enabling clock to USART 0 */
61  CMU_ClockEnable(MICROSD_CMUCLOCK, true);
63 
64  /* Initialize USART in SPI master mode. */
65  xfersPrMsec = MICROSD_LO_SPI_FREQ / 8000;
66  init.baudrate = MICROSD_LO_SPI_FREQ;
67  init.msbf = true;
68  USART_InitSync(MICROSD_USART, &init);
69 
70  /* Enabling pins and setting location, SPI CS not enable */
71  MICROSD_USART->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN |
72  USART_ROUTE_CLKPEN | MICROSD_LOC;
73 
74 #if defined( USART_CTRL_SMSDELAY )
75  /* This will allow us to use higher baudrate. */
76  MICROSD_USART->CTRL |= USART_CTRL_SMSDELAY;
77 #endif
78 
79  /* IO configuration */
80  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModePushPull, 0); /* MOSI */
81  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeInputPull, 1); /* MISO */
82  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN, gpioModePushPull, 1); /* CS */
83  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN, gpioModePushPull, 0); /* CLK */
84 }
85 
86 /**************************************************************************/
91 void MICROSD_Deinit(void)
92 {
93  USART_Reset(MICROSD_USART);
94 
95  /* IO configuration (USART 0, Location #0) */
96  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModeDisabled, 0); /* MOSI */
97  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeDisabled, 0); /* MISO */
98  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN, gpioModeDisabled, 0); /* CS */
99  GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN, gpioModeDisabled, 0); /* Clock */
100 }
101 
102 /**************************************************************************/
112 uint8_t MICROSD_XferSpi(uint8_t data)
113 {
114  if ( timeOut )
115  {
116  timeOut--;
117  }
118 
119  return USART_SpiTransfer(MICROSD_USART, data);
120 }
121 
122 /**************************************************************************/
126 {
127  GPIO->P[ MICROSD_GPIOPORT ].DOUTSET = 1 << MICROSD_CSPIN; /* CS pin high. */
128  MICROSD_XferSpi(0xff);
129 }
130 
131 /**************************************************************************/
135 int MICROSD_Select(void)
136 {
137  GPIO->P[ MICROSD_GPIOPORT ].DOUTCLR = 1 << MICROSD_CSPIN; /* CS pin low. */
138  if (WaitReady() != 0xFF)
139  {
141  return 0;
142  }
143  return 1;
144 }
145 
146 /**************************************************************************/
150 void MICROSD_PowerOn(void)
151 {
152  /* Enable SPI clock */
153  CMU_ClockEnable(MICROSD_CMUCLOCK, true);
154 }
155 
156 /**************************************************************************/
161 {
162  /* Wait for micro SD card ready */
163  MICROSD_Select();
165  /* Disable SPI clock */
166  CMU_ClockEnable(MICROSD_CMUCLOCK, false);
167 }
168 
169 /**************************************************************************/
178 int MICROSD_BlockRx(uint8_t *buff, uint32_t btr)
179 {
180  uint8_t token;
181  uint16_t val;
182  uint32_t retryCount, framectrl, ctrl;
183 
184  /* Wait for data packet in timeout of 100ms */
185  retryCount = 100 * xfersPrMsec;
186  do
187  {
188  token = MICROSD_XferSpi(0xff);
189  } while ((token == 0xFF) && --retryCount);
190 
191  if (token != 0xFE)
192  {
193  /* Invalid data token */
194  return 0;
195  }
196 
197  /* Save current configuration. */
198  framectrl = MICROSD_USART->FRAME;
199  ctrl = MICROSD_USART->CTRL;
200 
201  /* Set frame length to 16 bit. This will increase the effective data rate. */
202  MICROSD_USART->FRAME = (MICROSD_USART->FRAME & (~_USART_FRAME_DATABITS_MASK))
204  MICROSD_USART->CTRL |= USART_CTRL_BYTESWAP;
205 
206  /* Clear send and receive buffers. */
207  MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
208 
209  if ( timeOut >= btr + 2 )
210  {
211  timeOut -= btr + 2;
212  }
213  else
214  {
215  timeOut = 0;
216  }
217 
218  /* Pipelining - The USART has two buffers of 16 bit in both
219  * directions. Make sure that at least one is in the pipe at all
220  * times to maximize throughput. */
221  MICROSD_USART->TXDOUBLE = 0xffff;
222  do
223  {
224  MICROSD_USART->TXDOUBLE = 0xffff;
225 
226  while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
227 
228  val = MICROSD_USART->RXDOUBLE;
229  *buff++ = val;
230  *buff++ = val >> 8;
231 
232  btr -= 2;
233  } while (btr);
234 
235  /* Next two bytes is the CRC which we discard. */
236  while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
237  MICROSD_USART->RXDOUBLE;
238 
239  /* Restore old settings. */
240  MICROSD_USART->FRAME = framectrl;
241  MICROSD_USART->CTRL = ctrl;
242 
243  return 1; /* Return with success */
244 }
245 
246 /**************************************************************************/
252 #if _READONLY == 0
253 int MICROSD_BlockTx(const uint8_t *buff, uint8_t token)
254 {
255  uint8_t resp;
256  uint16_t val;
257  uint32_t bc = 512;
258  uint32_t framectrl, ctrl;
259 
260  if (WaitReady() != 0xFF)
261  {
262  return 0;
263  }
264 
265  MICROSD_XferSpi(token); /* Xmit a token */
266 
267  if (token == 0xFD)
268  {
269  /* StopTran token */
270  return 1;
271  }
272 
273  /* Save current configuration. */
274  framectrl = MICROSD_USART->FRAME;
275  ctrl = MICROSD_USART->CTRL;
276 
277  /* Set frame length to 16 bit. This will increase the effective data rate. */
278  MICROSD_USART->FRAME = (MICROSD_USART->FRAME & (~_USART_FRAME_DATABITS_MASK))
280  MICROSD_USART->CTRL |= USART_CTRL_BYTESWAP;
281 
282  /* Clear send and receive buffers. */
283  MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
284 
285  if ( timeOut >= bc + 2 )
286  {
287  timeOut -= bc + 2;
288  }
289  else
290  {
291  timeOut = 0;
292  }
293 
294  do
295  {
296  /* Transmit a 512 byte data block to the SD-Card. */
297 
298  val = *buff++;
299  val |= *buff++ << 8;
300  bc -= 2;
301 
302  while (!(MICROSD_USART->STATUS & USART_STATUS_TXBL));
303 
304  MICROSD_USART->TXDOUBLE = val;
305  } while (bc);
306 
307  while (!(MICROSD_USART->STATUS & USART_STATUS_TXBL));
308 
309  /* Transmit two dummy CRC bytes. */
310  MICROSD_USART->TXDOUBLE = 0xFFFF;
311 
312  while (!(MICROSD_USART->STATUS & USART_STATUS_TXC));
313 
314  /* Clear send and receive buffers. */
315  MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
316 
317  /* Restore old settings. */
318  MICROSD_USART->FRAME = framectrl;
319  MICROSD_USART->CTRL = ctrl;
320 
321  resp = MICROSD_XferSpi(0xff); /* Receive a data response */
322 
323  if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
324  {
325  return 0;
326  }
327 
328  return 1;
329 }
330 #endif /* _READONLY */
331 
332 /**************************************************************************/
342 uint8_t MICROSD_SendCmd(uint8_t cmd, DWORD arg)
343 {
344  uint8_t n, res;
345  uint32_t retryCount;
346 
347  if (cmd & 0x80)
348  { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
349  cmd &= 0x7F;
350  res = MICROSD_SendCmd(CMD55, 0);
351  if (res > 1)
352  {
353  return res;
354  }
355  }
356 
357  /* Select the card and wait for ready */
359  if (!MICROSD_Select())
360  {
361  return 0xFF;
362  }
363 
364  /* Send command packet */
365  MICROSD_XferSpi(0x40 | cmd); /* Start + Command index */
366  MICROSD_XferSpi((uint8_t)(arg >> 24)); /* Argument[31..24] */
367  MICROSD_XferSpi((uint8_t)(arg >> 16)); /* Argument[23..16] */
368  MICROSD_XferSpi((uint8_t)(arg >> 8)); /* Argument[15..8] */
369  MICROSD_XferSpi((uint8_t) arg); /* Argument[7..0] */
370  n = 0x01; /* Dummy CRC + Stop */
371  if (cmd == CMD0)
372  {
373  n = 0x95; /* Valid CRC for CMD0(0) */
374  }
375  if (cmd == CMD8)
376  {
377  n = 0x87; /* Valid CRC for CMD8(0x1AA) */
378  }
379  MICROSD_XferSpi(n);
380 
381  /* Receive command response */
382  if (cmd == CMD12)
383  {
384  MICROSD_XferSpi(0xff); /* Skip a stuff byte when stop reading */
385  }
386  retryCount = 10; /* Wait for a valid response in timeout of 10 attempts */
387  do
388  {
389  res = MICROSD_XferSpi(0xff);
390  } while ((res & 0x80) && --retryCount);
391 
392  return res; /* Return with the response value */
393 }
394 
395 /**************************************************************************/
400 {
401  USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_LO_SPI_FREQ);
402  xfersPrMsec = MICROSD_LO_SPI_FREQ / 8000;
403 }
404 
405 /**************************************************************************/
409 {
410  USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_HI_SPI_FREQ);
411  xfersPrMsec = MICROSD_HI_SPI_FREQ / 8000;
412 }
413 
414 /**************************************************************************/
422 void MICROSD_TimeOutSet(uint32_t msec)
423 {
424  timeOut = xfersPrMsec * msec;
425 }
426 
427 /**************************************************************************/
434 {
435  return timeOut == 0;
436 }
Clock management unit (CMU) API.
void MICROSD_Init(void)
Initialize the SPI peripheral for microSD card usage. SPI pins and speed etc. is defined in microsdco...
Definition: microsd.c:56
void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
Init USART for synchronous mode.
Definition: em_usart.c:640
#define USART_STATUS_TXBL
#define USART_STATUS_RXDATAV
void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
Configure USART operating in synchronous mode to use a given baudrate (or as close as possible to spe...
Definition: em_usart.c:480
#define CMD55
Definition: microsd.h:57
Micro SD card driver for the EFM32GG_DK3750 development kit.
#define CMD12
Definition: microsd.h:47
#define USART_CTRL_BYTESWAP
Universal synchronous/asynchronous receiver/transmitter (USART/UART) peripheral API.
void MICROSD_SpiClkSlow(void)
Set SPI clock to a low frequency suitable for initial card initialization.
Definition: microsd.c:399
#define GPIO
#define USART_STATUS_TXC
void MICROSD_PowerOn(void)
Turn on micro SD card power. DK doesn't support socket power control, only enable the SPI clock...
Definition: microsd.c:150
#define USART_FRAME_DATABITS_SIXTEEN
void MICROSD_Deinit(void)
Deinitialize SPI peripheral. Turn off the SPI peripheral and disable SPI GPIO pins.
Definition: microsd.c:91
#define _USART_FRAME_DATABITS_MASK
void MICROSD_Deselect(void)
Deselect the micro SD card and release the SPI bus.
Definition: microsd.c:125
int MICROSD_Select(void)
Select the micro SD card and wait for the card to become ready.
Definition: microsd.c:135
bool MICROSD_TimeOutElapsed(void)
Check if timeout value set with MICROSD_TimeOutSet() has elapsed.
Definition: microsd.c:433
void GPIO_PinModeSet(GPIO_Port_TypeDef port, unsigned int pin, GPIO_Mode_TypeDef mode, unsigned int out)
Set the mode for a GPIO pin.
Definition: em_gpio.c:269
void MICROSD_SpiClkFast(void)
Set SPI clock to maximum frequency.
Definition: microsd.c:408
void MICROSD_TimeOutSet(uint32_t msec)
Set a timeout value. The timeout value will be decremented towards zero when SPI traffic to/from the ...
Definition: microsd.c:422
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
#define USART_CTRL_SMSDELAY
#define CMD8
Definition: microsd.h:44
int MICROSD_BlockTx(const uint8_t *buff, uint8_t token)
Send a data block to micro SD card.
Definition: microsd.c:253
void USART_Reset(USART_TypeDef *usart)
Reset USART/UART to same state as after a HW reset.
Definition: em_usart.c:856
uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
Perform one 8 bit frame SPI transfer.
Definition: em_usart.c:1050
#define CMD0
Definition: microsd.h:41
void MICROSD_PowerOff(void)
Turn off micro SD card power. DK doesn't support socket power control, only disable the SPI clock...
Definition: microsd.c:160
uint8_t MICROSD_SendCmd(uint8_t cmd, DWORD arg)
Send a command packet to micro SD card.
Definition: microsd.c:342
int MICROSD_BlockRx(uint8_t *buff, uint32_t btr)
Receive a data block from micro SD card.
Definition: microsd.c:178
#define USART_INITSYNC_DEFAULT
Definition: em_usart.h:467
#define USART_CMD_CLEARRX
uint8_t MICROSD_XferSpi(uint8_t data)
Do one SPI transfer.
Definition: microsd.c:112
#define USART_CMD_CLEARTX