microsd.c

Go to the documentation of this file.
00001 /**************************************************************************/
00019 #include "diskio.h"
00020 #include "microsd.h"
00021 #include "em_cmu.h"
00022 #include "em_usart.h"
00023 
00024 /**************************************************************************/
00030 static uint32_t timeOut, xfersPrMsec;
00031 
00032 /**************************************************************************/
00036 static uint8_t WaitReady(void)
00037 {
00038   uint8_t res;
00039   uint32_t retryCount;
00040 
00041   /* Wait for ready in timeout of 500ms */
00042   retryCount = 500 * xfersPrMsec;
00043   do
00044     res = MICROSD_XferSpi(0xff);
00045   while ((res != 0xFF) && --retryCount);
00046 
00047   return res;
00048 }
00051 /**************************************************************************/
00056 void MICROSD_Init(void)
00057 {
00058   USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT;
00059 
00060   /* Enabling clock to USART 0 */
00061   CMU_ClockEnable(MICROSD_CMUCLOCK, true);
00062   CMU_ClockEnable(cmuClock_GPIO, true);
00063 
00064   /* Initialize USART in SPI master mode. */
00065   xfersPrMsec   = MICROSD_LO_SPI_FREQ / 8000;
00066   init.baudrate = MICROSD_LO_SPI_FREQ;
00067   init.msbf     = true;
00068   USART_InitSync(MICROSD_USART, &init);
00069 
00070   /* Enabling pins and setting location, SPI CS not enable */
00071   MICROSD_USART->ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN |
00072                          USART_ROUTE_CLKPEN | MICROSD_LOC;
00073 
00074 #if defined( USART_CTRL_SMSDELAY )
00075   /* This will allow us to use higher baudrate. */
00076   MICROSD_USART->CTRL |= USART_CTRL_SMSDELAY;
00077 #endif
00078 
00079   /* IO configuration */
00080   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModePushPull, 0);  /* MOSI */
00081   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeInputPull, 1); /* MISO */
00082   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN,   gpioModePushPull, 1);  /* CS */
00083   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN,  gpioModePushPull, 0);  /* CLK */
00084 }
00085 
00086 /**************************************************************************/
00091 void MICROSD_Deinit(void)
00092 {
00093   USART_Reset(MICROSD_USART);
00094 
00095   /* IO configuration (USART 0, Location #0) */
00096   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MOSIPIN, gpioModeDisabled, 0);  /* MOSI */
00097   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_MISOPIN, gpioModeDisabled, 0);  /* MISO */
00098   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CSPIN,   gpioModeDisabled, 0);  /* CS */
00099   GPIO_PinModeSet(MICROSD_GPIOPORT, MICROSD_CLKPIN,  gpioModeDisabled, 0);  /* Clock */
00100 }
00101 
00102 /**************************************************************************/
00112 uint8_t MICROSD_XferSpi(uint8_t data)
00113 {
00114   if ( timeOut )
00115   {
00116     timeOut--;
00117   }
00118 
00119   return USART_SpiTransfer(MICROSD_USART, data);
00120 }
00121 
00122 /**************************************************************************/
00125 void MICROSD_Deselect(void)
00126 {
00127   GPIO->P[ MICROSD_GPIOPORT ].DOUTSET = 1 << MICROSD_CSPIN; /* CS pin high. */
00128   MICROSD_XferSpi(0xff);
00129 }
00130 
00131 /**************************************************************************/
00135 int MICROSD_Select(void)
00136 {
00137   GPIO->P[ MICROSD_GPIOPORT ].DOUTCLR = 1 << MICROSD_CSPIN; /* CS pin low. */
00138   if (WaitReady() != 0xFF)
00139   {
00140     MICROSD_Deselect();
00141     return 0;
00142   }
00143   return 1;
00144 }
00145 
00146 /**************************************************************************/
00150 void MICROSD_PowerOn(void)
00151 {
00152   /* Enable SPI clock */
00153   CMU_ClockEnable(MICROSD_CMUCLOCK, true);
00154 }
00155 
00156 /**************************************************************************/
00160 void MICROSD_PowerOff(void)
00161 {
00162   /* Wait for micro SD card ready */
00163   MICROSD_Select();
00164   MICROSD_Deselect();
00165   /* Disable SPI clock */
00166   CMU_ClockEnable(MICROSD_CMUCLOCK, false);
00167 }
00168 
00169 /**************************************************************************/
00178 int MICROSD_BlockRx(uint8_t *buff, uint32_t btr)
00179 {
00180   uint8_t token;
00181   uint16_t val;
00182   uint32_t retryCount, framectrl, ctrl;
00183 
00184   /* Wait for data packet in timeout of 100ms */
00185   retryCount = 100 * xfersPrMsec;
00186   do
00187   {
00188     token = MICROSD_XferSpi(0xff);
00189   } while ((token == 0xFF) && --retryCount);
00190 
00191   if (token != 0xFE)
00192   {
00193     /* Invalid data token */
00194     return 0;
00195   }
00196 
00197   /* Save current configuration. */
00198   framectrl = MICROSD_USART->FRAME;
00199   ctrl      = MICROSD_USART->CTRL;
00200 
00201   /* Set frame length to 16 bit. This will increase the effective data rate. */
00202   MICROSD_USART->FRAME = (MICROSD_USART->FRAME & (~_USART_FRAME_DATABITS_MASK))
00203                          | USART_FRAME_DATABITS_SIXTEEN;
00204   MICROSD_USART->CTRL |= USART_CTRL_BYTESWAP;
00205 
00206   /* Clear send and receive buffers. */
00207   MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
00208 
00209   if ( timeOut >= btr + 2 )
00210   {
00211     timeOut -= btr + 2;
00212   }
00213   else
00214   {
00215     timeOut = 0;
00216   }
00217 
00218   /* Pipelining - The USART has two buffers of 16 bit in both
00219    * directions. Make sure that at least one is in the pipe at all
00220    * times to maximize throughput. */
00221   MICROSD_USART->TXDOUBLE = 0xffff;
00222   do
00223   {
00224     MICROSD_USART->TXDOUBLE = 0xffff;
00225 
00226     while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
00227 
00228     val = MICROSD_USART->RXDOUBLE;
00229     *buff++ = val;
00230     *buff++ = val >> 8;
00231 
00232     btr -= 2;
00233   } while (btr);
00234 
00235   /* Next two bytes is the CRC which we discard. */
00236   while (!(MICROSD_USART->STATUS & USART_STATUS_RXDATAV));
00237   MICROSD_USART->RXDOUBLE;
00238 
00239   /* Restore old settings. */
00240   MICROSD_USART->FRAME = framectrl;
00241   MICROSD_USART->CTRL  = ctrl;
00242 
00243   return 1;     /* Return with success */
00244 }
00245 
00246 /**************************************************************************/
00252 #if _READONLY == 0
00253 int MICROSD_BlockTx(const uint8_t *buff, uint8_t token)
00254 {
00255   uint8_t resp;
00256   uint16_t val;
00257   uint32_t bc = 512;
00258   uint32_t framectrl, ctrl;
00259 
00260   if (WaitReady() != 0xFF)
00261   {
00262     return 0;
00263   }
00264 
00265   MICROSD_XferSpi(token);         /* Xmit a token */
00266 
00267   if (token == 0xFD)
00268   {
00269     /* StopTran token */
00270     return 1;
00271   }
00272 
00273   /* Save current configuration. */
00274   framectrl = MICROSD_USART->FRAME;
00275   ctrl      = MICROSD_USART->CTRL;
00276 
00277   /* Set frame length to 16 bit. This will increase the effective data rate. */
00278   MICROSD_USART->FRAME = (MICROSD_USART->FRAME & (~_USART_FRAME_DATABITS_MASK))
00279                          | USART_FRAME_DATABITS_SIXTEEN;
00280   MICROSD_USART->CTRL |= USART_CTRL_BYTESWAP;
00281 
00282   /* Clear send and receive buffers. */
00283   MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
00284 
00285   if ( timeOut >= bc + 2 )
00286   {
00287     timeOut -= bc + 2;
00288   }
00289   else
00290   {
00291     timeOut = 0;
00292   }
00293 
00294   do
00295   {
00296     /* Transmit a 512 byte data block to the SD-Card. */
00297 
00298     val  = *buff++;
00299     val |= *buff++ << 8;
00300     bc  -= 2;
00301 
00302     while (!(MICROSD_USART->STATUS & USART_STATUS_TXBL));
00303 
00304     MICROSD_USART->TXDOUBLE = val;
00305   } while (bc);
00306 
00307   while (!(MICROSD_USART->STATUS & USART_STATUS_TXBL));
00308 
00309   /* Transmit two dummy CRC bytes. */
00310   MICROSD_USART->TXDOUBLE = 0xFFFF;
00311 
00312   while (!(MICROSD_USART->STATUS & USART_STATUS_TXC));
00313 
00314   /* Clear send and receive buffers. */
00315   MICROSD_USART->CMD = USART_CMD_CLEARRX | USART_CMD_CLEARTX;
00316 
00317   /* Restore old settings. */
00318   MICROSD_USART->FRAME = framectrl;
00319   MICROSD_USART->CTRL  = ctrl;
00320 
00321   resp = MICROSD_XferSpi(0xff); /* Receive a data response */
00322 
00323   if ((resp & 0x1F) != 0x05)    /* If not accepted, return with error */
00324   {
00325     return 0;
00326   }
00327 
00328   return 1;
00329 }
00330 #endif  /* _READONLY */
00331 
00332 /**************************************************************************/
00342 uint8_t MICROSD_SendCmd(uint8_t cmd, DWORD arg)
00343 {
00344   uint8_t  n, res;
00345   uint32_t retryCount;
00346 
00347   if (cmd & 0x80)
00348   { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
00349     cmd &= 0x7F;
00350     res  = MICROSD_SendCmd(CMD55, 0);
00351     if (res > 1)
00352     {
00353       return res;
00354     }
00355   }
00356 
00357   /* Select the card and wait for ready */
00358   MICROSD_Deselect();
00359   if (!MICROSD_Select())
00360   {
00361     return 0xFF;
00362   }
00363 
00364   /* Send command packet */
00365   MICROSD_XferSpi(0x40 | cmd);            /* Start + Command index */
00366   MICROSD_XferSpi((uint8_t)(arg >> 24));  /* Argument[31..24] */
00367   MICROSD_XferSpi((uint8_t)(arg >> 16));  /* Argument[23..16] */
00368   MICROSD_XferSpi((uint8_t)(arg >> 8));   /* Argument[15..8] */
00369   MICROSD_XferSpi((uint8_t) arg);         /* Argument[7..0] */
00370   n = 0x01;                               /* Dummy CRC + Stop */
00371   if (cmd == CMD0)
00372   {
00373     n = 0x95;                             /* Valid CRC for CMD0(0) */
00374   }
00375   if (cmd == CMD8)
00376   {
00377     n = 0x87;                             /* Valid CRC for CMD8(0x1AA) */
00378   }
00379   MICROSD_XferSpi(n);
00380 
00381   /* Receive command response */
00382   if (cmd == CMD12)
00383   {
00384     MICROSD_XferSpi(0xff);                /* Skip a stuff byte when stop reading */
00385   }
00386   retryCount = 10;                        /* Wait for a valid response in timeout of 10 attempts */
00387   do
00388   {
00389     res = MICROSD_XferSpi(0xff);
00390   } while ((res & 0x80) && --retryCount);
00391 
00392   return res;             /* Return with the response value */
00393 }
00394 
00395 /**************************************************************************/
00399 void MICROSD_SpiClkSlow(void)
00400 {
00401   USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_LO_SPI_FREQ);
00402   xfersPrMsec = MICROSD_LO_SPI_FREQ / 8000;
00403 }
00404 
00405 /**************************************************************************/
00408 void MICROSD_SpiClkFast(void)
00409 {
00410   USART_BaudrateSyncSet(MICROSD_USART, 0, MICROSD_HI_SPI_FREQ);
00411   xfersPrMsec = MICROSD_HI_SPI_FREQ / 8000;
00412 }
00413 
00414 /**************************************************************************/
00422 void MICROSD_TimeOutSet(uint32_t msec)
00423 {
00424   timeOut = xfersPrMsec * msec;
00425 }
00426 
00427 /**************************************************************************/
00433 bool MICROSD_TimeOutElapsed(void)
00434 {
00435   return timeOut == 0;
00436 }