microsd.c

Go to the documentation of this file.
00001 /**************************************************************************/
00037 #include "diskio.h"
00038 #include "microsd.h"
00039 #include "em_cmu.h"
00040 #include "em_usart.h"
00041 
00042 /**************************************************************************/
00048 static uint32_t timeOut, xfersPrMsec;
00049 
00050 /**************************************************************************/
00054 static uint8_t WaitReady(void)
00055 {
00056   uint8_t res;
00057   uint32_t retryCount;
00058 
00059   /* Wait for ready in timeout of 500ms */
00060   retryCount = 500 * xfersPrMsec;
00061   do
00062     res = MICROSD_XferSpi(0xff);
00063   while ((res != 0xFF) && --retryCount);
00064 
00065   return res;
00066 }
00069 /**************************************************************************/
00074 void MICROSD_Init(void)
00075 {
00076   USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
00077 
00078   /* Enabling clock to USART 0 */
00079   CMU_ClockEnable(MICROSD_CMUCLOCK, true);
00080   CMU_ClockEnable(cmuClock_GPIO, true);
00081 
00082   /* Initialize USART in SPI master mode. */
00083   xfersPrMsec   = MICROSD_LO_SPI_FREQ / 8000;
00084   init.baudrate = MICROSD_LO_SPI_FREQ;
00085   init.msbf     = true;
00086   USART_InitSync(MICROSD_USART, &init);
00087 
00088   /* Enabling pins and setting location, SPI CS not enable */
00089   MICROSD_USART->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN |
00090                          USART_ROUTE_CLKPEN | MICROSD_LOC;
00091 
00092   /* IO configuration */
00093   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModePushPull, 0);  /* MOSI */
00094   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeInputPull, 1); /* MISO */
00095   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN,   gpioModePushPull, 1);  /* CS */
00096   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN,  gpioModePushPull, 0);  /* CLK */
00097 }
00098 
00099 /**************************************************************************/
00104 void MICROSD_Deinit(void)
00105 {
00106   USART_Reset(MICROSD_USART);
00107 
00108   /* IO configuration (USART 0, Location #0) */
00109   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModeDisabled, 0);  /* MOSI */
00110   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeDisabled, 0);  /* MISO */
00111   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN,   gpioModeDisabled, 0);  /* CS */
00112   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN,  gpioModeDisabled, 0);  /* Clock */
00113 }
00114 
00115 /**************************************************************************/
00125 uint8_t MICROSD_XferSpi(uint8_t data)
00126 {
00127   if ( timeOut )
00128     timeOut--;
00129 
00130   return USART_SpiTransfer(MICROSD_USART, data);
00131 }
00132 
00133 /**************************************************************************/
00136 void MICROSD_Deselect(void)
00137 {
00138   GPIO->P[ MICROSD_GPIOPORT ].DOUTSET = 1 << MICROSD_CSPIN; /* CS pin high. */
00139   MICROSD_XferSpi(0xff);
00140 }
00141 
00142 /**************************************************************************/
00146 int MICROSD_Select(void)
00147 {
00148   GPIO->P[ MICROSD_GPIOPORT ].DOUTCLR = 1 << MICROSD_CSPIN; /* CS pin low. */
00149   if (WaitReady() != 0xFF)
00150   {
00151     MICROSD_Deselect();
00152     return 0;
00153   }
00154   return 1;
00155 }
00156 
00157 /**************************************************************************/
00161 void MICROSD_PowerOn(void)
00162 {
00163   /* Enable SPI clock */
00164   CMU_ClockEnable(MICROSD_CMUCLOCK, true);
00165 }
00166 
00167 /**************************************************************************/
00171 void MICROSD_PowerOff(void)
00172 {
00173   /* Wait for micro SD card ready */
00174   MICROSD_Select();
00175   MICROSD_Deselect();
00176   /* Disable SPI clock */
00177   CMU_ClockEnable(MICROSD_CMUCLOCK, false);
00178 }
00179 
00180 /**************************************************************************/
00189 int MICROSD_BlockRx(uint8_t *buff, uint32_t btr)
00190 {
00191   uint8_t token;
00192   uint32_t retryCount, framectrl, ctrl;
00193   uint16_t *buff_16 = (uint16_t *) buff;
00194 
00195   /* Wait for data packet in timeout of 100ms */
00196   retryCount = 100 * xfersPrMsec;
00197   do
00198     token = MICROSD_XferSpi(0xff);
00199   while ((token == 0xFF) && --retryCount);
00200 
00201   if (token != 0xFE)
00202     /* Invalid data token */
00203     return 0;
00204 
00205   /* Save old configuration. */
00206   framectrl = MICROSD_USART->FRAME;
00207   ctrl      = MICROSD_USART->CTRL;
00208 
00209   /* Set up frames to 16 bit on each frame. This will increase the
00210    * data rate and make the maximum use of the buffers available. */
00211   MICROSD_USART->FRAME = (MICROSD_USART->FRAME & (~_USART_FRAME_DATABITS_MASK))
00212                          | USART_FRAME_DATABITS_SIXTEEN;
00213   MICROSD_USART->CTRL |= USART_CTRL_BYTESWAP;
00214 
00215   /* Clear send and receive buffer */
00216   MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
00217 
00218   if ( timeOut >= btr + 2 )
00219     timeOut -= btr + 2;
00220   else
00221     timeOut = 0;
00222 
00223   /* Pipelining - The USART has two buffers of 16 bit in both
00224    * directions. Make sure that at least one is in the pipe at all
00225    * times to maximize throughput. */
00226   MICROSD_USART->TXDOUBLE = 0xffff;
00227   do
00228   {
00229     MICROSD_USART->TXDOUBLE = 0xffff;
00230 
00231     while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
00232     *buff_16++ = (uint16_t) MICROSD_USART->RXDOUBLE;
00233 
00234     btr -= 2;
00235   } while (btr);
00236 
00237   /* Next two bytes is the CRC which we discard. */
00238   while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
00239   MICROSD_USART->RXDOUBLE;
00240 
00241   /* Restore old settings. */
00242   MICROSD_USART->FRAME = framectrl;
00243   MICROSD_USART->CTRL  = ctrl;
00244 
00245   return 1;     /* Return with success */
00246 }
00247 
00248 /**************************************************************************/
00254 #if _READONLY == 0
00255 int MICROSD_BlockTx(const uint8_t *buff, uint8_t token)
00256 {
00257   uint8_t resp;
00258   uint32_t bc = 512;
00259 
00260   if (WaitReady() != 0xFF)
00261     return 0;
00262 
00263   MICROSD_XferSpi(token);         /* Xmit a token */
00264   if (token != 0xFD)
00265   {                               /* Not StopTran token */
00266     do
00267     {
00268       /* Xmit the 512 byte data block to the MMC */
00269       MICROSD_XferSpi(*buff++);
00270       MICROSD_XferSpi(*buff++);
00271       MICROSD_XferSpi(*buff++);
00272       MICROSD_XferSpi(*buff++);
00273       bc -= 4;
00274     } while (bc);
00275 
00276     MICROSD_XferSpi(0xFF);        /* CRC (Dummy) */
00277     MICROSD_XferSpi(0xFF);
00278     resp = MICROSD_XferSpi(0xff); /* Receive a data response */
00279     if ((resp & 0x1F) != 0x05)    /* If not accepted, return with error */
00280       return 0;
00281   }
00282   return 1;
00283 }
00284 #endif  /* _READONLY */
00285 
00286 /**************************************************************************/
00296 uint8_t MICROSD_SendCmd(uint8_t cmd, DWORD arg)
00297 {
00298   uint8_t  n, res;
00299   uint32_t retryCount;
00300 
00301   if (cmd & 0x80)
00302   { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
00303     cmd &= 0x7F;
00304     res  = MICROSD_SendCmd(CMD55, 0);
00305     if (res > 1) return res;
00306   }
00307 
00308   /* Select the card and wait for ready */
00309   MICROSD_Deselect();
00310   if (!MICROSD_Select())
00311     return 0xFF;
00312 
00313   /* Send command packet */
00314   MICROSD_XferSpi(0x40 | cmd);            /* Start + Command index */
00315   MICROSD_XferSpi((uint8_t)(arg >> 24));  /* Argument[31..24] */
00316   MICROSD_XferSpi((uint8_t)(arg >> 16));  /* Argument[23..16] */
00317   MICROSD_XferSpi((uint8_t)(arg >> 8));   /* Argument[15..8] */
00318   MICROSD_XferSpi((uint8_t) arg);         /* Argument[7..0] */
00319   n = 0x01;                               /* Dummy CRC + Stop */
00320   if (cmd == CMD0)
00321     n = 0x95;                             /* Valid CRC for CMD0(0) */
00322   if (cmd == CMD8)
00323     n = 0x87;                             /* Valid CRC for CMD8(0x1AA) */
00324   MICROSD_XferSpi(n);
00325 
00326   /* Receive command response */
00327   if (cmd == CMD12)
00328     MICROSD_XferSpi(0xff);                /* Skip a stuff byte when stop reading */
00329   retryCount = 10;                        /* Wait for a valid response in timeout of 10 attempts */
00330   do
00331     res = MICROSD_XferSpi(0xff);
00332   while ((res & 0x80) && --retryCount);
00333 
00334   return res;             /* Return with the response value */
00335 }
00336 
00337 /**************************************************************************/
00341 void MICROSD_SpiClkSlow(void)
00342 {
00343   USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_LO_SPI_FREQ);
00344   xfersPrMsec = MICROSD_LO_SPI_FREQ / 8000;
00345 }
00346 
00347 /**************************************************************************/
00350 void MICROSD_SpiClkFast(void)
00351 {
00352   USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_HI_SPI_FREQ);
00353   xfersPrMsec = MICROSD_HI_SPI_FREQ / 8000;
00354 }
00355 
00356 /**************************************************************************/
00364 void MICROSD_TimeOutSet(uint32_t msec)
00365 {
00366   timeOut = xfersPrMsec * msec;
00367 }
00368 
00369 /**************************************************************************/
00375 bool MICROSD_TimeOutElapsed(void)
00376 {
00377   return timeOut == 0;
00378 }