ChibiOS 21.11.4
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 */
44
45/**
46 * @brief SDC switch mode.
47 */
48typedef enum {
52
53/**
54 * @brief SDC switch function.
55 */
62
63/*===========================================================================*/
64/* Driver exported variables. */
65/*===========================================================================*/
66
67/*===========================================================================*/
68/* Driver local variables and types. */
69/*===========================================================================*/
70
71/**
72 * @brief Virtual methods table.
73 */
74static 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 */
100static bool mode_detect(SDCDriver *sdcp) {
101 uint32_t resp[1];
102
103 /* V2.0 cards detection.*/
105 MMCSD_CMD8_PATTERN, resp)) {
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])) {
121 }
122 else {
124
125 /* Reset error flag illegal command.*/
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 */
144static 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) {
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 */
181static bool sdc_init(SDCDriver *sdcp) {
182 unsigned i;
183 uint32_t ocr;
184 uint32_t resp[1];
185
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) {
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 */
229static 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 */
249static 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 */
319static bool sdc_detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) {
320 uint32_t cmdarg;
321 const size_t N = 64;
322 uint8_t *tmp = sdcp->buf;
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.*/
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.*/
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.*/
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 */
373static 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 */
401static bool detect_bus_clk(SDCDriver *sdcp, sdcbusclk_t *clk) {
402
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 */
420static 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) {
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
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 */
458static 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
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 * @param[in] crc_check CRC check flag
491
492 * @return The operation status.
493 * @retval HAL_SUCCESS operation succeeded.
494 * @retval HAL_FAILED operation failed.
495 *
496 * @notapi
497 */
499 bool crc_check) {
500 uint32_t resp[1];
501 bool cmd_fail;
502
503 while (true) {
504 if (crc_check) {
505 cmd_fail = sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_SEND_STATUS, sdcp->rca, resp);
506 }
507 else {
508 cmd_fail = sdc_lld_send_cmd_short(sdcp, MMCSD_CMD_SEND_STATUS, sdcp->rca, resp);
509 }
510
511 if (cmd_fail || MMCSD_R1_ERROR(resp[0])) {
512 return HAL_FAILED;
513 }
514
515 switch (MMCSD_R1_STS(resp[0])) {
516 case MMCSD_STS_TRAN:
517 return HAL_SUCCESS;
518 case MMCSD_STS_DATA:
519 case MMCSD_STS_RCV:
520 case MMCSD_STS_PRG:
521#if SDC_NICE_WAITING == TRUE
523#endif
524 continue;
525 default:
526 /* The card should have been initialized so any other state is not
527 valid and is reported as an error.*/
528 return HAL_FAILED;
529 }
530 }
531}
532
533/*===========================================================================*/
534/* Driver exported functions. */
535/*===========================================================================*/
536
537/**
538 * @brief Wait for the card to complete pending operations with CRC check.
539 *
540 * @param[in] sdcp pointer to the @p SDCDriver object
541 *
542 * @return The operation status.
543 * @retval HAL_SUCCESS operation succeeded.
544 * @retval HAL_FAILED operation failed.
545 *
546 * @notapi
547 */
552
553/**
554 * @brief Wait for the card to complete pending operations without CRC check.
555 *
556 * @param[in] sdcp pointer to the @p SDCDriver object
557 *
558 * @return The operation status.
559 * @retval HAL_SUCCESS operation succeeded.
560 * @retval HAL_FAILED operation failed.
561 *
562 * @notapi
563 */
568
569/**
570 * @brief SDC Driver initialization.
571 * @note This function is implicitly invoked by @p halInit(), there is
572 * no need to explicitly initialize the driver.
573 *
574 * @init
575 */
576void sdcInit(void) {
577
578 sdc_lld_init();
579}
580
581/**
582 * @brief Initializes the standard part of a @p SDCDriver structure.
583 *
584 * @param[out] sdcp pointer to the @p SDCDriver object
585 *
586 * @init
587 */
589
590 sdcp->vmt = &sdc_vmt;
591 sdcp->state = BLK_STOP;
592 sdcp->errors = SDC_NO_ERROR;
593 sdcp->config = NULL;
594 sdcp->capacity = 0;
595}
596
597/**
598 * @brief Configures and activates the SDC peripheral.
599 *
600 * @param[in] sdcp pointer to the @p SDCDriver object
601 * @param[in] config pointer to the @p SDCConfig object, can be @p NULL if
602 * the driver supports a default configuration or
603 * requires no configuration
604 * @return The operation status.
605 *
606 * @api
607 */
608msg_t sdcStart(SDCDriver *sdcp, const SDCConfig *config) {
609 msg_t msg;
610
611 osalDbgCheck(sdcp != NULL);
612
613 osalSysLock();
614 osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
615 "invalid state");
616
617 sdcp->config = config;
618
619#if defined(SDC_LLD_ENHANCED_API)
620 msg = sdc_lld_start(sdcp);
621 if (msg == HAL_RET_SUCCESS) {
622 sdcp->state = BLK_ACTIVE;
623 }
624 else {
625 sdcp->state = BLK_STOP;
626 }
627#else
628 sdc_lld_start(sdcp);
629 sdcp->state = BLK_ACTIVE;
630 msg = HAL_RET_SUCCESS;
631#endif
632
634
635 return msg;
636}
637
638/**
639 * @brief Deactivates the SDC peripheral.
640 *
641 * @param[in] sdcp pointer to the @p SDCDriver object
642 *
643 * @api
644 */
645void sdcStop(SDCDriver *sdcp) {
646
647 osalDbgCheck(sdcp != NULL);
648
649 osalSysLock();
650
651 osalDbgAssert((sdcp->state == BLK_STOP) || (sdcp->state == BLK_ACTIVE),
652 "invalid state");
653
654 sdc_lld_stop(sdcp);
655 sdcp->config = NULL;
656 sdcp->state = BLK_STOP;
657
659}
660
661/**
662 * @brief Performs the initialization procedure on the inserted card.
663 * @details This function should be invoked when a card is inserted and
664 * brings the driver in the @p BLK_READY state where it is possible
665 * to perform read and write operations.
666 *
667 * @param[in] sdcp pointer to the @p SDCDriver object
668 *
669 * @return The operation status.
670 * @retval HAL_SUCCESS operation succeeded.
671 * @retval HAL_FAILED operation failed.
672 *
673 * @api
674 */
676 uint32_t resp[1];
678
679 osalDbgCheck(sdcp != NULL);
680 osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
681 "invalid state");
682
683 /* Connection procedure in progress.*/
684 sdcp->state = BLK_CONNECTING;
685
686 /* Card clock initialization.*/
687 sdc_lld_start_clk(sdcp);
688
689 /* Enforces the initial card state.*/
691
692 /* Detect card type.*/
693 if (HAL_FAILED == mode_detect(sdcp)) {
694 goto failed;
695 }
696
697 /* Perform specific initialization procedure.*/
699 if (HAL_FAILED == mmc_init(sdcp)) {
700 goto failed;
701 }
702 }
703 else {
704 if (HAL_FAILED == sdc_init(sdcp)) {
705 goto failed;
706 }
707 }
708
709 /* Reads CID.*/
710 if (sdc_lld_send_cmd_long_crc(sdcp, MMCSD_CMD_ALL_SEND_CID, 0, sdcp->cid)) {
711 goto failed;
712 }
713
714 /* Asks for the RCA.*/
716 0, &sdcp->rca)) {
717 goto failed;
718 }
719
720 /* Reads CSD.*/
722 sdcp->rca, sdcp->csd)) {
723 goto failed;
724 }
725
726 /* Selects the card for operations.*/
728 sdcp->rca, resp)) {
729 goto failed;
730 }
731
732 /* Switches to high speed.*/
733 if (detect_bus_clk(sdcp, &clk) != HAL_SUCCESS) {
734 goto failed;
735 }
736 sdc_lld_set_data_clk(sdcp, clk);
737
738 /* Not checking CRC here according to JEDEC Standard No. 84-B51 6.6.2 */
740 goto failed;
741 }
742
743
744 /* Reads extended CSD if needed and possible.*/
746
747 /* The card is a MMC, checking if it is a large device.*/
749 uint8_t *ext_csd = sdcp->buf;
750
751 if (sdc_lld_read_special(sdcp, ext_csd, 512, MMCSD_CMD_SEND_EXT_CSD, 0)) {
752 goto failed;
753 }
754
755 /* Capacity from the EXT_CSD.*/
756 sdcp->capacity = _mmcsd_get_capacity_ext(ext_csd);
757 }
758 else {
759 /* Capacity from the normal CSD.*/
760 sdcp->capacity = _mmcsd_get_capacity(sdcp->csd);
761 }
762 }
763 else {
764 /* The card is an SDC, capacity from the normal CSD.*/
765 sdcp->capacity = _mmcsd_get_capacity(sdcp->csd);
766 }
767
768 /* Block length fixed at 512 bytes.*/
770 MMCSD_BLOCK_SIZE, resp) ||
771 MMCSD_R1_ERROR(resp[0])) {
772 goto failed;
773 }
774
775 /* Switches to wide bus mode.*/
776 switch (sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) {
779 if (HAL_FAILED == sdc_set_bus_width(sdcp)) {
780 goto failed;
781 }
782 break;
784 if (mmc_set_bus_width(sdcp) == HAL_FAILED) {
785 goto failed;
786 }
787 break;
788 default:
789 /* Unknown type.*/
790 goto failed;
791 }
792
793 /* Initialization complete.*/
794 sdcp->state = BLK_READY;
795 return HAL_SUCCESS;
796
797 /* Connection failed, state reset to BLK_ACTIVE.*/
798failed:
799 sdc_lld_stop_clk(sdcp);
800 sdcp->state = BLK_ACTIVE;
801 return HAL_FAILED;
802}
803
804/**
805 * @brief Brings the driver in a state safe for card removal.
806 *
807 * @param[in] sdcp pointer to the @p SDCDriver object
808 *
809 * @return The operation status.
810 * @retval HAL_SUCCESS operation succeeded.
811 * @retval HAL_FAILED operation failed.
812 *
813 * @api
814 */
816
817 osalDbgCheck(sdcp != NULL);
818
819 osalSysLock();
820 osalDbgAssert((sdcp->state == BLK_ACTIVE) || (sdcp->state == BLK_READY),
821 "invalid state");
822 if (sdcp->state == BLK_ACTIVE) {
824 return HAL_SUCCESS;
825 }
826 sdcp->state = BLK_DISCONNECTING;
828
829 /* Waits for eventual pending operations completion.*/
831 sdc_lld_stop_clk(sdcp);
832 sdcp->state = BLK_ACTIVE;
833 return HAL_FAILED;
834 }
835
836 /* Card clock stopped.*/
837 sdc_lld_stop_clk(sdcp);
838 sdcp->state = BLK_ACTIVE;
839 return HAL_SUCCESS;
840}
841
842/**
843 * @brief Reads one or more blocks.
844 * @pre The driver must be in the @p BLK_READY state after a successful
845 * sdcConnect() invocation.
846 *
847 * @param[in] sdcp pointer to the @p SDCDriver object
848 * @param[in] startblk first block to read
849 * @param[out] buf pointer to the read buffer
850 * @param[in] n number of blocks to read
851 *
852 * @return The operation status.
853 * @retval HAL_SUCCESS operation succeeded.
854 * @retval HAL_FAILED operation failed.
855 *
856 * @api
857 */
858bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) {
859 bool status;
860
861 osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U));
862 osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
863
864 if ((startblk + n - 1U) > sdcp->capacity) {
865 sdcp->errors |= SDC_OVERFLOW_ERROR;
866 return HAL_FAILED;
867 }
868
869 /* Read operation in progress.*/
870 sdcp->state = BLK_READING;
871
872 status = sdc_lld_read(sdcp, startblk, buf, n);
873
874 /* Read operation finished.*/
875 sdcp->state = BLK_READY;
876 return status;
877}
878
879/**
880 * @brief Writes one or more blocks.
881 * @pre The driver must be in the @p BLK_READY state after a successful
882 * sdcConnect() invocation.
883 *
884 * @param[in] sdcp pointer to the @p SDCDriver object
885 * @param[in] startblk first block to write
886 * @param[out] buf pointer to the write buffer
887 * @param[in] n number of blocks to write
888 *
889 * @return The operation status.
890 * @retval HAL_SUCCESS operation succeeded.
891 * @retval HAL_FAILED operation failed.
892 *
893 * @api
894 */
895bool sdcWrite(SDCDriver *sdcp, uint32_t startblk,
896 const uint8_t *buf, uint32_t n) {
897 bool status;
898
899 osalDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0U));
900 osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
901
902 if ((startblk + n - 1U) > sdcp->capacity) {
903 sdcp->errors |= SDC_OVERFLOW_ERROR;
904 return HAL_FAILED;
905 }
906
907 /* Write operation in progress.*/
908 sdcp->state = BLK_WRITING;
909
910 status = sdc_lld_write(sdcp, startblk, buf, n);
911
912 /* Write operation finished.*/
913 sdcp->state = BLK_READY;
914 return status;
915}
916
917/**
918 * @brief Returns the errors mask associated to the previous operation.
919 *
920 * @param[in] sdcp pointer to the @p SDCDriver object
921 * @return The errors mask.
922 *
923 * @api
924 */
926 sdcflags_t flags;
927
928 osalDbgCheck(sdcp != NULL);
929 osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
930
931 osalSysLock();
932 flags = sdcp->errors;
933 sdcp->errors = SDC_NO_ERROR;
935 return flags;
936}
937
938/**
939 * @brief Waits for card idle condition.
940 *
941 * @param[in] sdcp pointer to the @p SDCDriver object
942 *
943 * @return The operation status.
944 * @retval HAL_SUCCESS the operation succeeded.
945 * @retval HAL_FAILED the operation failed.
946 *
947 * @api
948 */
949bool sdcSync(SDCDriver *sdcp) {
950 bool result;
951
952 osalDbgCheck(sdcp != NULL);
953
954 if (sdcp->state != BLK_READY) {
955 return HAL_FAILED;
956 }
957
958 /* Synchronization operation in progress.*/
959 sdcp->state = BLK_SYNCING;
960
961 result = sdc_lld_sync(sdcp);
962
963 /* Synchronization operation finished.*/
964 sdcp->state = BLK_READY;
965 return result;
966}
967
968/**
969 * @brief Returns the media info.
970 *
971 * @param[in] sdcp pointer to the @p SDCDriver object
972 * @param[out] bdip pointer to a @p BlockDeviceInfo structure
973 *
974 * @return The operation status.
975 * @retval HAL_SUCCESS the operation succeeded.
976 * @retval HAL_FAILED the operation failed.
977 *
978 * @api
979 */
981
982 osalDbgCheck((sdcp != NULL) && (bdip != NULL));
983
984 if (sdcp->state != BLK_READY) {
985 return HAL_FAILED;
986 }
987
988 bdip->blk_num = sdcp->capacity;
990
991 return HAL_SUCCESS;
992}
993
994/**
995 * @brief Erases the supplied blocks.
996 *
997 * @param[in] sdcp pointer to the @p SDCDriver object
998 * @param[in] startblk starting block number
999 * @param[in] endblk ending block number
1000 *
1001 * @return The operation status.
1002 * @retval HAL_SUCCESS the operation succeeded.
1003 * @retval HAL_FAILED the operation failed.
1004 *
1005 * @api
1006 */
1007bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk) {
1008 uint32_t resp[1];
1009
1010 osalDbgCheck((sdcp != NULL));
1011 osalDbgAssert(sdcp->state == BLK_READY, "invalid state");
1012
1013 /* Erase operation in progress.*/
1014 sdcp->state = BLK_WRITING;
1015
1016 /* Handling command differences between HC and normal cards.*/
1017 if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0U) {
1018 startblk *= MMCSD_BLOCK_SIZE;
1019 endblk *= MMCSD_BLOCK_SIZE;
1020 }
1021
1022 if (_sdc_wait_for_transfer_state(sdcp)) {
1023 goto failed;
1024 }
1025
1027 startblk, resp) != HAL_SUCCESS) ||
1028 MMCSD_R1_ERROR(resp[0])) {
1029 goto failed;
1030 }
1031
1033 endblk, resp) != HAL_SUCCESS) ||
1034 MMCSD_R1_ERROR(resp[0])) {
1035 goto failed;
1036 }
1037
1039 0, resp) != HAL_SUCCESS) ||
1040 MMCSD_R1_ERROR(resp[0])) {
1041 goto failed;
1042 }
1043
1044 /* Quick sleep to allow it to transition to programming or receiving state */
1045 /* CHTODO: ??????????????????????????? */
1046
1047 /* Wait for it to return to transfer state to indicate it has finished erasing */
1048 if (_sdc_wait_for_transfer_state(sdcp)) {
1049 goto failed;
1050 }
1051
1052 sdcp->state = BLK_READY;
1053 return HAL_SUCCESS;
1054
1055failed:
1056 sdcp->state = BLK_READY;
1057 return HAL_FAILED;
1058}
1059
1060#endif /* HAL_USE_SDC == TRUE */
1061
1062/** @} */
1063
#define HAL_RET_SUCCESS
Definition hal.h:93
#define HAL_SUCCESS
HAL operation success.
Definition hal.h:81
#define HAL_FAILED
HAL operation failed.
Definition hal.h:86
@ BLK_WRITING
Definition hal_ioblock.h:48
@ BLK_STOP
Definition hal_ioblock.h:42
@ BLK_CONNECTING
Definition hal_ioblock.h:44
@ BLK_READY
Definition hal_ioblock.h:46
@ BLK_DISCONNECTING
Definition hal_ioblock.h:45
@ BLK_READING
Definition hal_ioblock.h:47
@ BLK_SYNCING
Definition hal_ioblock.h:49
@ BLK_ACTIVE
Definition hal_ioblock.h:43
#define MMCSD_CMD_ERASE_RW_BLK_END
Definition hal_mmcsd.h:91
#define MMCSD_CMD_INIT
Definition hal_mmcsd.h:71
#define MMCSD_R1_ERROR(r1)
Evaluates to true if the R1 response contains error flags.
Definition hal_mmcsd.h:432
#define MMCSD_CMD_SEND_EXT_CSD
Definition hal_mmcsd.h:79
#define MMCSD_CSD_MMC_CSD_STRUCTURE_SLICE
Definition hal_mmcsd.h:104
#define MMCSD_CMD_SWITCH
Definition hal_mmcsd.h:76
#define MMCSD_STS_RCV
Definition hal_mmcsd.h:61
#define MMCSD_CMD_APP_OP_COND
Definition hal_mmcsd.h:93
#define MMCSD_STS_DATA
Definition hal_mmcsd.h:60
#define MMCSD_R1_STS(r1)
Returns the status field of an R1 response.
Definition hal_mmcsd.h:439
#define MMCSD_STS_PRG
Definition hal_mmcsd.h:62
#define MMCSD_CMD_SEND_STATUS
Definition hal_mmcsd.h:83
#define MMCSD_CMD_ERASE
Definition hal_mmcsd.h:92
#define MMCSD_STS_TRAN
Definition hal_mmcsd.h:59
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
#define MMCSD_CMD_SEND_RELATIVE_ADDR
Definition hal_mmcsd.h:73
#define MMCSD_CMD_APP_CMD
Definition hal_mmcsd.h:95
#define MMCSD_CMD_SET_BUS_WIDTH
Definition hal_mmcsd.h:75
uint32_t _mmcsd_get_capacity(const uint32_t *csd)
Extract card capacity from a CSD.
Definition hal_mmcsd.c:93
#define MMCSD_CMD8_PATTERN
Fixed pattern for CMD8.
Definition hal_mmcsd.h:49
#define MMCSD_BLOCK_SIZE
Fixed block size for MMC/SD block devices.
Definition hal_mmcsd.h:39
#define MMCSD_CMD_SEND_CSD
Definition hal_mmcsd.h:80
#define MMCSD_CMD_SEND_IF_COND
Definition hal_mmcsd.h:78
#define MMCSD_CMD_SET_BLOCKLEN
Definition hal_mmcsd.h:84
#define MMCSD_CMD_ALL_SEND_CID
Definition hal_mmcsd.h:72
uint32_t _mmcsd_get_capacity_ext(const uint8_t *ext_csd)
Extract MMC card capacity from EXT_CSD.
Definition hal_mmcsd.c:125
#define MMCSD_CMD_GO_IDLE_STATE
Definition hal_mmcsd.h:70
#define MMCSD_CSD_10_CSD_STRUCTURE_SLICE
Definition hal_mmcsd.h:193
#define MMCSD_CMD_SEL_DESEL_CARD
Definition hal_mmcsd.h:77
#define MMCSD_CMD_ERASE_RW_BLK_START
Definition hal_mmcsd.h:90
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalThreadSleepMilliseconds(msecs)
Delays the invoking thread for the specified number of milliseconds.
Definition osal.h:522
void sdcObjectInit(SDCDriver *sdcp)
Initializes the standard part of a SDCDriver structure.
Definition hal_sdc.c:588
bool sdc_lld_is_write_protected(SDCDriver *sdcp)
#define SDC_NO_ERROR
Definition hal_sdc.h:49
void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk)
Sets the SDIO clock to data mode (25MHz or less).
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
void sdcStop(SDCDriver *sdcp)
Deactivates the SDC peripheral.
Definition hal_sdc.c:645
#define SDC_OVERFLOW_ERROR
Definition hal_sdc.h:57
bool sdc_lld_sync(SDCDriver *sdcp)
Waits for card idle condition.
void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg)
Sends an SDIO command with no response expected.
static bool sdc_init(SDCDriver *sdcp)
Init procedure for SDC.
Definition hal_sdc.c:181
void sdc_lld_stop_clk(SDCDriver *sdcp)
Stops the SDIO clock.
bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n)
Reads one or more blocks.
msg_t sdcStart(SDCDriver *sdcp, const SDCConfig *config)
Configures and activates the SDC peripheral.
Definition hal_sdc.c:608
#define SDC_MODE_CARDTYPE_MASK
Definition hal_sdc.h:38
#define SDC_INIT_OCR_V20
OCR initialization constant for V20 cards.
Definition hal_sdc.h:100
#define SDC_MODE_CARDTYPE_MMC
Definition hal_sdc.h:41
bool sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n)
Reads one or more blocks.
Definition hal_sdc.c:858
bool sdcConnect(SDCDriver *sdcp)
Performs the initialization procedure on the inserted card.
Definition hal_sdc.c:675
bool sdcWrite(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n)
Writes one or more blocks.
Definition hal_sdc.c:895
void sdc_lld_stop(SDCDriver *sdcp)
Deactivates the SDC peripheral.
Definition hal_sdc_lld.c:93
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
#define SDC_MODE_CARDTYPE_SDV11
Definition hal_sdc.h:39
static bool mmc_set_bus_width(SDCDriver *sdcp)
Sets bus width for MMC.
Definition hal_sdc.c:458
static bool mmc_init(SDCDriver *sdcp)
Init procedure for MMC.
Definition hal_sdc.c:144
#define SDC_INIT_OCR
OCR initialization constant for non-V20 cards.
Definition hal_sdc.h:107
#define SDC_MODE_CARDTYPE_SDV20
Definition hal_sdc.h:40
void sdc_lld_start(SDCDriver *sdcp)
Configures and activates the SDC peripheral.
Definition hal_sdc_lld.c:79
bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, uint8_t cmd, uint32_t argument)
#define SDC_MODE_HIGH_CAPACITY
Definition hal_sdc.h:42
bool sdcDisconnect(SDCDriver *sdcp)
Brings the driver in a state safe for card removal.
Definition hal_sdc.c:815
static bool sdc_set_bus_width(SDCDriver *sdcp)
Sets bus width for SDC.
Definition hal_sdc.c:420
#define SDC_INIT_RETRY
Number of initialization attempts before rejecting the card.
Definition hal_sdc.h:74
bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n)
Writes one or more blocks.
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
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.
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.
sdcbusclk_t
Max supported clock.
Definition hal_sdc.h:131
static bool mode_detect(SDCDriver *sdcp)
Detects card mode.
Definition hal_sdc.c:100
void sdcInit(void)
SDC Driver initialization.
Definition hal_sdc.c:576
void sdc_lld_start_clk(SDCDriver *sdcp)
Starts the SDIO clock and sets it to init mode (400kHz or less).
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
sdcflags_t sdcGetAndClearErrors(SDCDriver *sdcp)
Returns the errors mask associated to the previous operation.
Definition hal_sdc.c:925
void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode)
Switches the bus to 4 bits mode.
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
bool _sdc_wait_for_transfer_state(SDCDriver *sdcp)
Wait for the card to complete pending operations with CRC check.
Definition hal_sdc.c:548
static const struct SDCDriverVMT sdc_vmt
Virtual methods table.
Definition hal_sdc.c:74
void sdc_lld_init(void)
Low level SDC driver initialization.
Definition hal_sdc_lld.c:65
sd_switch_t
SDC switch mode.
Definition hal_sdc.c:48
sd_switch_function_t
SDC switch function.
Definition hal_sdc.c:56
bool sdcSync(SDCDriver *sdcp)
Waits for card idle condition.
Definition hal_sdc.c:949
static bool _sdc_wait_for_transfer_state_internal(SDCDriver *sdcp, bool crc_check)
Wait for the card to complete pending operations.
Definition hal_sdc.c:498
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.
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
bool sdc_lld_is_card_inserted(SDCDriver *sdcp)
mmc_switch_t
MMC switch mode.
Definition hal_sdc.c:38
uint32_t sdcflags_t
SDC Driver condition flags type.
Definition hal_sdc_lld.h:68
bool _sdc_wait_for_transfer_state_nocrc(SDCDriver *sdcp)
Wait for the card to complete pending operations without CRC check.
Definition hal_sdc.c:564
bool sdcGetInfo(SDCDriver *sdcp, BlockDeviceInfo *bdip)
Returns the media info.
Definition hal_sdc.c:980
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
bool sdcErase(SDCDriver *sdcp, uint32_t startblk, uint32_t endblk)
Erases the supplied blocks.
Definition hal_sdc.c:1007
@ SDC_MODE_4BIT
Definition hal_sdc.h:124
@ SDC_MODE_1BIT
Definition hal_sdc.h:123
@ SDC_MODE_8BIT
Definition hal_sdc.h:125
@ SDC_CLK_50MHz
Definition hal_sdc.h:133
@ SDC_CLK_25MHz
Definition hal_sdc.h:132
@ SD_SWITCH_SET
Definition hal_sdc.c:50
@ SD_SWITCH_CHECK
Definition hal_sdc.c:49
@ SD_SWITCH_FUNCTION_DRIVER_STRENGTH
Definition hal_sdc.c:59
@ SD_SWITCH_FUNCTION_CURRENT_LIMIT
Definition hal_sdc.c:60
@ SD_SWITCH_FUNCTION_SPEED
Definition hal_sdc.c:57
@ SD_SWITCH_FUNCTION_CMD_SYSTEM
Definition hal_sdc.c:58
@ MMC_SWITCH_SET_BITS
Definition hal_sdc.c:40
@ MMC_SWITCH_CLEAR_BITS
Definition hal_sdc.c:41
@ MMC_SWITCH_WRITE_BYTE
Definition hal_sdc.c:42
@ MMC_SWITCH_COMMAND_SET
Definition hal_sdc.c:39
int32_t msg_t
Definition chearly.h:88
HAL subsystem header.
Block device info.
Definition hal_ioblock.h:55
uint32_t blk_num
Total number of blocks.
Definition hal_ioblock.h:57
uint32_t blk_size
Block size in bytes.
Definition hal_ioblock.h:56
Driver configuration structure.
Definition hal_sdc_lld.h:79
sdcbusmode_t bus_width
Bus width.
Definition hal_sdc_lld.h:83
Structure representing an SDC driver.
sdcmode_t cardmode
Various flags regarding the mounted card.
_mmcsd_block_device_data const SDCConfig * config
Current configuration data.
uint8_t buf[MMCSD_BLOCK_SIZE]
Buffer for internal operations.
uint32_t rca
Card RCA.
const struct SDCDriverVMT * vmt
Virtual Methods Table.
sdcflags_t errors
Errors flags.
SDCDriver virtual methods table.
Definition hal_sdc_lld.h:98