В этом тексте я написал про некоторые особенности работ c SD картами при соединении их с микроконтроллером по интерфейсу SPI. Прежде чем двигаться дальше надо вспомнить следующие определения.
Блок - массив фиксированного размера
Big-Endian (network byte order, Motorola byte order) - порядок следования байт от старшего к младшему. Естественный для человека порядок байт.
Little-endian (intel byte order)- Порядок байт от младшего к старшему.

Что надо из оборудования?

Оборудование

Назначение

Множество SD карт

128 МByte; 2GByte и т.п.

Отладочная плата с микроконтроллером

МК будет мастером SPI

Перемычки

для соединения SD карты и микроконтроллера по SPI

Осциллограф

Для отладки тактирования и сигналов

DMM

Для прозвонки пинов, проверки заземления.

USB-A-USB mini кабуль

Чтобы запрограммировать отладочную плату и получить виртуальный последовательный порт.

Подготовительная работа

Прежде чем пользоваться SD картой её следует проверить на факт подделки. Для этого есть утилита H2testw.exe. Скачать H2testw можно по ссылке https://www.softportal.com/getsoft-45617-h2testw-1.html
Эта
утилита не стирает данные с карты. Эта утилита по частям пишет 1MByte, читает 1MByte и проверяет прочитанное с записанным. И так по всей памяти.

утилита H2testw проверяет SD карту
утилита H2testw проверяет SD карту

Утилита H2testw проверяет SD карту в случае успеха утилита выдает строку Test finished without errors. Тут же есть отчет по битовой скорости записи и чтения.

На самой карте появятся серия здоровенных бинарных файлов *.h2w по гигабайту каждый, которые можно удалить вручную после отработки утилиты H2testw

Также вам понадобится утилита для правильного форматирования SD карт. Называется утилита SD Memory Card Formatter for Windows/Mac. Скачать ее можно тут https://www.sdcard.org/downloads/formatter/

Для чего используют SD карты в программировании микроконтроллеров?

Функция

1

Логирование на SD карту. Черный ящик. Сохранение лога загрузки. Сохранение отладочных логов во время работы устройства.

2

Обновление прошивки с SD карты

3

Конфигурирование прошивки параметрами с SD карты

4

Сохранение показаний датчиков

5

Хранение аудиофайлов для воспроизведения на DAC чипах

6

Сбор статистики для последующего анализа случайной величины (показания датчика).

7

Запись потокового видео с цифровых камер.

8

Хранение конфигурационных данных

9

Хранение паролей

10

Хранение калибровочных данных

11

Вы можете организовать NVRAM прямо на SD карте. Хранить именованные бинарные массивы как бинарные файлы в файловой системе. Контроллер SD карты сам будет заботиться о равномерном износе гектаров flash NAND, а ваша прошивка будет оставаться простой и лаконичной.

Бывает возникает ситуация, когда на микроконтроллере надо прочитать файл из SD карты и при этом на плате топология такова, что интерфейс SDIO банально не выведен на разъём. Примером тому плата STM32 MINI-F4. Спасением может быть подключение SD карты по SPI. SPI настолько прост, что его можно вообще запрограммировать на основе драйвера GPIO и таймера. В режиме SPI данные из SD-карты можно извлечь или прописать при помощи всего 6 проводов и микроконтроллера.

Что надо из доков?

Название

Содержание

pages

SD Specification Part 1 Physical Layer Simplified Specification Version 6.00

Это инструкция того как пользоваться SD картой. Список команд, схемы алгоритмов, детализация регистров.

263

даташит на микроконтроллер

Схемотехника

Рассмотрим блок-схему SD- карты памяти. Выглядит как обычная микросхема с 8 пинами. Внутри же гектары засаженные NAND flash памятью, отдельный микроконтроллер, который следит за равномерностью износа NAND памяти, SPI трансивер, SDIO трансивер и конфигурационные регистры.

блок-схема SD карты
блок-схема SD карты

Распиновка SD карты очень проста и лаконична.

Алгоритмы работы с SD картой
С точки зрения программиста SD карта выглядит как-то так.

Настройки режима SPI

Биты захватывать надо по положительному перепаду на проводе CLK. В режиме idle на SCLK должно быть напряжение 0 Вольт. В пределах байта биты следует передавать старшим битом вперед MSB. Инициализацию следует делать на битовой част��те в пределах от до 300 kHz. Вот такими должны быть осциллограммы для работы с SD картой в режиме SPI.

Структура SPI пакета

Для записи команд в SD карту надо посылать 6-ти байтные пакеты. Данные передаются младшим битом вперед. Старшим байтом вперед.

Регистры

У каждой SD карты есть 8 регистров.

Акроним

байт

CMD

Описание

CID

16

CMD10

Card IDentification

CSD

16

CMD9

Card Specific Data

OCR

4

CMD58

Operation Condition

SSR

64

SD Status Register

CSR

4

CMD13?

Card Status Register

Если коротко, то вот 5 основных регистров SD карты.

Как можно заметить, CMD13 пере используется для чтения двух регистров: SSR и CSR.

Алгоритм инициализации

Чтобы SD карта завелась надо выполнить следующие шаги.

--Подать питание. Для начала 3.3V.
--Перейти в режим SPI
--Выполнить программный сброс
--Установить настройки напряжения
--Запустить процедуру внутренней инициализации
--Задать размер блока (512 байт)
--Снять блокировку

Графически это можно показать так.

Чтение массива из SD карты

Чтение памяти производится блоками по 512 байт. Для чтение блока существует команда CMD17. После отправки команды чтения надо ожидать ответного токена 0xFE. Затем из карты можно выгрести массив с CRC16.

Запись блока в SD карту

Запись блока производится командой CMD24.

Чтение регистра CSD

Системный вызов ioctrl потребует чтение регистра CSD

Вот результат чтения регистра CSD из реальной 2GBYTE SD карты.

Это же, только в тексте

->
->ll sdcard debug; sd_read_csd
 I,[SYS] Spot 46=SdCard
 I,[SdCard] Read,Reg,CSD,16byte..
 D,[SdCard] SendNoneStd,CMD9,Arg:0x00000000
 D,[SdCard] Send,CMD9=0x09=[SEND_CSD],Arg:0x00000000
 D,[SdCard] WaitReady..
 D,[SdCard] BusSpareAfter 0 ByteOfJunk, 0 Zeros
 D,[SdCard] SendFrame,CMD9=0x09=[SEND_CSD],Arg:0x00000000,CRC7:0x57
 D,[SdCard] Write:4900000000AF
 D,[SdCard] SendFrame,Ok
 D,[SdCard] ReadUntil:0xFE
 D,[SdCard] ReadData:16 Byte
 D,[SdCard] Data:007F00325B5A83A0F6DBFF87168000E9,CRC16Read 0x00c7 CRC16Calc 0x00c7
 I,[SdCard] ReadCSDok
e900801687ffdbf6a0835a5b32007f00
 W,[SdCard] Parse CSD
 W,[SdCard] Parse CSD V1
 I,[SdCard] CSD_STRUCT: 0=CSD Version 1.0
 I,[SdCard] C_SIZE 3715
 I,[SdCard] C_SIZE_MULT 7
 I,[SdCard] CardCommandClasses 1461
 I,[SdCard] Crc 116
 I,[SdCard] READ_BL_LEN 10
 I,[SdCard] EraseSectorSize 127
 W,[SdCard] MemoryCapacity 1948254208
 I,[SdCard] BlockNumber 1902592
 I,[SdCard] BlockLen 1024
 I,[SdCard] MULT 512
-->
-->

Чтение регистра CID

Биты регистра CID выдаются старшим байтом вперед.

Поэтому на ARM Cortex-M вам придется инвертировать порядок байт для корректного заполнения битового поря.

Вот результат чтения регистра CID из реальной 2GBYTE SD карты. Как вычислять CRC7 я так и не понял. В спеке про это явно не указано.

или так в текстовом виде.

-->
-->sdc 0x0a 0 512
 I,[SdCard] Sd_sendCommand,cmd:0x0a,arg:0x00000000,RxSize:0x200
FF00FFFE9F5449303030303000000000580154FFC954FFFFFFFFFFFFFFFFFFFF
FF00FFFE 9F5449303030303000000000580154FF C954 FFFFFFFFFFFFFFFFFFFF
-->sdrcid
 I,[SdCard] ReadCID..
 D,[SdCard] SendNoneStd,CMD10,Arg:0x00000000
 D,[SdCard] Send,CMD10=0x0a=[SEND_CID],Arg:0x00000000
 D,[SdCard] WaitReady..
 D,[SdCard] BusSpareAfter 0 ByteOfJunk, 0 Zeros
 D,[SdCard] SendFrame,CMD10=0x0a=[ASK_CID],Arg:0x00000000,CRC7:0x0d
 D,[SdCard] Write:4A000000001B
 D,[SdCard] SendFrame,Ok
 D,[SdCard] ReadUntil:0xFE
 D,[SdCard] ReadData:16 Byte
 D,[SdCard] Data:9F5449303030303000000000580154FF,CRC16Read 0xc954
 D,[SdCard] CRC16Calc 0xc954
 I,[SdCard] ReadCIDok
 W,[SdCard] Parse,CardIdentification(CID)
 I,[SdCard] CRC7:Read:0x7f,Calc:0x6b
 W,[SdCard] isValid:0
ff54015800000000303030303049549f
 I,[SdCard] CRC7: 0x7f
 I,[SdCard] ManufDate 0x0154=April,2021
 I,[SdCard] SerialNum: 0x00000058
 I,[SdCard] Revision 0x00
ProdName: 3030303030     |00000|
I,[SdCard] AppId: 0x5449
I,[SdCard] ManufId 0x9f=FAIS_ON
-->

Чтение статусного регистра Card Status Register (CSR)

CSR это 4х байтовый регистр. Читается командой CMD13. Вот его типичное значение: 0x0000FFFF.

-->
--> sdc 13 0 512
 I,[SdCard] Sd_sendCommand,cmd:0x0d,arg:0x00000000,RxSize:0x200
FF0000FFFFFFFFFFF

Чтение регистра SD Status Register (SSR)

SSR - это самый циклопический регистр в SD карте: размером 64 байта. Читается тандемной командой CMD55 + CMD13.

Детализация в его битовых полей изложена в таблице 4-44 SD Status. Из полезного там указан класс производительности карты, разрядность шины данных, режим безопасности, размер защищенной области.

Лог чтения регистра SD Status (SSR)

-->
--> ll sdcard debug; sdrssr
 I,[SYS] Spot 46=SdCard
-->I,[SdCard]
TryToSwToAppSpecificCmd,ExpRx:0x00
[SdCard] Send,CMD55=0x37=[APP_CMD],Arg:0x00000000
[SdCard] WaitReady..
[SdCard] BusSpareAfter 0 ByteOfJunk, 0 Zeros
[SdCard] SendFrame,CMD55=0x37=[APP_CMD],Arg:0x00000000,CRC7:0x32
[SdCard] Write:77 00000000 65
[SdCard] SendFrame,Ok
[SdCard] ReadUntil:0x00
[SdCard] AppSpecificSwitchOk
[SdCard] SendNoneStd,CMD13,Arg:0x00000000
[SdCard] Send,CMD13=0x0d=[SEND_STATUS],Arg:0x00000000
[SdCard] WaitReady..
[SdCard] BusSpareAfter 0 ByteOfJunk, 0 Zeros
[SdCard] SendFrame,CMD13=0x0d=[SEND_STATUS],Arg:0x00000000,CRC7:0x06
[SdCard] Write:4D 00000000 0D
[SdCard] SendFrame,Ok
[SdCard] ReadUntil:0xFE
[SdCard] ReadData:64 Byte
[SdCard] 
Data:
000000000000002803039000080A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
         CRC16Read 0x60c4
[SdCard] CRC16Calc 0x60c4
000000000000002803039000080A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
10:57:49,1Jan2000-->
10:57:50,1Jan2000-->

Чтение регистра OCR (Operating Condition Register)
В SD карте есть 32 битный регистр. Запрашивается командой CMD58.

Этот регистр явно показывает каким напряжением можно запитывать микросхему. Биты с 15 по 25 просто набирают собой нужный интервал с шагом 0,1 Вольт.

Читается регистр OCR вот такой осциллограммой.

На реальной SD карте прочиталось значение 0x0080ff80. Это значит, что карта может работать в интервале 2.7 V ... 3.6V

То же в тексте

-->
sdrocr
W,[SdCard] ParseOCR:0x80ff8000=0b1000_0000|1111_1111|1000_0000|0000_0000
0080ff80
I,[SdCard] UHS II 0
I,[SdCard] VoltageWindow:2.7-2.8,Volts
I,[SdCard] VoltageWindow:2.8-2.9,Volts
I,[SdCard] VoltageWindow:2.9-3.0,Volts
I,[SdCard] VoltageWindow:3.0-3.1,Volts
I,[SdCard] VoltageWindow:3.1-3.2,Volts
I,[SdCard] VoltageWindow:3.2-3.3,Volts
I,[SdCard] VoltageWindow:3.3-3.4,Volts
I,[SdCard] VoltageWindow:3.4-3.5,Volts
I,[SdCard] VoltageWindow:3.5-3.6,Volts
I,[SdCard] CCS 0
I,[SdCard] CardPowerUpStatus: 1
-->
-->
--> sdc 58 0 400
 D,[SdCard] Send,CMD58=0x3a=[READ_OCR],Arg:0x00000000
 D,[SdCard] WaitReady..
 D,[SdCard] BusSpareAfter 0 ByteOfJunk, 0 Zeros
 D,[SdCard] SendFrame,CMD58=0x3a=[READ_OCR],Arg:0x00000000,CRC7:0x7e
 D,[SdCard] Write:7A00000000FD
 D,[SdCard] SendFrame,Ok
 I,[SdCard] Sd_sendCommand,cmd:0x3a,arg:0x00000000,RxSize:400
ff0080ff8000fffffff
ff00 80ff8000 fffffff

Особенности при работе в SD картами:

1--В SPI за один такт SCLK одновременно принимается и передается один бит информации. Оказывается, что если при чтении ответа от SD-карты случайно послать по SPI что-то отличное от 0xFF, то большинство SD-карт ведут себя абсолютно непредсказуемо! Поэтому прием данных от карты следует производить с одновременной записью в них 0xFF. По сути работа с SD картой в режиме SPI требует полнодуплексного режима.

2--Все провода SPI кроме SCKL должны быть подтянуты к питанию.

3--При чтении и записи блоков надо указывать адрес блока в байтах. То есть первый блок будет иметь адрес 512, второй 1024 и так далее (1536; 2048; 2560 ...).

4--При подаче питания SD-карта может быть залочена. Надо её разблокировать командой CMD42.

6--Если функция f_mount возвращает FR_NO_FILESYSTEM, а при этом тесты SD-SPI проходят, то это значит, что надо отформатировать SD-карту прямо на микроконтроллере функцией f_mkfs().

7--Некоторые команды не являются атомарными (CMD13; CMD41). Для выполнения одного действия надо выполнить не одну а две команды. Первая это CMD55. CMD55 приказывает переключиться в режим работы с нестандартными командами.

8--Чтобы работать с SD картой в вашем репозитории должны быть такие программные компоненты как GPIO, SPI, RTC, FAT-FS. Плюс базовое API для работы с массивами (инвертирование порядка байт).

Проверка на реальных SD картах

Как вы уже могли заметить, отладку алгоритмов работы с SD картами я проводил через текстовый shell работающей поверх UART. Это позволяет проверять множество разных тестировочных операций без пересборки и перепрошивки всего проекта. Всё можно проверить во время исполнения прошивки.

Отмечу сразу, что не все SD карты, что у меня были заработали. Бывают ситуации, когда MCU видит файловую систему, а операционная система не видит. Или наоборот. Однако вот на одной SD-карте у меня была достигнута совместимость между микроконтроллером и PC. На ней была файловая система FAT16. Если прочитать регистры, то про эту карту можно узнать следующие данные.

ManufDate 0x0154 April 2021, Revision 0x00, ManufId 0x9f=Undef MID, AppId: 0x5449, CSD_STRUCT: 0=CSD Version 1.0, C_SIZE 3715, C_SIZE_MULT 7, CardCommandClasses 1461, READ_BL_LEN 10, EraseSectorSize 127, MemoryCapacity 1948254208, BlockNumber 1902592, ProdName: 0х3030303030 , BlockLen 1024, MULT 512, UHS II 0, SwTo 1.8V 0, CCS 0

Вот параметры еще одной реальной работающей SD карты: ManufDate 0x00aa October 2010, Revision 0x60, ProdName: 0x5344303247 |SD02G|, AppId: 0x544d, ManufId 0x02=Toshiba, CSD_STRUCT: 0=CSD Version 1.0, C_SIZE 3751, C_SIZE_MULT 7, CardCommandClasses 1461, READ_BL_LEN 10, EraseSectorSize 127, MemoryCapacity 1967128576, BlockNumber 1921024, BlockLen 1024, MULT 512, UHS II 0, SwTo 1.8V 0, CCS 0, CardPowerUpStatus: 0, Lock Off,

Согласно моим экспериментам с разными SD картами получается так, что Fat FS с доступом по SPI работает только с SD картами емкостью до 2 GByte.

Модульные тесты для SD карты
Какими могут быть модульные тесты для SD карты?

--Прежде всего можно проверить размер базовых битовых полей, которые фигурируют в драйвере SD карты.

--Можно попробовать прочитать любой блок и проверить CRC16

--Можно определить какой-нибудь блок, прописать его, прочитать, проверить что записанное и прочитанное совпало.

Достоинства работы с SD картой по SPI

1) Интерфейс SPI проще отлаживать, чем интерфейс SDIO. При работе в режиме SDIO SD карты порой зависают при чтении или записи и прошивка бесконечно вызывает прерывания снова и снова. Контролировать SD карту в режиме SPI это более надежное решение.
2) SPI можно реализовать даже на GPIO в купе с аппаратными таймерами.

Недостатки SD карт
1) Рваные регистры. То есть каждый регистр SD карты имеет разный размер и разный способ его чтения. Это только пере усложняет драйверы работы с SD картами.
2) Ограничение по скорости записи и чтения данных.
3) В регистрах карты (например OCR) не хватает контрольных константных битовых полей для проверки правильности порядка байт при чтении и для составления модульных тестов. При этом там десятки зарезервированных впустую битов.

Итоги
Удалось научится подключать SD карту к микроконтроллеру по интерфейсу SPI, читать писать блоки в память и вычитывать внутренние регистры микросхемы (CID, CSD, CSR, SSR).

Конечно же SD карты более сложны, чем изложено в тексте. Однако я указал базовые моменты работы SD картами. Далее можно только увеличивать производительность обмена и настаивать режимы безопасности хранения информации.

Сокращение

Значение

SD

Secure Digital

SSR

SD Status register

CSR

Card Status Register

MSB

most significant bit

MOSI

Master Out Slave In

MISO

Master In Slave Out

ECC

Error Correction Code

CSD

Card Specific Data Register

SPI

Serial Peripheral Interface

DSR

Driver Stage Register

NRС

command response time (0 to 8 bytes for SDC)

OCR

Operating Condition Register

MMC

MultiMedia Card

SDIO

SD I/O

CID

Card IDentification register

SDSC

SD Standart Capacity Memory Card

SDHC

SD High Capacity Memory Card

SDXC

SD Extended Capacity

HCS

Host Capacity Support

Источники

Название

URL

FatFs - Generic FAT Filesystem Module

http://elm-chan.org/fsw/ff/00index_e.html

Работа с SD картой. Подключение к микроконтроллеру. Ч1

https://chipenable.ru/index.php/programming-avr/209-rabota-s-sd-kartoy-podklyuchenie-k-mikrokontrolleru-ch1.html

Работа с SD картой. Библиотека Petit FatFs. Ч2

https://chipenable.ru/index.php/programming-avr/211-rabota-s-sd-kartoy-biblioteka-petit-fatfs-ch2.html

How to Use MMC/SDC

http://elm-chan.org/docs/mmc/mmc_e.html

Учимся работать с SDHC/SDXC-картами по протоколу SPI

https://eax.me/stm32-sdcard/

SD Memory Card Formatter for Windows/Mac

https://www.sdcard.org/downloads/formatter/

Учимся работать с SDHC/SDXC-картами по протоколу SPI

https://eax.me/stm32-sdcard/

SD card responds with illegal command (0x04) when I send Write_Block (or Read_Block)

https://electronics.stackexchange.com/questions/309478/sd-card-responds-with-illegal-command-0x04-when-i-send-write-block-or-read-bl

Krasutski-zz/ sdcard_spi_driver

https://github.com/Krasutski-zz/sdcard_spi_driver/blob/master/spi_sdcard_driver.c

Как определить поддельную Micro SD флеш карту @nochkin

https://habr.com/ru/articles/367655/

Как использовать карты памяти MMC/SDC

https://microsin.net/programming/file-systems/howto-use-mmc-sdc.html

Работа с SD-картой по интерфейсу SPI. Реализация на VHDL @Fenja

https://habr.com/ru/articles/495400/

В этом реестре я перечислил все команды SD карт в SPI режиме и их свойства.

https://docs.google.com/spreadsheets/d/1bgMdlLLMcUmSmdP2YYg3L84dLlPY4j7P-vAtlKooMQk/edit#gid=423674399

Медленная работа SD карточек — кто виноват и что делать? @GarryC

https://habr.com/ru/articles/220433/

SD Memory Card Formatter 5.0.2 for SD/SDHC/SDXC

https://www.sdcard.org/downloads/formatter/

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Вы программировали SD карты микроконтроллером?
83.33%Да. по аппаратному интерфейсу SPI.5
66.67%Да, по аппаратному интерфейсу SDIO.4
16.67%Да. по программному интерфейсу SPI.1
16.67%Да, по программному интерфейсу SDIO.1
Проголосовали 6 пользователей. Воздержался 1 пользователь.