ChibiOS  21.6.0
hal_sdc.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 /**
18  * @file hal_sdc.c
19  * @brief SDC Driver code.
20  *
21  * @addtogroup SDC
22  * @{
23  */
24 
25 #include <string.h>
26 
27 #include "hal.h"
28 
29 #if (HAL_USE_SDC == TRUE) || defined(__DOXYGEN__)
30 
31 /*===========================================================================*/
32 /* Driver local definitions. */
33 /*===========================================================================*/
34 
35 /**
36  * @brief MMC switch mode.
37  */
38 typedef enum {
39  MMC_SWITCH_COMMAND_SET = 0,
40  MMC_SWITCH_SET_BITS = 1,
41  MMC_SWITCH_CLEAR_BITS = 2,
42  MMC_SWITCH_WRITE_BYTE = 3
43 } mmc_switch_t;
44 
45 /**
46  * @brief SDC switch mode.
47  */
48 typedef enum {
49  SD_SWITCH_CHECK = 0,
50  SD_SWITCH_SET = 1
51 } sd_switch_t;
52 
53 /**
54  * @brief SDC switch function.
55  */
56 typedef enum {
57  SD_SWITCH_FUNCTION_SPEED = 0,
58  SD_SWITCH_FUNCTION_CMD_SYSTEM = 1,
59  SD_SWITCH_FUNCTION_DRIVER_STRENGTH = 2,
60  SD_SWITCH_FUNCTION_CURRENT_LIMIT = 3
62 
63 /*===========================================================================*/
64 /* Driver exported variables. */
65 /*===========================================================================*/
66 
67 /*===========================================================================*/
68 /* Driver local variables and types. */
69 /*===========================================================================*/
70 
71 /**
72  * @brief Virtual methods table.
73  */
74 static const struct SDCDriverVMT sdc_vmt = {
75  (size_t)0,
76  (bool (*)(void *))sdc_lld_is_card_inserted,
77  (bool (*)(void *))sdc_lld_is_write_protected,
78  (bool (*)(void *))sdcConnect,
79  (bool (*)(void *))sdcDisconnect,
80  (bool (*)(void *, uint32_t, uint8_t *, uint32_t))sdcRead,
81  (bool (*)(void *, uint32_t, const uint8_t *, uint32_t))sdcWrite,
82  (bool (*)(void *))sdcSync,
83  (bool (*)(void *, BlockDeviceInfo *))sdcGetInfo
84 };
85 
86 /*===========================================================================*/
87 /* Driver local functions. */
88 /*===========================================================================*/
89 /**
90  * @brief Detects card mode.
91  *
92  * @param[in] sdcp pointer to the @p SDCDriver object
93  *
94  * @return The operation status.
95  * @retval HAL_SUCCESS operation succeeded.
96  * @retval HAL_FAILED operation failed.
97  *
98  * @notapi
99  */
100 static bool mode_detect(SDCDriver *sdcp) {
101  uint32_t resp[1];
102 
103  /* V2.0 cards detection.*/
104  if (!sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_IF_COND,
105  MMCSD_CMD8_PATTERN, resp)) {
106  sdcp->cardmode = SDC_MODE_CARDTYPE_SDV20;
107  /* Voltage verification.*/
108  if (((resp[0] >> 8U) & 0xFU) != 1U) {
109  return HAL_FAILED;
110  }
111  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) ||
112  MMCSD_R1_ERROR(resp[0])) {
113  return HAL_FAILED;
114  }
115  }
116  else {
117  /* MMC or SD V1.1 detection.*/
118  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) ||
119  MMCSD_R1_ERROR(resp[0])) {
120  sdcp->cardmode = SDC_MODE_CARDTYPE_MMC;
121  }
122  else {
123  sdcp->cardmode = SDC_MODE_CARDTYPE_SDV11;
124 
125  /* Reset error flag illegal command.*/
126  sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0);
127  }
128  }
129 
130  return HAL_SUCCESS;
131 }
132 
133 /**
134  * @brief Init procedure for MMC.
135  *
136  * @param[in] sdcp pointer to the @p SDCDriver object
137  *
138  * @return The operation status.
139  * @retval HAL_SUCCESS operation succeeded.
140  * @retval HAL_FAILED operation failed.
141  *
142  * @notapi
143  */
144 static bool mmc_init(SDCDriver *sdcp) {
145  uint32_t ocr;
146  unsigned i;
147  uint32_t resp[1];
148 
149  ocr = 0xC0FF8000U;
150  i = 0;
151  while (true) {
152  if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_INIT, ocr, resp)) {
153  return HAL_FAILED;
154  }
155  if ((resp[0] & 0x80000000U) != 0U) {
156  if ((resp[0] & 0x40000000U) != 0U) {
157  sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY;
158  }
159  break;
160  }
161  if (++i >= (unsigned)SDC_INIT_RETRY) {
162  return HAL_FAILED;
163  }
165  }
166 
167  return HAL_SUCCESS;
168 }
169 
170 /**
171  * @brief Init procedure for SDC.
172  *
173  * @param[in] sdcp pointer to the @p SDCDriver object
174  *
175  * @return The operation status.
176  * @retval HAL_SUCCESS operation succeeded.
177  * @retval HAL_FAILED operation failed.
178  *
179  * @notapi
180  */
181 static bool sdc_init(SDCDriver *sdcp) {
182  unsigned i;
183  uint32_t ocr;
184  uint32_t resp[1];
185 
186  if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_SDV20) {
187  ocr = SDC_INIT_OCR_V20;
188  }
189  else {
190  ocr = SDC_INIT_OCR;
191  }
192 
193  i = 0;
194  while (true) {
195  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, 0, resp) ||
196  MMCSD_R1_ERROR(resp[0])) {
197  return HAL_FAILED;
198  }
199  if (sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_APP_OP_COND, ocr, resp)) {
200  return HAL_FAILED;
201  }
202  if ((resp[0] & 0x80000000U) != 0U) {
203  if ((resp[0] & 0x40000000U) != 0U) {
204  sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY;
205  }
206  break;
207  }
208  if (++i >= (unsigned)SDC_INIT_RETRY) {
209  return HAL_FAILED;
210  }
212  }
213 
214  return HAL_SUCCESS;
215 }
216 
217 /**
218  * @brief Constructs CMD6 argument for MMC.
219  *
220  * @param[in] access EXT_CSD access mode
221  * @param[in] idx EXT_CSD byte number
222  * @param[in] value value to be written in target field
223  * @param[in] cmd_set switch current command set
224  *
225  * @return CMD6 argument.
226  *
227  * @notapi
228  */
229 static uint32_t mmc_cmd6_construct(mmc_switch_t access, uint32_t idx,
230  uint32_t value, uint32_t cmd_set) {
231 
232  osalDbgAssert(idx <= 191U, "This field is not writable");
233  osalDbgAssert(cmd_set < 8U, "This field has only 3 bits");
234 
235  return ((uint32_t)access << 24U) | (idx << 16U) | (value << 8U) | cmd_set;
236 }
237 
238 /**
239  * @brief Constructs CMD6 argument for SDC.
240  *
241  * @param[in] mode switch/test mode
242  * @param[in] function function number to be switched
243  * @param[in] value value to be written in target function
244  *
245  * @return CMD6 argument.
246  *
247  * @notapi
248  */
249 static uint32_t sdc_cmd6_construct(sd_switch_t mode,
250  sd_switch_function_t function,
251  uint32_t value) {
252  uint32_t ret = 0xFFFFFF;
253 
254  osalDbgAssert((value < 16U), "This field has only 4 bits");
255 
256  ret &= ~((uint32_t)0xFU << ((uint32_t)function * 4U));
257  ret |= value << ((uint32_t)function * 4U);
258  return ret | ((uint32_t)mode << 31U);
259 }
260 
261 /**
262  * @brief Extracts information from CMD6 answer.
263  *
264  * @param[in] function function number to be switched
265  * @param[in] buf buffer with answer
266  *
267  * @return extracted answer.
268  *
269  * @notapi
270  */
272  const uint8_t *buf) {
273 
274  unsigned start = 12U - ((unsigned)function * 2U);
275 
276  return ((uint16_t)buf[start] << 8U) | (uint16_t)buf[start + 1U];
277 }
278 
279 /**
280  * @brief Checks status after switching using CMD6.
281  *
282  * @param[in] function function number to be switched
283  * @param[in] buf buffer with answer
284  *
285  * @return The operation status.
286  * @retval HAL_SUCCESS operation succeeded.
287  * @retval HAL_FAILED operation failed.
288  *
289  * @notapi
290  */
292  const uint8_t *buf) {
293 
294  uint32_t tmp;
295  uint32_t status;
296 
297  tmp = ((uint32_t)buf[14] << 16U) |
298  ((uint32_t)buf[15] << 8U) |
299  (uint32_t)buf[16];
300  status = (tmp >> ((uint32_t)function * 4U)) & 0xFU;
301  if (0xFU != status) {
302  return HAL_SUCCESS;
303  }
304  return HAL_FAILED;
305 }
306 
307 /**
308  * @brief Reads supported bus clock and switch SDC to appropriate mode.
309  *
310  * @param[in] sdcp pointer to the @p SDCDriver object
311  * @param[out] clk pointer to clock enum
312  *
313  * @return The operation status.
314  * @retval HAL_SUCCESS operation succeeded.
315  * @retval HAL_FAILED operation failed.
316  *
317  * @notapi
318  */
319 static bool sdc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) {
320  uint32_t cmdarg;
321  const size_t N = 64;
322  uint8_t tmp[N];
323 
324  /* Safe default.*/
325  *clk = SDC_CLK_25MHz;
326 
327  /* Looks like only "high capacity" cards produce meaningful results during
328  this clock detection procedure.*/
329  if (0U == _mmcsd_get_slice(sdcp->csd, MMCSD_CSD_10_CSD_STRUCTURE_SLICE)) {
330  *clk = SDC_CLK_25MHz;
331  return HAL_SUCCESS;
332  }
333 
334  /* Read switch functions' register.*/
335  if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, 0)) {
336  return HAL_FAILED;
337  }
338 
339  /* Check card capabilities parsing acquired data.*/
340  if ((sdc_cmd6_extract_info(SD_SWITCH_FUNCTION_SPEED, tmp) & 2U) == 2U) {
341  /* Construct command to set the bus speed.*/
342  cmdarg = sdc_cmd6_construct(SD_SWITCH_SET, SD_SWITCH_FUNCTION_SPEED, 1);
343 
344  /* Write constructed command and read operation status in single call.*/
345  if (sdc_lld_read_special(sdcp, tmp, N, MMCSD_CMD_SWITCH, cmdarg)) {
346  return HAL_FAILED;
347  }
348 
349  /* Check card answer for success status bits.*/
350  if (HAL_SUCCESS == sdc_cmd6_check_status(SD_SWITCH_FUNCTION_SPEED, tmp)) {
351  *clk = SDC_CLK_50MHz;
352  }
353  else {
354  *clk = SDC_CLK_25MHz;
355  }
356  }
357 
358  return HAL_SUCCESS;
359 }
360 
361 /**
362  * @brief Reads supported bus clock and switch MMC to appropriate mode.
363  *
364  * @param[in] sdcp pointer to the @p SDCDriver object
365  * @param[out] clk pointer to clock enum
366  *
367  * @return The operation status.
368  * @retval HAL_SUCCESS operation succeeded.
369  * @retval HAL_FAILED operation failed.
370  *
371  * @notapi
372  */
373 static bool mmc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) {
374  uint32_t cmdarg;
375  uint32_t resp[1];
376 
377  /* Safe default.*/
378  *clk = SDC_CLK_25MHz;
379 
380  cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 185, 1, 0);
381  if (!(sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) ||
382  MMCSD_R1_ERROR(resp[0]))) {
383  *clk = SDC_CLK_50MHz;
384  }
385 
386  return HAL_SUCCESS;
387 }
388 
389 /**
390  * @brief Reads supported bus clock and switch card to appropriate mode.
391  *
392  * @param[in] sdcp pointer to the @p SDCDriver object
393  * @param[out] clk pointer to clock enum
394  *
395  * @return The operation status.
396  * @retval HAL_SUCCESS operation succeeded.
397  * @retval HAL_FAILED operation failed.
398  *
399  * @notapi
400  */
401 static bool detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) {
402 
403  if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) {
404  return mmc_detect_bus_clk(sdcp, clk);
405  }
406  return sdc_detect_bus_clk(sdcp, clk);
407 }
408 
409 /**
410  * @brief Sets bus width for SDC.
411  *
412  * @param[in] sdcp pointer to the @p SDCDriver object
413  *
414  * @return The operation status.
415  * @retval HAL_SUCCESS operation succeeded.
416  * @retval HAL_FAILED operation failed.
417  *
418  * @notapi
419  */
420 static bool sdc_set_bus_width(SDCDriver *sdcp) {
421  uint32_t resp[1];
422 
423  if (SDC_MODE_1BIT == sdcp->config->bus_width) {
424  /* Nothing to do. Bus is already in 1bit mode.*/
425  return HAL_SUCCESS;
426  }
427  else if (SDC_MODE_4BIT == sdcp->config->bus_width) {
428  sdc_lld_set_bus_mode(sdcp, SDC_MODE_4BIT);
429  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_APP_CMD, sdcp->rca, resp) ||
430  MMCSD_R1_ERROR(resp[0])) {
431  return HAL_FAILED;
432  }
433 
434  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BUS_WIDTH, 2, resp) ||
435  MMCSD_R1_ERROR(resp[0])) {
436  return HAL_FAILED;
437  }
438  }
439  else {
440  /* SD card does not support 8bit bus.*/
441  return HAL_FAILED;
442  }
443 
444  return HAL_SUCCESS;
445 }
446 
447 /**
448  * @brief Sets bus width for MMC.
449  *
450  * @param[in] sdcp pointer to the @p SDCDriver object
451  *
452  * @return The operation status.
453  * @retval HAL_SUCCESS operation succeeded.
454  * @retval HAL_FAILED operation failed.
455  *
456  * @notapi
457  */
458 static bool mmc_set_bus_width(SDCDriver *sdcp) {
459  uint32_t resp[1];
460  uint32_t cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 0, 0);
461 
462  switch (sdcp->config->bus_width) {
463  case SDC_MODE_1BIT:
464  /* Nothing to do. Bus is already in 1bit mode.*/
465  return HAL_SUCCESS;
466  case SDC_MODE_4BIT:
467  cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 1, 0);
468  break;
469  case SDC_MODE_8BIT:
470  cmdarg = mmc_cmd6_construct(MMC_SWITCH_WRITE_BYTE, 183, 2, 0);
471  break;
472  default:
473  osalDbgAssert(false, "unexpected case");
474  break;
475  }
476 
477  sdc_lld_set_bus_mode(sdcp, sdcp->config->bus_width);
478  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SWITCH, cmdarg, resp) ||
479  MMCSD_R1_ERROR(resp[0])) {
480  return HAL_FAILED;
481  }
482 
483  return HAL_SUCCESS;
484 }
485 
486 /**
487  * @brief Wait for the card to complete pending operations.
488  *
489  * @param[in] sdcp pointer to the @p SDCDriver object
490  *
491  * @return The operation status.
492  * @retval HAL_SUCCESS operation succeeded.
493  * @retval HAL_FAILED operation failed.
494  *
495  * @notapi
496  */
498  uint32_t resp[1];
499 
500  while (true) {
501  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_STATUS,
502  sdcp->rca, resp) ||
503  MMCSD_R1_ERROR(resp[0])) {
504  return HAL_FAILED;
505  }
506 
507  switch (MMCSD_R1_STS(resp[0])) {
508  case MMCSD_STS_TRAN:
509  return HAL_SUCCESS;
510  case MMCSD_STS_DATA:
511  case MMCSD_STS_RCV:
512  case MMCSD_STS_PRG:
513 #if SDC_NICE_WAITING == TRUE
515 #endif
516  continue;
517  default:
518  /* The card should have been initialized so any other state is not
519  valid and is reported as an error.*/
520  return HAL_FAILED;
521  }
522  }
523 }
524 
525 /*===========================================================================*/
526 /* Driver exported functions. */
527 /*===========================================================================*/
528 
529 /**
530  * @brief SDC Driver initialization.
531  * @note This function is implicitly invoked by @p halInit(), there is
532  * no need to explicitly initialize the driver.
533  *
534  * @init
535  */
536 void sdcInit(void) {
537 
538  sdc_lld_init();
539 }
540 
541 /**
542  * @brief Initializes the standard part of a @p SDCDriver structure.
543  *
544  * @param[out] sdcp pointer to the @p SDCDriver object
545  *
546  * @init
547  */
549 
550  sdcp->vmt = &sdc_vmt;
551  sdcp->state = BLK_STOP;
552  sdcp->errors = SDC_NO_ERROR;
553  sdcp->config = NULL;
554  sdcp->capacity = 0;
555 }
556 
557 /**
558  * @brief Configures and activates the SDC peripheral.
559  *
560  * @param[in] sdcp pointer to the @p SDCDriver object
561  * @param[in] config pointer to the @p SDCConfig object, can be @p NULL if
562  * the driver supports a default configuration or
563  * requires no configuration
564  *
565  * @api
566  */
567 void sdcStart(SDCDriver *sdcp, const SDCConfig *config) {
568 
569  osalDbgCheck(sdcp != NULL);
570 
571  osalSysLock();
572  osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
573  "invalid state");
574  sdcp->config = config;
575  sdc_lld_start(sdcp);
576  sdcp->state = BLK_ACTIVE;
577  osalSysUnlock();
578 }
579 
580 /**
581  * @brief Deactivates the SDC peripheral.
582  *
583  * @param[in] sdcp pointer to the @p SDCDriver object
584  *
585  * @api
586  */
587 void sdcStop(SDCDriver *sdcp) {
588 
589  osalDbgCheck(sdcp != NULL);
590 
591  osalSysLock();
592 
593  osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
594  "invalid state");
595 
596  sdc_lld_stop(sdcp);
597  sdcp->config = NULL;
598  sdcp->state = BLK_STOP;
599 
600  osalSysUnlock();
601 }
602 
603 /**
604  * @brief Performs the initialization procedure on the inserted card.
605  * @details This function should be invoked when a card is inserted and
606  * brings the driver in the @p BLK_READY state where it is possible
607  * to perform read and write operations.
608  *
609  * @param[in] sdcp pointer to the @p SDCDriver object
610  *
611  * @return The operation status.
612  * @retval HAL_SUCCESS operation succeeded.
613  * @retval HAL_FAILED operation failed.
614  *
615  * @api
616  */
617 bool sdcConnect(SDCDriver *sdcp) {
618  uint32_t resp[1];
619  sdcbusclk_t clk = SDC_CLK_25MHz;
620 
621  osalDbgCheck(sdcp != NULL);
622  osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
623  "invalid state");
624 
625  /* Connection procedure in progress.*/
626  sdcp->state = BLK_CONNECTING;
627 
628  /* Card clock initialization.*/
629  sdc_lld_start_clk(sdcp);
630 
631  /* Enforces the initial card state.*/
632  sdc_lld_send_cmd_none(sdcp, MMCSD_CMD_GO_IDLE_STATE, 0);
633 
634  /* Detect card type.*/
635  if (HAL_FAILED == mode_detect(sdcp)) {
636  goto failed;
637  }
638 
639  /* Perform specific initialization procedure.*/
640  if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) {
641  if (HAL_FAILED == mmc_init(sdcp)) {
642  goto failed;
643  }
644  }
645  else {
646  if (HAL_FAILED == sdc_init(sdcp)) {
647  goto failed;
648  }
649  }
650 
651  /* Reads CID.*/
652  if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_ALL_SEND_CID, 0, sdcp->cid)) {
653  goto failed;
654  }
655 
656  /* Asks for the RCA.*/
657  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_RELATIVE_ADDR,
658  0, &sdcp->rca)) {
659  goto failed;
660  }
661 
662  /* Reads CSD.*/
663  if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_SEND_CSD,
664  sdcp->rca, sdcp->csd)) {
665  goto failed;
666  }
667 
668  /* Selects the card for operations.*/
669  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEL_DESEL_CARD,
670  sdcp->rca, resp)) {
671  goto failed;
672  }
673 
674  /* Switches to high speed.*/
675  if (HAL_SUCCESS != detect_bus_clk(sdcp, &clk)) {
676  goto failed;
677  }
678  sdc_lld_set_data_clk(sdcp, clk);
679 
680  /* Reads extended CSD if needed and possible.*/
681  if (SDC_MODE_CARDTYPE_MMC == (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK)) {
682 
683  /* The card is a MMC, checking if it is a large device.*/
684  if (_mmcsd_get_slice(sdcp->csd, MMCSD_CSD_MMC_CSD_STRUCTURE_SLICE) > 1U) {
685  uint8_t *ext_csd = sdcp->buf;
686 
687  if (sdc_lld_read_special(sdcp, ext_csd, 512, MMCSD_CMD_SEND_EXT_CSD, 0)) {
688  goto failed;
689  }
690 
691  /* Capacity from the EXT_CSD.*/
692  sdcp->capacity = _mmcsd_get_capacity_ext(ext_csd);
693  }
694  else {
695  /* Capacity from the normal CSD.*/
696  sdcp->capacity = _mmcsd_get_capacity(sdcp->csd);
697  }
698  }
699  else {
700  /* The card is an SDC, capacity from the normal CSD.*/
701  sdcp->capacity = _mmcsd_get_capacity(sdcp->csd);
702  }
703 
704  /* Block length fixed at 512 bytes.*/
705  if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SET_BLOCKLEN,
706  MMCSD_BLOCK_SIZE, resp) ||
707  MMCSD_R1_ERROR(resp[0])) {
708  goto failed;
709  }
710 
711  /* Switches to wide bus mode.*/
712  switch (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) {
713  case SDC_MODE_CARDTYPE_SDV11:
714  case SDC_MODE_CARDTYPE_SDV20:
715  if (HAL_FAILED == sdc_set_bus_width(sdcp)) {
716  goto failed;
717  }
718  break;
719  case SDC_MODE_CARDTYPE_MMC:
720  if (HAL_FAILED == mmc_set_bus_width(sdcp)) {
721  goto failed;
722  }
723  break;
724  default:
725  /* Unknown type.*/
726  goto failed;
727  }
728 
729  /* Initialization complete.*/
730  sdcp->state = BLK_READY;
731  return HAL_SUCCESS;
732 
733  /* Connection failed, state reset to BLK_ACTIVE.*/
734 failed:
735  sdc_lld_stop_clk(sdcp);
736  sdcp->state = BLK_ACTIVE;
737  return HAL_FAILED;
738 }
739 
740 /**
741  * @brief Brings the driver in a state safe for card removal.
742  *
743  * @param[in] sdcp pointer to the @p SDCDriver object
744  *
745  * @return The operation status.
746  * @retval HAL_SUCCESS operation succeeded.
747  * @retval HAL_FAILED operation failed.
748  *
749  * @api
750  */
752 
753  osalDbgCheck(sdcp != NULL);
754 
755  osalSysLock();
756  osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
757  "invalid state");
758  if (sdcp->state == BLK_ACTIVE) {
759  osalSysUnlock();
760  return HAL_SUCCESS;
761  }
762  sdcp->state = BLK_DISCONNECTING;
763  osalSysUnlock();
764 
765  /* Waits for eventual pending operations completion.*/
766  if (_sdc_wait_for_transfer_state(sdcp)) {
767  sdc_lld_stop_clk(sdcp);
768  sdcp->state = BLK_ACTIVE;
769  return HAL_FAILED;
770  }
771 
772  /* Card clock stopped.*/
773  sdc_lld_stop_clk(sdcp);
774  sdcp->state = BLK_ACTIVE;
775  return HAL_SUCCESS;
776 }
777 
778 /**
779  * @brief Reads one or more blocks.
780  * @pre The driver must be in the @p BLK_READY state after a successful
781  * sdcConnect() invocation.
782  *
783  * @param[in] sdcp pointer to the @p SDCDriver object
784  * @param[in] startblk first block to read
785  * @param[out] buf pointer to the read buffer
786  * @param[in] n number of blocks to read
787  *
788  * @return The operation status.
789  * @retval HAL_SUCCESS operation succeeded.
790  * @retval HAL_FAILED operation failed.
791  *
792  * @api
793  */
794 bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) {
795  bool status;
796 
797  osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U));
798  osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
799 
800  if ((startblk + n - 1U) > sdcp->capacity) {
801  sdcp->errors |= SDC_OVERFLOW_ERROR;
802  return HAL_FAILED;
803  }
804 
805  /* Read operation in progress.*/
806  sdcp->state = BLK_READING;
807 
808  status = sdc_lld_read(sdcp, startblk, buf, n);
809 
810  /* Read operation finished.*/
811  sdcp->state = BLK_READY;
812  return status;
813 }
814 
815 /**
816  * @brief Writes one or more blocks.
817  * @pre The driver must be in the @p BLK_READY state after a successful
818  * sdcConnect() invocation.
819  *
820  * @param[in] sdcp pointer to the @p SDCDriver object
821  * @param[in] startblk first block to write
822  * @param[out] buf pointer to the write buffer
823  * @param[in] n number of blocks to write
824  *
825  * @return The operation status.
826  * @retval HAL_SUCCESS operation succeeded.
827  * @retval HAL_FAILED operation failed.
828  *
829  * @api
830  */
831 bool sdcWrite(SDCDriver *sdcp, uint32_t startblk,
832  const uint8_t *buf, uint32_t n) {
833  bool status;
834 
835  osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U));
836  osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
837 
838  if ((startblk + n - 1U) > sdcp->capacity) {
839  sdcp->errors |= SDC_OVERFLOW_ERROR;
840  return HAL_FAILED;
841  }
842 
843  /* Write operation in progress.*/
844  sdcp->state = BLK_WRITING;
845 
846  status = sdc_lld_write(sdcp, startblk, buf, n);
847 
848  /* Write operation finished.*/
849  sdcp->state = BLK_READY;
850  return status;
851 }
852 
853 /**
854  * @brief Returns the errors mask associated to the previous operation.
855  *
856  * @param[in] sdcp pointer to the @p SDCDriver object
857  * @return The errors mask.
858  *
859  * @api
860  */
862  sdcflags_t flags;
863 
864  osalDbgCheck(sdcp != NULL);
865  osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
866 
867  osalSysLock();
868  flags = sdcp->errors;
869  sdcp->errors = SDC_NO_ERROR;
870  osalSysUnlock();
871  return flags;
872 }
873 
874 /**
875  * @brief Waits for card idle condition.
876  *
877  * @param[in] sdcp pointer to the @p SDCDriver object
878  *
879  * @return The operation status.
880  * @retval HAL_SUCCESS the operation succeeded.
881  * @retval HAL_FAILED the operation failed.
882  *
883  * @api
884  */
885 bool sdcSync(SDCDriver *sdcp) {
886  bool result;
887 
888  osalDbgCheck(sdcp != NULL);
889 
890  if (sdcp->state != BLK_READY) {
891  return HAL_FAILED;
892  }
893 
894  /* Synchronization operation in progress.*/
895  sdcp->state = BLK_SYNCING;
896 
897  result = sdc_lld_sync(sdcp);
898 
899  /* Synchronization operation finished.*/
900  sdcp->state = BLK_READY;
901  return result;
902 }
903 
904 /**
905  * @brief Returns the media info.
906  *
907  * @param[in] sdcp pointer to the @p SDCDriver object
908  * @param[out] bdip pointer to a @p BlockDeviceInfo structure
909  *
910  * @return The operation status.
911  * @retval HAL_SUCCESS the operation succeeded.
912  * @retval HAL_FAILED the operation failed.
913  *
914  * @api
915  */
917 
918  osalDbgCheck((sdcp != NULL) && (bdip != NULL));
919 
920  if (sdcp->state != BLK_READY) {
921  return HAL_FAILED;
922  }
923 
924  bdip->blk_num = sdcp->capacity;
925  bdip->blk_size = MMCSD_BLOCK_SIZE;
926 
927  return HAL_SUCCESS;
928 }
929 
930 /**
931  * @brief Erases the supplied blocks.
932  *
933  * @param[in] sdcp pointer to the @p SDCDriver object
934  * @param[in] startblk starting block number
935  * @param[in] endblk ending block number
936  *
937  * @return The operation status.
938  * @retval HAL_SUCCESS the operation succeeded.
939  * @retval HAL_FAILED the operation failed.
940  *
941  * @api
942  */
943 bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk) {
944  uint32_t resp[1];
945 
946  osalDbgCheck((sdcp != NULL));
947  osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
948 
949  /* Erase operation in progress.*/
950  sdcp->state = BLK_WRITING;
951 
952  /* Handling command differences between HC and normal cards.*/
953  if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) != 0U) {
954  startblk *= MMCSD_BLOCK_SIZE;
955  endblk *= MMCSD_BLOCK_SIZE;
956  }
957 
958  if (_sdc_wait_for_transfer_state(sdcp)) {
959  goto failed;
960  }
961 
962  if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_START,
963  startblk, resp) != HAL_SUCCESS) ||
964  MMCSD_R1_ERROR(resp[0])) {
965  goto failed;
966  }
967 
968  if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE_RW_BLK_END,
969  endblk, resp) != HAL_SUCCESS) ||
970  MMCSD_R1_ERROR(resp[0])) {
971  goto failed;
972  }
973 
974  if ((sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_ERASE,
975  0, resp) != HAL_SUCCESS) ||
976  MMCSD_R1_ERROR(resp[0])) {
977  goto failed;
978  }
979 
980  /* Quick sleep to allow it to transition to programming or receiving state */
981  /* CHTODO: ??????????????????????????? */
982 
983  /* Wait for it to return to transfer state to indicate it has finished erasing */
984  if (_sdc_wait_for_transfer_state(sdcp)) {
985  goto failed;
986  }
987 
988  sdcp->state = BLK_READY;
989  return HAL_SUCCESS;
990 
991 failed:
992  sdcp->state = BLK_READY;
993  return HAL_FAILED;
994 }
995 
996 #endif /* HAL_USE_SDC == TRUE */
997 
998 /** @} */
999 
sdc_lld_send_cmd_short_crc
bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, uint32_t *resp)
Sends an SDIO command with a short response expected and CRC.
Definition: hal_sdc_lld.c:222
SDCDriverVMT
SDCDriver virtual methods table.
Definition: hal_sdc_lld.h:98
mmc_set_bus_width
static bool mmc_set_bus_width(SDCDriver *sdcp)
Sets bus width for MMC.
Definition: hal_sdc.c:458
mmc_init
static bool mmc_init(SDCDriver *sdcp)
Init procedure for MMC.
Definition: hal_sdc.c:144
SDCDriver::vmt
const struct SDCDriverVMT * vmt
Virtual Methods Table.
Definition: hal_sdc_lld.h:109
sdc_cmd6_extract_info
static uint16_t sdc_cmd6_extract_info(sd_switch_function_t function, const uint8_t *buf)
Extracts information from CMD6 answer.
Definition: hal_sdc.c:271
BLK_READY
@ BLK_READY
Definition: hal_ioblock.h:46
_mmcsd_get_slice
uint32_t _mmcsd_get_slice(const uint32_t *data, uint32_t end, uint32_t start)
Gets a bit field from a words array.
Definition: hal_mmcsd.c:61
sdcStart
void sdcStart(SDCDriver *sdcp, const SDCConfig *config)
Configures and activates the SDC peripheral.
Definition: hal_sdc.c:567
sdcSync
bool sdcSync(SDCDriver *sdcp)
Waits for card idle condition.
Definition: hal_sdc.c:885
sdc_lld_start_clk
void sdc_lld_start_clk(SDCDriver *sdcp)
Starts the SDIO clock and sets it to init mode (400kHz or less).
Definition: hal_sdc_lld.c:107
MMCSD_CMD8_PATTERN
#define MMCSD_CMD8_PATTERN
Fixed pattern for CMD8.
Definition: hal_mmcsd.h:49
sd_switch_function_t
sd_switch_function_t
SDC switch function.
Definition: hal_sdc.c:56
sdc_lld_init
void sdc_lld_init(void)
Low level SDC driver initialization.
Definition: hal_sdc_lld.c:65
sdc_lld_start
void sdc_lld_start(SDCDriver *sdcp)
Configures and activates the SDC peripheral.
Definition: hal_sdc_lld.c:79
HAL_FAILED
#define HAL_FAILED
HAL operation failed.
Definition: hal.h:85
sdc_vmt
static const struct SDCDriverVMT sdc_vmt
Virtual methods table.
Definition: hal_sdc.c:74
BLK_DISCONNECTING
@ BLK_DISCONNECTING
Definition: hal_ioblock.h:45
hal.h
HAL subsystem header.
SDC_INIT_OCR_V20
#define SDC_INIT_OCR_V20
OCR initialization constant for V20 cards.
Definition: hal_sdc.h:100
sdcWrite
bool sdcWrite(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n)
Writes one or more blocks.
Definition: hal_sdc.c:831
sdcConnect
bool sdcConnect(SDCDriver *sdcp)
Performs the initialization procedure on the inserted card.
Definition: hal_sdc.c:617
sdc_lld_send_cmd_long_crc
bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, uint32_t *resp)
Sends an SDIO command with a long response expected and CRC.
Definition: hal_sdc_lld.c:247
MMCSD_BLOCK_SIZE
#define MMCSD_BLOCK_SIZE
Fixed block size for MMC/SD block devices.
Definition: hal_mmcsd.h:39
SDCDriver::buf
uint8_t buf[MMCSD_BLOCK_SIZE]
Buffer for internal operations.
Definition: hal_sdc_lld.h:130
sd_switch_t
sd_switch_t
SDC switch mode.
Definition: hal_sdc.c:48
mmc_detect_bus_clk
static bool mmc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk)
Reads supported bus clock and switch MMC to appropriate mode.
Definition: hal_sdc.c:373
osalSysUnlock
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition: osal.h:611
sdc_lld_read
bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n)
Reads one or more blocks.
Definition: hal_sdc_lld.c:272
MMCSD_R1_ERROR
#define MMCSD_R1_ERROR(r1)
Evaluates to true if the R1 response contains error flags.
Definition: hal_mmcsd.h:431
sdc_lld_sync
bool sdc_lld_sync(SDCDriver *sdcp)
Waits for card idle condition.
Definition: hal_sdc_lld.c:319
SDCDriver::rca
uint32_t rca
Card RCA.
Definition: hal_sdc_lld.h:126
sdc_lld_stop
void sdc_lld_stop(SDCDriver *sdcp)
Deactivates the SDC peripheral.
Definition: hal_sdc_lld.c:93
sdcErase
bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk)
Erases the supplied blocks.
Definition: hal_sdc.c:943
SDC_INIT_RETRY
#define SDC_INIT_RETRY
Number of initialization attempts before rejecting the card.
Definition: hal_sdc.h:74
sdcObjectInit
void sdcObjectInit(SDCDriver *sdcp)
Initializes the standard part of a SDCDriver structure.
Definition: hal_sdc.c:548
MMCSD_R1_STS
#define MMCSD_R1_STS(r1)
Returns the status field of an R1 response.
Definition: hal_mmcsd.h:438
SDCConfig::bus_width
sdcbusmode_t bus_width
Bus width.
Definition: hal_sdc_lld.h:83
sdc_lld_send_cmd_none
void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg)
Sends an SDIO command with no response expected.
Definition: hal_sdc_lld.c:175
SDCConfig
Driver configuration structure.
Definition: hal_sdc_lld.h:79
BLK_STOP
@ BLK_STOP
Definition: hal_ioblock.h:42
SDCDriver
Structure representing an SDC driver.
Definition: hal_sdc_lld.h:105
sdcRead
bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n)
Reads one or more blocks.
Definition: hal_sdc.c:794
BlockDeviceInfo::blk_num
uint32_t blk_num
Total number of blocks.
Definition: hal_ioblock.h:57
sdc_lld_set_bus_mode
void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode)
Switches the bus to 4 bits mode.
Definition: hal_sdc_lld.c:146
_mmcsd_get_capacity_ext
uint32_t _mmcsd_get_capacity_ext(const uint8_t *ext_csd)
Extract MMC card capacity from EXT_CSD.
Definition: hal_mmcsd.c:125
osalThreadSleepMilliseconds
#define osalThreadSleepMilliseconds(msecs)
Delays the invoking thread for the specified number of milliseconds.
Definition: osal.h:522
BlockDeviceInfo::blk_size
uint32_t blk_size
Block size in bytes.
Definition: hal_ioblock.h:56
sdcInit
void sdcInit(void)
SDC Driver initialization.
Definition: hal_sdc.c:536
sdcflags_t
uint32_t sdcflags_t
SDC Driver condition flags type.
Definition: hal_sdc_lld.h:68
sdcDisconnect
bool sdcDisconnect(SDCDriver *sdcp)
Brings the driver in a state safe for card removal.
Definition: hal_sdc.c:751
BLK_CONNECTING
@ BLK_CONNECTING
Definition: hal_ioblock.h:44
SDC_INIT_OCR
#define SDC_INIT_OCR
OCR initialization constant for non-V20 cards.
Definition: hal_sdc.h:107
HAL_SUCCESS
#define HAL_SUCCESS
HAL operation success.
Definition: hal.h:81
detect_bus_clk
static bool detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk)
Reads supported bus clock and switch card to appropriate mode.
Definition: hal_sdc.c:401
SDCDriver::errors
sdcflags_t errors
Errors flags.
Definition: hal_sdc_lld.h:122
SDCDriver::cardmode
sdcmode_t cardmode
Various flags regarding the mounted card.
Definition: hal_sdc_lld.h:118
osalDbgCheck
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:284
sdc_lld_stop_clk
void sdc_lld_stop_clk(SDCDriver *sdcp)
Stops the SDIO clock.
Definition: hal_sdc_lld.c:133
BLK_SYNCING
@ BLK_SYNCING
Definition: hal_ioblock.h:49
sdc_lld_write
bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n)
Writes one or more blocks.
Definition: hal_sdc_lld.c:297
SDCDriver::config
const _mmcsd_block_device_data SDCConfig * config
Current configuration data.
Definition: hal_sdc_lld.h:114
sdc_lld_send_cmd_short
bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, uint32_t *resp)
Sends an SDIO command with a short response expected.
Definition: hal_sdc_lld.c:197
mmc_cmd6_construct
static uint32_t mmc_cmd6_construct(mmc_switch_t access, uint32_t idx, uint32_t value, uint32_t cmd_set)
Constructs CMD6 argument for MMC.
Definition: hal_sdc.c:229
osalSysLock
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition: osal.h:601
BLK_READING
@ BLK_READING
Definition: hal_ioblock.h:47
BLK_WRITING
@ BLK_WRITING
Definition: hal_ioblock.h:48
_mmcsd_get_capacity
uint32_t _mmcsd_get_capacity(const uint32_t *csd)
Extract card capacity from a CSD.
Definition: hal_mmcsd.c:93
mmc_switch_t
mmc_switch_t
MMC switch mode.
Definition: hal_sdc.c:38
sdc_cmd6_construct
static uint32_t sdc_cmd6_construct(sd_switch_t mode, sd_switch_function_t function, uint32_t value)
Constructs CMD6 argument for SDC.
Definition: hal_sdc.c:249
sdc_init
static bool sdc_init(SDCDriver *sdcp)
Init procedure for SDC.
Definition: hal_sdc.c:181
BlockDeviceInfo
Block device info.
Definition: hal_ioblock.h:55
BLK_ACTIVE
@ BLK_ACTIVE
Definition: hal_ioblock.h:43
osalDbgAssert
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:264
sdc_detect_bus_clk
static bool sdc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk)
Reads supported bus clock and switch SDC to appropriate mode.
Definition: hal_sdc.c:319
sdcStop
void sdcStop(SDCDriver *sdcp)
Deactivates the SDC peripheral.
Definition: hal_sdc.c:587
sdc_set_bus_width
static bool sdc_set_bus_width(SDCDriver *sdcp)
Sets bus width for SDC.
Definition: hal_sdc.c:420
sdcGetAndClearErrors
sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp)
Returns the errors mask associated to the previous operation.
Definition: hal_sdc.c:861
_sdc_wait_for_transfer_state
bool _sdc_wait_for_transfer_state(SDCDriver *sdcp)
Wait for the card to complete pending operations.
Definition: hal_sdc.c:497
sdcGetInfo
bool sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip)
Returns the media info.
Definition: hal_sdc.c:916
mode_detect
static bool mode_detect(SDCDriver *sdcp)
Detects card mode.
Definition: hal_sdc.c:100
sdc_cmd6_check_status
static bool sdc_cmd6_check_status(sd_switch_function_t function, const uint8_t *buf)
Checks status after switching using CMD6.
Definition: hal_sdc.c:291
sdcbusclk_t
sdcbusclk_t
Max supported clock.
Definition: hal_sdc.h:131
sdc_lld_set_data_clk
void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk)
Sets the SDIO clock to data mode (25MHz or less).
Definition: hal_sdc_lld.c:120