Embedded HandbookПриложения
Все разделы › VI. Практикум
STM32F411, STM32F407, STM32F429 · уровень средний · 11 мин чтения
Открыть в интерактивном справочнике

41а. SD-карта по SDIO: четыре линии данных, команды, DMA и FatFS

В разделе 41 карта подключена по SPI — четыре провода, любой микроконтроллер, скорость около 3 МБ/с в лучшем случае. У F4 (и у F103 высокой плотности) есть собственный блок SDIO: он говорит с картой на её родном протоколе, гонит данные по четырём линиям сразу, считает контрольные суммы аппаратно и кормит DMA. Тот же FatFS поверх него работает быстрее в несколько раз. Цена — три лишних провода, подтяжки и протокол запуска, который нужно понимать, когда карта «не определяется».

Правила протокола, формула делителя, устройство FIFO и порядок работы с DMA взяты из справочного руководства на F4 (из пакета Keil); последовательность команд при запуске — из исходников HAL 2.17.1. Времена, CRC и делители пересчитаны программой _verify/sdio41a/sdio_calc.c, собранной gcc на компьютере. Сверяет _verify/sdio41a_check.py.

Как это называется в документации

Оригинал Перевод
SDIO, SDMMC блок для SD/MMC-карт (в новых семействах — SDMMC)
SDIO_CK, SDIO_CMD, SDIO_D0…D3 такт, линия команд, линии данных
CPSM, DPSM автоматы команд и данных внутри блока
command, response (R1…R7) команда и ответ карты
ACMD «прикладная» команда — идёт после CMD55
OCR, CID, CSD, RCA, SCR регистры карты: питание, паспорт, параметры, адрес, возможности
SDSC, SDHC/SDXC карта стандартной и высокой ёмкости
block, DBLOCKSIZE блок данных и код его размера
wide bus четырёхбитный режим

41а.1 Чем SDIO отличается от карты по SPI

У карты два лица. В режиме SPI она притворяется обычным ведомым устройством: одна линия туда, одна обратно, выбор кристалла. В родном режиме у неё отдельная линия команд CMD, такт CLK и до четырёх линий данных D0…D3; по всем четырём биты идут одновременно. Блок SDIO знает только родной режим — режима SPI у него нет, это прямо сказано в руководстве.

Что это даёт на 24 МГц (рабочий такт по умолчанию в HAL):

Режим Один блок 512 байт Предел фазы данных
SDIO, 1 линия 4114 тактов — 171,4 мкс 3,0 МБ/с
SDIO, 4 линии 1042 такта — 43,4 мкс 11,8 МБ/с
SPI на 25 Мбит/с ≈ 4100 тактов ≈ 3 МБ/с

Блок — это стартовый бит, 4096 бит данных, по 16 бит CRC на каждой линии и стоповый бит: на четырёх линиях данные делятся на четыре, а контрольные суммы считаются параллельно. Отсюда почти четырёхкратный выигрыш.

Это предел самой передачи данных. В настоящий поток входят ещё команда и ответ по 48 бит, время доступа карты до первого блока, а при записи — время, пока карта держит D0 «занято»: у дешёвых карт это миллисекунды на блок. Близко к расчёту подходит только чтение многими блоками подряд.

Обмен по SDIO: по линии CMD идёт команда из 48 бит с номером, аргументом и CRC7, затем ответ карты R1 на 48 бит тоже с CRC7; блок 512 байт идёт по четырём линиям D0…D3 по 1024 бита на каждую с CRC16 на каждой линии — старт, 1024, 16 и стоп дают 1042 такта, 43,4 мкс и 11,8 МБ/с на 24 МГц

Ещё два отличия: контрольные суммы всегда включены — CRC7 у команд и ответов, CRC16 у каждой линии данных, и считает их блок сам; и линии двунаправленные, им нужны подтяжки к питанию на всех D0…D3 и CMD — руководство требует внешних резисторов на линиях данных. Без них карта молчит или работает только в однобитном режиме.

У F411 блок SDIO есть (в даташите — «SD/MMC/eMMC»), у F407 и F429 тоже; у BluePill на F103C8 его нет — там только SPI (раздел 41).


41а.2 Такт: делитель и два режима частоты

Тактовая частота карты получается из SDIOCLK делителем в регистре CLKCR:

SDIO_CK = SDIOCLK / (CLKDIV + 2)

SDIOCLK — те же 48 МГц, что для USB (руководство: до 50 МГц, 48 при совместной работе с USB), поэтому ФАПЧ должна выдавать честные 48 МГц, иначе карта получит не ту частоту. Есть и режим обхода делителя — тогда карта тактируется прямо от SDIOCLK.

HAL держит два делителя:

#define SDIO_INIT_CLK_DIV     ((uint8_t)0x76)    /* 48MHz / (SDMMC_INIT_CLK_DIV + 2) < 400KHz */
#define SDIO_TRANSFER_CLK_DIV ((uint8_t)0x0)     /* 48MHz / (SDMMC_TRANSFER_CLK_DIV + 2) < 25MHz */

0x76 — это 118: 48 МГц / 120 = ровно 400 кГц, предел для опроса карты при запуске. 0 — 48 / 2 = 24 МГц для передачи данных. Запуск на низкой частоте — не прихоть HAL, а требование карты: на 24 МГц она не ответит на первые команды, и симптом будет «карта не определяется», причём разные карты ведут себя по-разному.


41а.3 Команда и ответ

Команда — всегда 48 бит на линии CMD: стартовый бит, бит направления, 6 бит номера команды, 32 бита аргумента, CRC7 и стоповый бит. Ответы бывают короткие — тоже 48 бит — и длинные, 136 бит: так карта отдаёт регистры CID и CSD. Аппарат (автомат команд, CPSM) сам ставит CRC7 и сам проверяет его в ответе; исключение — ответ на запрос питания R3, где поле CRC заполнено единицами и не проверяется.

Кадры первых команд совпадают с теми, что считались вручную в 18.10 для режима SPI: CMD0 — CRC 0x95, CMD8 с аргументом 0x1AA — 0x87. Только здесь их считает блок, а не программа.

Ответы, которые встречаются при запуске:

Ответ Длина Что несёт
R1 48 номер команды и состояние карты
R2 136 CID (паспорт) или CSD (параметры)
R3 48 OCR: окно питания, готовность, признак SDHC
R6 48 опубликованный адрес RCA
R7 48 ответ на CMD8: напряжение и эхо шаблона

Часть команд — прикладные, ACMD: номер у них может совпадать с обычной командой (ACMD41, ACMD6, ACMD51), различает их карта только по тому, что перед ними пришла CMD55 с её адресом. Без CMD55 тот же номер она выполнит как обычную команду — или ответит ошибкой.


41а.4 Запуск карты: что делает HAL_SD_Init

HAL_SD_Init вызывает HAL_SD_InitCard, и там весь протокол запуска, в том же порядке, что и по SPI в разделе 41, но с другими ответами:

  1. Блок настраивается на 1 бит и SDIO_INIT_CLK_DIV, включается питание выводов, такт, пауза HAL_Delay(2) — карте нужно время после подачи такта.
  2. CMD0 — карта в состоянии ожидания.
  3. CMD8 с шаблоном 0x1AA. Ответила — карта версии 2, не ответила — версии 1, и CMD0 повторяется.
  4. CMD55 + ACMD41 в цикле — до 0xFFFF попыток: аргумент несёт окно питания и бит 0x40000000 «хост умеет SDHC». В ответе бит 31 — «готова»; пока он нулевой, цикл продолжается. Бит 30 в ответе готовой карты — SDHC/SDXC, иначе SDSC.
  5. CMD2 — карта отдаёт CID (136 бит), CMD3 — публикует адрес RCA.
  6. CMD9 с RCA — CSD: из него HAL вычисляет число блоков и ёмкость.
  7. CMD7 — выбрать карту: она переходит в состояние передачи.
  8. CMD16 — длина блока 512.

После этого HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) читает регистр SCR (ACMD51, блок 8 байт), убеждается, что карта умеет 4 бита, шлёт ACMD6 и перенастраивает блок на четыре линии и рабочий делитель. Перепутать порядок нельзя: 4 бита включаются только после выбора карты, а частота поднимается только после запуска.

Запуск SD-карты по SDIO: HAL_SD_Init на одной линии и 400 кГц проходит восемь шагов — настройка, CMD0, CMD8 с шаблоном 0x1AA, CMD55 и ACMD41 в цикле до готовности, CMD2 и CMD3, CMD9, CMD7, CMD16; затем HAL_SD_ConfigWideBusOperation через ACMD51 и ACMD6 включает четыре линии и 24 МГц

if (HAL_SD_Init(&hsd) != HAL_OK)                  /* 1 бит, 400 кГц, весь протокол */
    return -1;
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
    return -2;                                    /* 4 линии, 24 МГц */

В самой hsd.Init.BusWide при этом оставляют SDIO_BUS_WIDE_1B: сразу после CMD7 HAL перенастраивает блок по hsd.Init — и делитель, и ширину шины. С SDIO_BUS_WIDE_4B там блок перешёл бы на четыре линии раньше карты (41а.7).

Ёмкость и адресация: у SDSC адрес в командах чтения — байтовый, у SDHC/SDXC — номер блока; HAL прячет это внутри HAL_SD_ReadBlocks, и наружу всегда торчит номер блока по 512 байт.


41а.5 Блок данных, FIFO и DMA

Данные ходят блоками по 512 байт — ровно сектор FAT. В регистре управления данными размер кодируется степенью двойки: DBLOCKSIZE = 0x9 — это 2⁹ = 512. Внутри блока FIFO на 32 слова по 32 бита; флаг «половина» — 8 слов — служит запросом DMA. Читать FIFO процессором можно (HAL_SD_ReadBlocks так и делает), но на 24 МГц по четырём линиям слово прилетает каждые 333 нс, и процессор занят только этим.

Правильный путь — DMA, и у него в руководстве точный рецепт: DMA2, поток 3 или поток 6, канал 4; слова по 32 бита; управление потоком — периферией (PFCTRL: длину знает SDIO, а не DMA); пакеты по 4 слова хотя бы со стороны периферии. Порядок при записи блока: запустить DMA, послать CMD24, дождаться CMDREND, включить автомат данных с DMAEN, дождаться DBCKEND. HAL_SD_WriteBlocks_DMA и HAL_SD_ReadBlocks_DMA делают это сами; от программы нужны два обработчика — SDIO_IRQHandler и прерывание потока DMA — и буфер, выровненный на 4 байта.

Контрольные суммы данных — CRC16 с полиномом 0x1021, по одной на каждую линию. Блок из 512 байт 0xFF по одной линии даёт 0x7FA1 (в четырёхбитном режиме каждая линия несёт 128 байт 0xFF, и сумма на линии — 0xEDA9) — число, по которому проверяют свою реализацию все, кто писал драйвер карты руками; здесь его считает аппарат, а ошибка приходит флагом DCRCFAIL. Второй сторож — таймер данных DTIMER: если карта не ответила на чтение или держит линию «занято» дольше заданного, блок поднимает DTIMEOUT вместо вечного ожидания.


41а.6 FatFS поверх SDIO

Слой диска для FatFS (раздел 42) — те же пять функций, что и для SPI, только внутри них HAL:

static volatile int rx_done;

void HAL_SD_RxCpltCallback(SD_HandleTypeDef *h) { (void)h; rx_done = 1; }

DRESULT disk_read(BYTE pdrv, BYTE *buf, LBA_t sector, UINT count)
{
    (void)pdrv;
    rx_done = 0;
    if (HAL_SD_ReadBlocks_DMA(&hsd, buf, (uint32_t)sector, count) != HAL_OK)
        return RES_ERROR;
    uint32_t t0 = HAL_GetTick();
    while (!rx_done)                                            /* DMA перенёс всё */
        if (HAL_GetTick() - t0 > 1000u) return RES_ERROR;
    while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)   /* карта снова готова */
        if (HAL_GetTick() - t0 > 1000u) return RES_ERROR;
    return RES_OK;
}

HAL_SD_ReadBlocks_DMA только запускает обмен и сразу возвращается. Конец переноса отмечает обратный вызов HAL_SD_RxCpltCallback: его зовёт прерывание DMA, когда последнее слово легло в память, а при чтении нескольких блоков HAL перед ним сам посылает CMD12. Поэтому сначала ждут его и лишь потом — состояния TRANSFER: оно говорит о карте, а не о памяти, — DMA мог ещё не выгрузить хвост FIFO, а опрос CMD13 посреди обмена сталкивается с CMD12 из прерывания. Оба ожидания — с тайм-аутом, иначе вынутая карта повесит программу навсегда.

disk_write — так же, с HAL_SD_TxCpltCallback, и там ожидание TRANSFER обязательно вдвойне: карта отвечает «принято» раньше, чем физически записала блок, и следующая команда без этой паузы получит ошибку «занято». Буфер от FatFS бывает невыровненным, а DMA нужен адрес, кратный 4 (41а.5): проверяют ((uintptr_t)buf & 3) != 0 и в этом случае гонят секторы по одному через свой выровненный буфер. Размер сектора — 512, число секторов — из HAL_SD_GetCardInfo, LogBlockNbr. Всё остальное в FatFS от шины не зависит.


41а.7 Грабли

Симптом Причина
карта не отвечает вовсе нет подтяжек на CMD и D0…D3 — линии двунаправленные
работает в 1 бит, в 4 бита ошибки CRC подтяжки только на D0; или D1…D3 заняты другой периферией
HAL_SD_Init прошёл, а первое же чтение — ошибка в hsd.Init.BusWide стоит SDIO_BUS_WIDE_4B: после CMD7 HAL перенастроил блок на четыре линии, а карта без ACMD6 осталась на одной
«не определяется» на одних картах, на других работает запуск сразу на рабочей частоте, а не на 400 кГц
частота такта не та, что рассчитана SDIOCLK — от 48-мегагерцового выхода ФАПЧ, он не настроен
ACMD41 крутится до таймаута перед прикладной командой нет CMD55; или карта версии 1 без ответа на CMD8
DMA переносит мусор или виснет не поток 3/6 DMA2, нет PFCTRL, буфер не выровнен на 4 байта
запись возвращает «занято» через раз следующая команда до перехода карты в TRANSFER
disk_read вернул успех, а в буфере не всё ждали только TRANSFER, а не обратного вызова конца DMA
вынули карту — программа висит ожидание обратного вызова или TRANSFER без тайм-аута
после записи данные читаются старыми обработчики SDIO_IRQHandler и потока DMA не подключены — колбэки не приходят
ошибки CRC на длинных проводах 24 МГц по шлейфу: снизить делителем или укоротить
DCRCFAIL при записи на коротких проводах у F4 включено аппаратное управление потоком (HWFC_EN, бит 14 SDIO_CLKCR) или NEGEDGE: по перечню ошибок оба портят данные — не включать
перезапуск при обращении к карте пик тока до 100 мА, нет конденсатора у держателя (раздел 41)

41а.8 Итоги

Дальше: раздел 41б «FSMC и FMC: дисплей 8080, внешняя SRAM и SDRAM» — параллельная шина, на которой внешняя память и дисплей становятся областью адресов.

Открыть в интерактивном справочнике