embkernel
 All Classes Functions Variables Typedefs Groups Pages
FsDriveSdSpi.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "FsDriveSdSpi.hpp"
7 #include "LibEndian.hpp"
8 #include "FsCfg.hpp"
9 
10 FsDriveSdSpi* FsDriveSdSpi::sInstances[1];
11 
12 FsDriveSdSpi::FsDriveSdSpi(DrvSpi* spi) {
13  sInstances[0] = this;
14  mSpi = spi;
15 }
16 
17 FsDriveSdSpi::~FsDriveSdSpi() {
18 
19 }
20 
21 bool FsDriveSdSpi::internalInit() {
22  mSpi->setBaudrate(400000);
23  mSpi->deselect();
24  for (int i = 0; i < 10; i++) {
25  mSpi->readWrite(0xFF);
26  }
27  if (sendCmd(CMD0_GO_IDLE_STATE, 0).value != RESP_R1_IDLE_VALUE) {
28  return false;
29  }
30  if (sendCmd(CMD8_SEND_IF_COND, 0x1AA).value != RESP_R1_IDLE_VALUE) {
31  return false;
32  }
33  RESP_R7 respR7;
34  mSpi->readWrite(0, 0, (uint8_t*) &respR7, sizeof(respR7));
35  if (respR7.voltageAccepted != 1 || respR7.checkPattern != 0xAA) {
36  return false;
37  }
38 
39  RtosTimer timer;
40  timer.set(Rtos::convertMsToTick(1000));
41  while (true) {
42  if (timer.isEllapsed()) {
43  return false;
44  }
45  if (sendCmd(CMD55_APP_CMD, 0).value <= RESP_R1_IDLE_VALUE) {
46  if (sendCmd(ACMD41_SD_SEND_OP_COND, 0x40000000).value == 0) {
47  break;
48  }
49  }
50  }
51 
52  if (sendCmd(CMD9_SEND_CSD, 0).value != 0) {
53  return false;
54  }
55 
56  uint8_t csd[16];
57  if (!readDataBlock(csd, sizeof(csd))) {
58  return false;
59  }
60  if ((csd[0] >> 6) == 1) { // SDC ver 2
61  uint32_t cs = csd[9] + ((uint32_t) csd[8] << 8) + 1;
62  mSectorsCount = cs << 10;
63  }
64  else { // SDC ver 1
65  uint32_t n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
66  uint32_t cs = (csd[8] >> 6) + ((uint32_t) csd[7] << 2) + ((uint32_t) (csd[6] & 3) << 10) + 1;
67  mSectorsCount = cs << (n - 9);
68  }
69  mSpi->setBaudrate(FS_CFG_SPI_FULL_SPEED_BAUDRATE);
70  return true;
71 }
72 
73 bool FsDriveSdSpi::init() {
74  bool result = internalInit();
75  mSpi->deselect();
76  return result;
77 }
78 
79 bool FsDriveSdSpi::readDataBlock(uint8_t* buffer, unsigned int size) {
80  RtosTimer timer;
81  timer.set(Rtos::convertMsToTick(100)+1);
82 
83  while (true) {
84  if (mSpi->readWrite(0xFF) == 0xFE) {
85  break;
86  }
87  if (timer.isEllapsed()) {
88  return false;
89  }
90  }
91 
92  mSpi->readWrite(0, 0, buffer, size);
93  uint8_t crc[2];
94  mSpi->readWrite(0, 0, crc, 2); //CRC
95  return true;
96 }
97 
98 bool FsDriveSdSpi::internalReadBlocks(FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
99  uint8_t* dst = (uint8_t*) buffer;
100 
101  if (blockCount == 1) {
102  if (sendCmd(CMD17_READ_SINGLE_BLOCK, blockNumber).value != 0) {
103  return false;
104  }
105  if (!readDataBlock(dst, 512)) {
106  return false;
107  }
108 
109  }
110  else {
111  if (sendCmd(CMD18_READ_MULTIPLE_BLOCK, blockNumber).value != 0) {
112  return false;
113  }
114 
115  while (blockCount-- > 0) {
116  if (!readDataBlock(dst, 512)) {
117  return false;
118  }
119  dst += 512;
120  }
121  sendCmd(CMD12_STOP_TRANSMISSION, 0);
122 
123  }
124  return true;
125 }
126 
127 bool FsDriveSdSpi::readBlocks(FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
128  bool result = internalReadBlocks(buffer, blockNumber, blockCount);
129  mSpi->deselect();
130  return result;
131 }
132 
133 bool FsDriveSdSpi::writeDataBlock(const uint8_t* buffer, unsigned int size, bool isMultipleBlock) {
134  if (!waitReady()) {
135  return false;
136  }
137 
138  if (isMultipleBlock) {
139  mSpi->readWrite(START_MULTIPLE_BLOCK_WRITE);
140  }
141  else {
142  mSpi->readWrite(START_SINGLE_BLOCK_WRITE);
143  }
144  mSpi->readWrite(buffer, size, 0, 0);
145  uint8_t tokenAndCrc[3];
146  mSpi->readWrite(0, 0, tokenAndCrc, 3);
147  if ((tokenAndCrc[0] & 0x1F) != 0x05) { //Check control token
148  return false;
149  }
150  return true;
151 }
152 
153 bool FsDriveSdSpi::internalWriteBlocks(const FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
154  uint8_t* src = (uint8_t*) buffer;
155  if (blockCount == 1) {
156  if (sendCmd(CMD24_WRITE_BLOCK, blockNumber).value != 0) {
157  return false;
158  }
159  if (!writeDataBlock(src, 512, false)) {
160  return false;
161  }
162 
163  }
164  else {
165  if (sendCmd(ACMD23_SET_WR_BLK_ERASE_COUNT, blockCount).value > RESP_R1_IDLE_VALUE) {
166  return false;
167  }
168  if (sendCmd(CMD25_WRITE_MULTIPLE_BLOCK, blockNumber).value != 0) {
169  return false;
170  }
171  while (blockCount-- > 0) {
172  if (!writeDataBlock(src, 512, true)) {
173  return false;
174  }
175  src += 512;
176  }
177  //Stop tranmission
178  if (!waitReady()) {
179  return false;
180  }
181  mSpi->readWrite(STOP_TRANSMISSION);
182  }
183  return true;
184 }
185 
186 bool FsDriveSdSpi::writeBlocks(const FsDefs::SECTOR* buffer, unsigned int blockNumber, unsigned int blockCount) {
187  bool result = internalWriteBlocks(buffer, blockNumber, blockCount);
188  mSpi->deselect();
189  return result;
190 }
191 
192 FsDriveSdSpi::RESP_R1 FsDriveSdSpi::sendCmd(uint8_t cmd, uint32_t arg) {
193  mSpi->deselect();
194 
195  CMD_RESP cmdResp;
196  RESP_R1 resp;
197 
198  cmdResp.start = 0;
199  cmdResp.cmdRsp = 1;
200  cmdResp.cmdId = cmd;
201  cmdResp.args[0] = (uint8_t) ((arg >> 24) & 0xFF);
202  cmdResp.args[1] = (uint8_t) ((arg >> 16) & 0xFF);
203  cmdResp.args[2] = (uint8_t) ((arg >> 8) & 0xFF);
204  cmdResp.args[3] = (uint8_t) (arg & 0xFF);
205  cmdResp.crc = 0;
206  cmdResp.stop = 1;
207 //The SPI interface is initialized in the CRC OFF mode in default. (except for commands CMD0 and CMD8).
208  if (cmd == CMD0_GO_IDLE_STATE) {
209  cmdResp.crc = 0x0A;
210  }
211  if (cmd == CMD8_SEND_IF_COND) {
212  cmdResp.crc = 0x43;
213  }
214 
215  resp.value = 0xFF;
216  mSpi->select();
217  if (!waitReady()) {
218  return resp;
219  }
220  mSpi->readWrite((uint8_t*) &cmdResp, sizeof(CMD_RESP), 0, 0);
221  if (cmd == CMD12_STOP_TRANSMISSION) {
222  mSpi->readWrite(0);
223  }
224 
225  for (int i = 0; (i < 10); i++) { //Get the response (try max 10 times)
226  resp.value = mSpi->readWrite(0xFF);
227  if (!resp.bits.zero) {
228  break;
229  }
230  }
231  return resp; // Return with the response value
232 }
233 
234 bool FsDriveSdSpi::waitReady() {
235  RtosTimer timer;
236  timer.set(Rtos::convertMsToTick(500)+1);
237 
238  while (!timer.isEllapsed()) {
239  if (mSpi->readWrite(0xFF) == 0xFF) {
240  return true;
241  }
242  }
243  return false;
244 }
245