embkernel
 All Classes Functions Variables Typedefs Groups Pages
FsDriveSdio.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "FsDriveSdio.hpp"
7 #include "LibEndian.hpp"
8 #include "DrvCfg.hpp"
9 #include <stm32f4xx.h>
10 
11 FsDriveSdio* FsDriveSdio::sInstances[1];
12 
13 FsDriveSdio::FsDriveSdio() :
14  mSemaInt(1, 0) {
15  sInstances[0] = this;
16 }
17 
18 FsDriveSdio::~FsDriveSdio() {
19 
20 }
21 
22 bool FsDriveSdio::init() {
23  NVIC ->IP[SDIO_IRQn] = RTOS_INT_PRI;
24  NVIC_EnableIRQ(SDIO_IRQn);
25  mFlags.value = 0;
26 
27  SDIO ->CLKCR = (DRV_CFG_PCLK1_FREQ / 400000) - 2;
28  SDIO ->POWER = SDIO_POWER_PWRCTRL;
29  SDIO ->CLKCR |= SDIO_CLKCR_CLKEN;
30  sendCmd(0, CMD_GO_IDLE_STATE | SDIO_CMD_CPSMEN );
31  if (sendCmd(SD_CHECK_PATTERN, SDIO_SEND_IF_COND | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_7)) {
32  mFlags.bits.isSdhc = true;
33  }
34  else {
35  sendCmd(0, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
36  }
37 
38  if (sendCmd(0, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) { //SD card
39  while (true) {
40  sendCmd(0, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
41  if (mFlags.bits.isSdhc) {
42  sendCmd(0xC0100000, CMD_SD_APP_OP_COND | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
43  }
44  else {
45  sendCmd(0x80100000, CMD_SD_APP_OP_COND | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
46  }
47  RESP_STATUS status;
48  status.value = SDIO ->RESP1;
49  if (status.bits.outOfRange) {
50  if (status.bits.addressError) {
51  mFlags.bits.isSdhc = 1;
52  }
53  else {
54  mFlags.bits.isSdhc = 0;
55  }
56  break;
57  }
58  }
59  }
60  else { //MMC card
61  return false;
62  }
63  if (!sendCmd(0, CMD_ALL_SEND_CID | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_1 | SDIO_CMD_WAITRESP_0, RESP_2)) {
64  return false;
65  }
66  mCid.values[0] = SDIO ->RESP4;
67  mCid.values[1] = SDIO ->RESP3;
68  mCid.values[2] = SDIO ->RESP2;
69  mCid.values[3] = SDIO ->RESP1;
70 
71  if (!sendCmd(0, CMD_SET_REL_ADDR | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_6)) {
72  return false;
73  }
74 
75  mRca.value = SDIO ->RESP1;
76  if (mRca.value & RESP_RCA_STATUS_ERROR_BITS) {
77  return false;
78  }
79 
80  if (!sendCmd(mRca.bits.newRca << 16, CMD_SEND_CSD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_1 | SDIO_CMD_WAITRESP_0, RESP_2)) {
81  return false;
82  }
83  mCsd.values[0] = SDIO ->RESP4;
84  mCsd.values[1] = SDIO ->RESP3;
85  mCsd.values[2] = SDIO ->RESP2;
86  mCsd.values[3] = SDIO ->RESP1;
87 
88  //Get card size
89  if (mCsd.bitsV1.csdStruct == 0) { //CSD Version 1.0
90  mSectorsCount = ((((uint32_t) mCsd.bitsV1.cSizeHi) << 2) + mCsd.bitsV1.cSizeLo) + 1;
91  mSectorsCount *= ((uint32_t) 2) << (((uint32_t) mCsd.bitsV1.cSizeMult) + 2);
92  uint32_t blocklen = ((uint32_t) 2) << mCsd.bitsV1.readBlLen;
93  mSectorsCount = (mSectorsCount / 512) * blocklen;
94  }
95  else if (mCsd.bitsV2.csdStruct == 1) { //CSD Version 2.0
96  mSectorsCount = (((uint32_t) mCsd.bitsV2.cSizeHi) << 16) + (uint32_t) mCsd.bitsV2.cSizeLo + 1;
97  mSectorsCount *= 1024;
98  }
99  else {
100  //Unknown version
101  mSectorsCount = 0;
102  }
103 
104  SDIO ->CLKCR &= ~SDIO_CLKCR_CLKDIV; //Set to 24MHz
105  Rtos::sleep(2);
106 
107  if (!sendCmd(mRca.bits.newRca << 16, CMD_SEL_DESEL_CARD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
108  return false;
109  }
110 
111  if (!sendCmd(8, CMD_SET_BLOCKLEN | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
112  return false;
113  }
114 
115  if (!sendCmd(mRca.bits.newRca << 16, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
116  return false;
117  }
118 
119  dataTransferConfig(0xFFFFFFFF, 8, SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DBLOCKSIZE_1 | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN );
120 
121  if (!sendCmd(0, CMD_SD_APP_SEND_SCR | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
122  return false;
123  }
124 
125  for (int i = 0; i < 2 && !(SDIO ->STA & (SDIO_STA_RXOVERR | SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_DBCKEND | SDIO_STA_STBITERR ));) {
126  if (i >= 2) {
127  return false;
128  }
129  if (SDIO ->STA & SDIO_STA_RXDAVL ) {
130  mScr.value[i] = LibEndian::beToHw(SDIO ->FIFO);
131  i++;
132  }
133  }
134 
135  if (SDIO ->STA & (SDIO_STA_DTIMEOUT | SDIO_STA_DCRCFAIL | SDIO_STA_RXOVERR | SDIO_STA_STBITERR )) {
136  return false;
137  }
138  SDIO ->ICR = SDIO_STATIC_FLAGS;
139 
140  if (!(mScr.bits.datBusWidthSupport & 0b0100)) {
141  return false;
142  }
143 
144  if (!sendCmd(mRca.bits.newRca << 16, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
145  return false;
146  }
147 
148  if (!sendCmd(2, CMD_APP_SD_SET_BUSWIDTH | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
149  return false;
150  }
151 
152  SDIO ->CLKCR |= SDIO_CLKCR_WIDBUS_0;
153 
154  if (!sendCmd(512, CMD_SET_BLOCKLEN | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
155  return false;
156  }
157  mBytesPerSector = 512;
158 
159  return true;
160 }
161 
162 bool FsDriveSdio::readBlocks(FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
163  int retries = 100;
164 
165  while (retries-- > 0) {
166  {
167  int timeout = 100000;
168  while (timeout--) {
169  SD_STATE state;
170  if (getState(&state)) {
171  if (state == SD_STATE_TRAN) {
172  break;
173  }
174  }
175  }
176  }
177 
178  SDIO ->DCTRL = 0;
179 
180  DMA2 ->LIFCR = 0x0F000000;
181  DMA2_Stream3 ->CR = 0;
182  DMA2_Stream3 ->FCR = DMA_SxFCR_FTH | DMA_SxFCR_DMDIS;
183  DMA2_Stream3 ->M0AR = (uint32_t) buffer;
184  DMA2_Stream3 ->NDTR = 0;
185  DMA2_Stream3 ->PAR = (uint32_t) &SDIO ->FIFO;
186  DMA2_Stream3 ->CR = DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1 | DMA_SxCR_MBURST_0
187  | DMA_SxCR_PBURST_0 | DMA_SxCR_PFCTRL | DMA_SxCR_EN;
188 
189  if (!sendCmd(blockNumber, CMD_READ_MULT_BLOCK | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
190  continue;
191  }
192 
193  SDIO ->MASK |= SDIO_STA_DATAEND | SDIO_STA_DCRCFAIL;
194  dataTransferConfig(0xFFFFFFFF, blockCount * 512,
195  SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DTDIR | SDIO_DCTRL_DTEN );
196 
197  uint32_t status;
198  bool result = false;
199  if (waitInterrupt(&status)) {
200  if (status & SDIO_STA_DCRCFAIL ) {
201  result = false;
202  }
203  else if (status & SDIO_STA_DATAEND ) {
204  result = true;
205  }
206  }
207 
208  sendCmd(0, CMD_STOP_TRANSMISSION | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
209 
210  if (result) {
211  return true;
212  }
213  }
214 
215  return false;
216 }
217 
218 bool FsDriveSdio::writeBlocks(const FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
219  int retries = 100;
220 
221  while (retries-- > 0) {
222  {
223  int timeout = 100000;
224  while (timeout--) {
225  SD_STATE state;
226  if (getState(&state)) {
227  if (state == SD_STATE_TRAN) {
228  break;
229  }
230  }
231  }
232  }
233 
234  SDIO ->DCTRL = 0;
235 
236  DMA2 ->LIFCR = 0x0F000000;
237  DMA2_Stream3 ->CR = 0;
238  DMA2_Stream3 ->FCR = DMA_SxFCR_FTH | DMA_SxFCR_DMDIS;
239  DMA2_Stream3 ->M0AR = (uint32_t) buffer;
240  DMA2_Stream3 ->NDTR = 0;
241  DMA2_Stream3 ->PAR = (uint32_t) &SDIO ->FIFO;
242  DMA2_Stream3 ->CR = DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_PSIZE_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PL_0 | DMA_SxCR_PL_1 | DMA_SxCR_MBURST_0
243  | DMA_SxCR_PBURST_0 | DMA_SxCR_PFCTRL | DMA_SxCR_EN | DMA_SxCR_DIR_0;
244 
245  if (!sendCmd(mRca.bits.newRca << 16, CMD_APP_CMD | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
246  continue;
247  }
248 
249  if (!sendCmd(blockCount, CMD_SET_BLOCK_COUNT | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
250  continue;
251  }
252 
253  if (!sendCmd(blockNumber, CMD_WRITE_MULT_BLOCK | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
254  continue;
255  }
256 
257  SDIO ->MASK |= SDIO_STA_DATAEND | SDIO_STA_DCRCFAIL;
258  dataTransferConfig(0xFFFFFFFF, blockCount * 512, SDIO_DCTRL_DBLOCKSIZE_0 | SDIO_DCTRL_DMAEN | SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DTEN );
259 
260  uint32_t status;
261  bool result = false;
262  if (waitInterrupt(&status)) {
263  if (status & SDIO_STA_DCRCFAIL ) {
264  result = false;
265  }
266  else if (status & SDIO_STA_DATAEND ) {
267  result = true;
268  }
269  }
270 
271  sendCmd(0, CMD_STOP_TRANSMISSION | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1);
272 
273  if (result) {
274  return true;
275  }
276  }
277 
278  return false;
279 }
280 
281 bool FsDriveSdio::waitInterrupt(uint32_t* status) {
282  bool result = mSemaInt.take(Rtos::convertMsToTick(10000));
283  *status = SDIO->STA;
284  SDIO->ICR = SDIO_STATIC_FLAGS;
285  return result;
286 }
287 
288 bool FsDriveSdio::sendCmd(uint32_t arg, uint32_t cmd, RESPONSE response) {
289  SDIO ->ARG = arg;
290  if (cmd & SDIO_CMD_WAITRESP_0 ) {
291  SDIO ->MASK |= SDIO_STA_CMDREND | SDIO_STA_CCRCFAIL | SDIO_STA_CTIMEOUT;
292  SDIO ->CMD = cmd;
293  if (!mSemaInt.take(Rtos::convertMsToTick(10000))) {
294  return false;
295  }
296  if (SDIO ->STA & SDIO_STA_CMDREND ) {
297  SDIO ->ICR = SDIO_STATIC_FLAGS;
298  switch (response) {
299  case RESP_NONE:
300  break;
301  case RESP_1: {
302  if ((SDIO ->RESPCMD & 0b11111) != (cmd & 0b11111)) {
303  return false;
304  }
305  RESP_STATUS status;
306  status.value = SDIO ->RESP1;
307  if (status.value & RESP_STATUS_ERROR_BITS) {
308  return false;
309  }
310  break;
311  }
312  case RESP_2:
313  break;
314  case RESP_3:
315  break;
316  case RESP_4:
317  break;
318  case RESP_5:
319  break;
320  case RESP_6: {
321  if ((SDIO ->RESPCMD & 0b11111) != (cmd & 0b11111)) {
322  return false;
323  }
324  break;
325  }
326  case RESP_7:
327  break;
328  }
329  return true;
330  }
331  if (SDIO ->STA & SDIO_STA_CCRCFAIL ) {
332  SDIO ->ICR = SDIO_STA_CCRCFAIL;
333  return false;
334  }
335  if (SDIO ->STA & SDIO_STA_CTIMEOUT ) {
336  SDIO ->ICR = SDIO_STA_CTIMEOUT;
337  return false;
338  }
339  }
340  else {
341  SDIO ->MASK |= SDIO_STA_CMDSENT;
342  SDIO ->CMD = cmd;
343  if (!mSemaInt.take(Rtos::convertMsToTick(10000))) {
344  return false;
345  }
346  SDIO ->ICR = SDIO_STATIC_FLAGS;
347  return true;
348  }
349  return false;
350 }
351 
352 bool FsDriveSdio::getState(SD_STATE* state) {
353  if (!sendCmd(mRca.bits.newRca << 16, CMD_SEND_STATUS | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0, RESP_1)) {
354  return false;
355  }
356  *state = ((RESP_STATUS*) (&SDIO ->RESP1))->bits.currentState;
357  return true;
358 }
359 
360 void FsDriveSdio::dataTransferConfig(uint32_t timer, uint32_t datalen, uint32_t ctrlFlags) {
361  SDIO ->DTIMER = timer;
362  SDIO ->DLEN = datalen;
363  SDIO ->DCTRL = ctrlFlags;
364 }
365 
366 void FsDriveSdio::onIntSdio() {
367  mSemaInt.giveFromInt();
368  SDIO ->MASK &= ~SDIO_STATIC_FLAGS;
369 }
370 
371 extern "C" void RtosInterrupt::IRQ_SDIO() {
372  FsDriveSdio::sInstances[0]->onIntSdio();
373 }
374