50503

[i] Работа с картой SD через интерфейс SDIO в К1901ВЦ1QI

Дата последнего изменения: 12.05.2023 13:27:45

Работа с картами памяти Secure Digital (SD) возможна через интерфейс SDIO и через SPI. В рамках данной статьи рассматривается работа с SD-картами по интерфейсу SDIO микроконтроллера К1901ВЦ1QI, а именно реализация файловой системы FatFs с помощью модуля от http://elm-chan.org/ (на момент написания статьи актуальная версия FatFs R0.15 от Nov 6, 2022). Портированный модуль тестировался на microSDHC-карте объемом 8Гб.

Рисунок 1. Назначение выводов SD и microSD в режимах SDIO и SPI

При работе с картой использовалось описание стандарта SD в переводе "Упрощенное описание стандарта физического уровня карт SD" и SD Card Association.

1. Вводные сведения о работе примера

В проекте запускается тест драйвера "диска" от автора библиотеки файловой системы. Этот тест проверяет драйвер и сообщает, будет ли драйвер работать с файловой системой FatFs или нет.

Для успешного запуска тестирования требуется реализовать 5 функций (которые расположены в файле diskio.c модуля FatFs):

  • disk_status - Возвращает статус текущего диска (диск отсутствует, диск не инициализирован, диск защищен от записи);
  • disk_initialize - Инициализация диска;
  • disk_read - Чтение данных;
  • disk_write - Запись данных;
  • disk_ioctl - Реализация вспомогательных функций I/O;
  • get_fattime - Возврат текущего времени (используется реализация по умолчанию с помощью модификации файла ffconf.h - FF_FS_NORTC = 1).

Пример работает следующим образом:

  • При подаче питания настраивается тактирование (80МГц), выводы GPIO для кнопок и светодиодов для демонстрационной платы, настройка таймаутов для работы с microSD-картой и инициализация системного таймера для их обработки.
  • При запуске мигает светодиод LED_CYCLE (PB13), показывая, что исполняется основной цикл while().
  • Кнопка Down - выполнение теста драйвера диска FatFs, результат отображается на светодиоды.
  • Кнопка Select - тест идентификации карты, результат отображается на светодиоды.
  • Результат:
    • LED_OK (PB15) - тест пройден успешно
    • LED_FAULT (PB14) - тест провален.

2. Блок SDIO в К1901ВЦ1QI

В спецификации SD по ссылке выше указано, какие сигналы и как необходимо подавать на карту при работе с ней. SDIO должен:

  1. Подавать частоту на линию SDIO_CLK, которая тактирует обмен по линиям SDIO_CMD и данных.
  2. На линию SDIO_CMD подавать команды для карты.
  3. С линии SDIO_CMD считывать ответы от карты.
  4. По линиям данных SDIO_DATA0-SDIO_DATA3 посылать и принимать данные.

Логика работы с модулем SDIO реализована в файле sd_card_sdio_ll.c. Модуль реализует все функции, необходимые для обмена сигналами с SD-картой. Протокол обмена реализован в отдельном файле sd_card_protocol.c.

Поскольку внутри SD-карты имеется свой контроллер, работающий на своей частоте, частота по SDIO_CLK от микроконтроллера к SD-карте нужна только для обмена. Передача данных может осуществляться по одной линии (SDIO_DATA0) или по четырем (SDIO_DATA0-SDIO_DATA3, обеспечивает бо́льшую скорость) - в текущем примере используются все линии.

Для работы с картой предварительно необходимо подать на нее питание, это может быть осуществлено при физическом детектировании карты в слоте, или, как это реализовано на демонстрационной плате К1901ВЦ1QI, может быть подано всегда. Поскольку на демоплате питание подано всегда, каких-либо дополнительных действий не требуется и в функции включения питания SDIO_LL_PowerOn() только инициализируется регистр управления блоком MDR_SDIO->CR. Маски значений регистра CR вынесены отдельно для наглядности задаваемого режима работы (фрагмент кода 1):

#define SDIO_CR__PowerOn      SDIO_CR_SDE | SDIO_CR_CLKOE | SDIO_CR_CRC_EN_DATA
#define SDIO_CR__SendCMD      SDIO_CR_CRC_EN_CMD | SDIO_CR_SBITCMD | SDIO_CR_DIRCMD
#define SDIO_CR__ReadResp     SDIO_CR_CRC_EN_CMD | SDIO_CR_SBITCMD
#define SDIO_CR__SendCycles   SDIO_CR_DIRCMD

#define SDIO_CR__ReadBlock    SDIO_CR_CRC_EN_CMD | SDIO_CR_SBITDAT
#define SDIO_CR__WriteBlock   SDIO_CR_CRC_EN_CMD | SDIO_CR_SBITDAT | SDIO_CR_DIRDATA

#define SDIO_CR__ModeClear    (SDIO_CR_CRC_EN_CMD | SDIO_CR_SBITCMD | SDIO_CR_DIRCMD | SDIO_CR_SBITDAT | SDIO_CR_DIRDATA)

void SDIO_LL_PowerOn(void)
{
    MDR_SDIO->CR = SDIO_CR__PowerOn;
}

Фрагмент кода 1.

Биты регистра CR при включении питания:

  • SDIO_CR_SDE - включить блок SDIO.
  • SDIO_CR_CLKOE - разрешить генерацию тактовых сигналов в линию SDIO_CLK.
  • SDIO_CR_CRC_EN_DATA - автоматически считать CRC посылаемых данных и выводить в линии данных.

2.1. Посылка команды

После подачи питания SD-карту необходимо идентифицировать и инициализировать, обмен при этом осуществляется через линии SDIO_CLK и SDIO_CMD. Для посылки команд реализована функция SDIO_LL_SendCMD(cmd, arg), которая является оберткой функции SPL SDIO_SendCommand(cmd, arg) (фрагмент кода 2).

static inline void SDIO_CR_SetMode(uint32_t CR_Flags)
{
    uint32_t regCR = MDR_SDIO->CR;
    regCR &= ~(SDIO_CR__ModeClear);
    MDR_SDIO->CR = regCR | CR_Flags;
}

SD_CARD_CMD_Result_TypeDef SDIO_LL_SendCMD(uint32_t cmd, uint32_t arg)
{
    SDIO_CR_SetMode(SDIO_CR__SendCMD);
    SDIO_SendCommand(cmd, arg);

    // The transfer is finished
    return SD_CARD_CMD_OK;
}

Фрагмент кода 2.

Пример диаграммы исполнения функции SDIO_LL_SendCMD(cmd, arg) представлен на рисунке 1:

Рисунок 2. Диаграмма исполнения функции SDIO_LL_SendCMD(cmd, arg)

Тактовые импульсы подаются только на время вывода команды. Их столько, сколько задано в (CMD_TRANSFER + 1), то есть для посылки команды к карте - (48 + 1) (по стандарту допускается отключить тактирование, не дожидаясь выхода карты из режима Busy. Текущая операция в карте SD при этом все равно закончится, но в данном случае необходимо подать на карту дополнительный тактовый перепад для снятия сигнала занятости по линии данных SDIO_DATA0).

Сигнал SDIO_CMD начинается со стартового бита, который всегда равен "0", и заканчивается стоповым битом, который всегда равен "1". Таким образом непрерывно идущие посылки разграничиваются переключением уровня сигнала SDIO_CMD "0"->"1" вне зависимости от данных.

Второй бит за стартовым определяет направление передачи по линии SDIO_CMD.
  • 1: Передача команды от хоста (МК) к SD-карте.
  • 0: Ответ от карты хосту.
Далее идет 6 бит команды, затем старший байт аргумента и остальные байты. После аргумента на линию выводится значение CRC, оно считается аппаратно при установленном бите SDIO_CR_CRC_EN_CMD. Завершается посылка выставлением стопового бита.

2.2. Особенности тактирования

Согласно спецификации на SD, пункт "4.4 Clock Control", тактирование по линии SDIO_CLK может подаваться постоянно, либо выключаться, например, для снижения энергопотребления при простое (отсутствии обмена). Но есть несколько исключений:

    1) Необходимо дождаться, чтобы карта закончила текущую операцию, то есть вышла из режима Busy. Для этого карту необходимо опрашивать с периодом не реже 50мс командой ACMD41 (SD_APP_OP_COND), которая возвращает биты статуса. Тактирование при этом можно держать постоянно либо включать только на время опроса, но с учетом п.3.

    2) Допускается отключить тактирование, не дожидаясь выхода карты из режима Busy. Текущая операция в карте при этом все равно закончится. Но в данном случае, необходимо подать на карту дополнительный тактовый перепад, чтобы снять сигнал занятости по линии данных SDIO_DATA0. Если этого не сделать, то линия SDIO_DATA0 останется в 0.

    3) Тактовая частота должна выдаваться все время, когда карта выводит данные или токены ответа (response). По окончании последней транзакции по шине SD хосту требуется предоставить 8 тактовых циклов для карты, чтобы завершить операцию перед выключением тактирования. Ниже приведен список различных транзакций по шине:
      1. Команда без ответа. 8 тактов подается хостом после завершающего бита команды.
      2. Команда с ответом карты (response). 8 тактов после завершающего бита ответа карты.
      3. Транзакция чтения данных. 8 тактов по завершении последнего бита последнего блока данных.
      4. Транзакция записи данных. 8 тактов после токена статуса CRC.

Необходимо, чтобы любая передача по линиям SDIO_DATA0-SDIO_DATA3 и SDIO_CMD всегда заканчивалась 8-ю дополнительными тактами на линии CLK, только после дополнительных 8 тактов сигнал тактирования на CLK может быть остановлен. Аппаратно такой режим не реализуется, дополнительные 8 тактов CLK необходимо формировать программно. Для этого реализована отдельная функция SDIO_LL_SendClockCycles(N) (рисунок 3).

Рисунок 3. Формирование дополнительных 8 тактов CLK после отправки команды

Между посылкой команды и дополнительными 8-ю тактами есть промежуток, связанный с переинициализацией блока SDIO, что, однако, при тестировании не вызывает нарушений обмена с SD-картой. Также следует отметить, что за один вызов функции максимальное количество посылаемых периодов - 32 (поскольку в регистр CMDDR записывается только одно слово для отправки), поэтому для формирования большего числа тактов необходимо вызывать функцию несколько раз.


#define CHECK_CMD_STOPPED 0


#if CHECK_CMD_STOPPED


static inline void WaitCMDStopped(void)
{
    do {
        MDR_SDIO->CR &= ~(SDIO_CR_WORK2 | SDIO_CR_SBITCMD);
    } while (MDR_SDIO->CR & SDIO_CR_WORK2);
}

#define WAIT_CMD_STOPPED WaitCMDStopped
#else
#define WAIT_CMD_STOPPED __nop
#endif

bool SDIO_LL_SendClockCycles(uint32_t clockCycles)
{
    WAIT_CMD_STOPPED();

    SDIO_CR_SetMode(SDIO_CR__SendCycles);
    MDR_SDIO->CMDDR = 0x00FF;
    MDR_SDIO->CMD_TRANSFER = clockCycles; // Number of cycles
    MDR_SDIO->CMDCRC = 0x00000000;

    MDR_SDIO->CR |= SDIO_CR_WORK2;

    if (!WaitCMDCompleted(_SDIO_Timeouts.SD_SendCMD_Timout_ms))
         return false;

    MDR_SDIO->CR &= ~SDIO_CR_DIRCMD; // Command RX
         return true;
}

Фрагмент кода 3.

Функция SDIO_LL_SendClockCycles() практически аналогична SDIO_LL_SendCMD(), различие заключается в управляющих битах регистра CR. В ней сброшены биты:

  1. SDIO_CR_SBITCMD = 0, данные на линию SDIO_CMD не выводятся. В регистр CMDDR кладется любое число, чтобы FIFO не было пустым, для начала передачи.
  2. SDIO_CR_CRC_EN_CMD = 0, значение CRC не считается и на линию не выводится.
  3. SDIO_CR_DIRCMD = 0, линия SDIO_CMD не используется и остается в режиме входа, состояние по умолчанию.

2.3. Чтение ответа от карты

Код чтения ответа от карты такой же, как в спецификации (фрагмент кода 4).

SD_CARD_CMD_Result_TypeDef SDIO_LL_ReadResponse(SD_CARD_ResponseLength_TypeDef respLength,
uint32_t* response)
{
    uint32_t tmpBuff[5];


    // Read answer form SD card
    SDIO_CR_SetMode(SDIO_CR__ReadResp);


    MDR_SDIO->CMD_TRANSFER = (uint32_t)respLength;
    MDR_SDIO->CMDCRC = 0x00000000;
    MDR_SDIO->CR |= SDIO_CR_WORK2;


    // Waiting for a response with a timeout
    if (!WaitCMDCompleted(_SDIO_Timeouts.SD_ReadResp_Timout_ms)) {
          // Force stopping a transaction
        MDR_SDIO->CR &= ~(SDIO_CR_WORK2 | SDIO_CR_SBITCMD);
                return SD_CARD_CMD_TimeoutSend;
    }


    // Reading received data from FIFO
    tmpBuff[0] = MDR_SDIO->CMDDR; // Read the response words 0
    tmpBuff[1] = MDR_SDIO->CMDDR; // Read the response words 1


    response[0] = ((tmpBuff[0] << 8) & 0xFFFFFF00) | ((tmpBuff[1] >> 8) & 0x000000FF);
    if (respLength == SD_CARD_Resp_136bit) {
         tmpBuff[2] = MDR_SDIO->CMDDR; // Read the response words 2
         tmpBuff[3] = MDR_SDIO->CMDDR; // Read the response words 3
         tmpBuff[4] = MDR_SDIO->CMDDR; // Read the response words 4


         response[1] = ((tmpBuff[1] << 8) & 0xFFFFFF00) | ((tmpBuff[2] >> 8) & 0x000000FF);
         response[2] = ((tmpBuff[2] << 8) & 0xFFFFFF00) | ((tmpBuff[3] >> 8) & 0x000000FF);
         response[3] = ((tmpBuff[3] << 8) & 0xFFFFFF00) | ((tmpBuff[4] >> 8) & 0x000000FF);
    }


    return SD_CARD_CMD_OK;
}

Фрагмент кода 4.

В регистре CR выставляются те же биты, что и для посылки команды, сброшен только бит:

  • SDIO_CR_DIRCMD = 0, линия SDIO_CMD работает как вход. Сигналами на нем управляет карта.

В этом режиме блок SDIO бесконечно генерирует тактовые импульсы и, после появления на линии SDIO_CMD стартового бита, считывает данные в количестве бит, указанных в регистре CMD_TRANSFER. По окончании чтения линии бит SDIO_CR_WORK2 сбросится в 0, и полученные данные будут вычитаны из регистров блока. Операция чтения выполняется с таймаутом, поскольку если ответа нет, то бесконечное чтение необходимо прервать. Это указывает на то, что карта SD не приняла команду, то есть не послала ответ, либо самой карты нет в разъеме. По этой причине при срабатывании таймаута необходимо вручную сбросить биты SDIO_CR_WORK2 и SDIO_CR_SBITCMD, чтобы остановить транзакцию.


2.4. Таймауты

В спецификации все таймауты указаны в миллисекундах. Для их обработки в примере используется системный таймер SysTick, который входит в состав ядра. Таймер настраивается на генерацию прерывания каждую миллисекунду. В обработчике прерывания декрементируются две переменные, которые отсчитывают таймаут. Значение переменной таймаута задается в коде и затем там же происходит ожидание обнуления этой переменной. Если переменная обнулилась, значит сработал таймаут.

В модуле декрементируются две переменные таймаута. Одна используется внутренними функциями модуля sd_card_sdio_ll.c, а вторая используется функциями более высокого уровня, реализованными в модуле sd_card_protocol.c. Декремент переменных выделен в отдельную функцию SDIO_LL_DelayHandler(). Это сделано для того, чтобы было возможно использовать обработчик системного таймера в основной программе, тогда в обработчике прерываний системного таймера нужно отдельно вызывать функцию SDIO_LL_DelayHandler() для отсчета таймаутов. Если в основной программе обработчик прерывания системного таймера не нужен, то обработчик по умолчанию SysTick_Handler() уже реализован в sd_card_sdio_ll.c и активируется макроопределением USE_SYS_TIMER_HANDLER = 1, в файле sd_card_sdio_ll.h (фрагмент кода 5).

volatile uint32_t DelayInt_ms, DelayExt_ms;

void SDIO_LL_DelayHandler(void)
{
    volatile uint32_t n;

    n = DelayExt_ms;
    if (n)
        DelayExt_ms = --n;
    n = DelayInt_ms;
    if (n)
        DelayInt_ms = --n;
}

#if USE_SYS_TIMER_HANDLER
void SysTick_Handler(void)
{
    SDIO_LL_DelayHandler();
}
#endif
Фрагмент кода 5.

В текущем примере прерывание от системного таймера используется в main.c для мигания светодиодом LED_CYCLE, поэтому определение USE_SYS_TIMER_HANDLER = 0, а в SysTick_Handler() вызывается SDIO_LL_DelayHandler().

3. Работа с SD-картой

Работа с SD-картой подразумевает посылку команд, принятие ответов и обмен данными. Все это реализуется функциями SDIO, которые были рассмотрены выше. Согласно стандарту некоторые команды требуют предварительного переключения SD-карты в режим восприятия следующей команды как "Application Specific Command" (команды, специфичные для приложения). Такие команды начинаются с префикса "A", то есть это ACMDx, и их исполнение состоит из двух посылок. На примере ACMD41 это:

  1. CMD55 (APP_CMD) - указывает, что следующая команда является командой, специфичной для приложения.
  2. ACMD41 - запрос статуса.

Для удобства реализована отдельная функция SDIO_LL_ExecACMD(), которая принимает на вход оба типа команд и, если посылаемая команда ACMD, предварительно посылает команду CMD55 (фрагмент кода 6).

#define CMD55 (55) // APP_CMD
bool SD_ExecACMD(uint32_t cmd, uint32_t arg, SD_CARD_ResponseLength_TypeDef respLength, uint32_t* response)
{
    SD_ResponseR1              respCMD55;
    SD_CARD_CMD_Result_TypeDef result;

    if (cmd & 0x80) {
        // Switch SD card to ACMD command response waiting
        result = SD_ExecCMD(CMD55, CardRCA << 16, SD_CARD_Resp_48bit, &respCMD55.value);
        if (result != SD_CARD_CMD_OK)
            return false;

        // Exit if SD card doesnt return APP_CMD wait status
        if (!(respCMD55.bits.SD_R1_APP_CMD))
            return false;
    }

    //  Command "Application-Specific Command"
    return (SD_ExecCMD(cmd, arg, respLength, response) == SD_CARD_CMD_OK);
}
Фрагмент кода 6.

Через функцию SD_ExecACMD() реализована вся логика работы с картой.

Работа с картой делится на два этапа:

  1. Идентификация карты и настройка рабочего режима.
  2. Работа с данными - запись и чтение данных на карте.

3.1. Идентификация карты

Идентификация карты происходит после включения питания. Опрашиваются внутренние регистры карты, определяется ее тип, объем, рабочее напряжение, максимальная скорость работы и т.д. В каждый момент времени на шине SDIO может быть активна только одна карта, поэтому карта назначается активной и затем с ней происходит обмен данными.

Идентификация должна проходить на низкой скорости 100-400кГц и при широком диапазоне напряжений питания 2.7-3.6 В, что необходимо для обратной совместимости со старыми картами.

Последовательность команд идентификации карты описана в спецификации SD, где наглядно указаны переходы между состояниями в виде графов. Ниже рассматривается ветка инициализации, используемая в примере:

  1. Включение питания - на демонстрационной плате постоянно подано.
  2. Выставление скорости обмена в битах BRG регистра CR - устанавливается делитель для последующего обмена, сама частота на данный момент не подается.
  3. Формирование 74 тактов SDIO_CLK согласно спецификации SD после подачи питания.
  4. CMD0 (GO_IDLE_STATE) - перевод карты в состояние IDLE. Карта после подачи питания должна быть в состоянии IDLE, но если идентификация вызывается не после подачи питания, а при уже инициализированной карте, которая находится в каком-то режиме, то вызов CMD0 необходим.
  5. CMD8 (SEND_IF_COND) - команда добавлена, начиная с версии спецификации 2.00 для карт, которые могут работать на меньших напряжениях питания. Используемая карта выдает ответ, что она поддерживает указанный диапазон напряжений 2,7-3,6В. С демонстрационной платы подается 3,3В.
  6. ACMD41 (SEND_OP_COND) - опрос статуса карты в цикле, пока она не вернет бит готовности после PowerUp. Бит CCS в ответе говорит, что используемая карта имеет высокую емкость (High Capacity SD Memory). В ответе карта возвращает значение регистра OCR (Operation Conditions Register).
  7. CMD2 (ALL_SEND_CID) - чтение регистра CID (Card Identification Data).
  8. CMD3 (SEND_RELATIVE_ADDR) - получение адреса карты RCA (Relative Card Address). Используется далее для адресации карты.
  9. CMD9 (SEND_CSD) - чтение регистра CSD (Card Specific Data).
  10. CMD7 (SELECT_CARD) - карта становится активной, состояние Transfer. С ней будет идти обмен по линиям данных. Остальные карты, если есть на шине, будут в состоянии StandBy.
  11. ACMD6 (SET_BUS_WIDTH) - устанавливается обмен по всем четырем линиям SDIO_DATAx.
  12. Идентификация закончена, устанавливается делитель частоты BRG на высокую скорость обмена, после чего возможен обмен данными.

Настраивать напряжение питания нет необходимости, поскольку, согласно спецификации на SD-карты, по напряжению питания карты делятся на:

  • высоковольтные, с диапазоном Vdd1: 2,7-3,6В (как используемая карта).
  • с двумя диапазонами. Это карты ультра-скоростного диапазона UHS_II.
    • Vdd1: 2,7-3,6 В
    • Vdd2: 1,7-1,95 В

3.2. Работа с данными

После идентификации и ответа карты о поддерживаемых скоростях микроконтроллер может выставить более высокую скорость общения с картой. Скорость определяется классом карты, для используемой в примере карты указан класс 10 - это значит, что карта поддерживает скорость не меньше 10МБ/сек. Максимальная же скорость обмена по стандарту 2.00 составляет 25МБ/сек, т.е. 50МГц (в режиме High Speed, введенным с версии 1.10 спецификации).

Работа с данными происходит блоками по 512 байт. Карты поддерживают одноблочные операции чтения/записи и многоблочные. При записи данных сразу в несколько блоков рекомендуется задать команду на предварительное стирание этих блоков, тогда запись данных произойдет быстрее.

Последовательность чтения данных:

  1. CMD13 - проверка, что карта в состоянии Transfer.
  2. Запрос на проведение операции чтения, проверка ответа на отсутствие ошибок обмена данными.
    • CMD17 - READ_SINGLE_BLOCK
    • CMD18 - READ_MULTIPLE_BLOCK
  3. Цикл чтения блока/блоков данных через SDIO функцией SDIO_LL_ReadBlock().
  4. После окончания считывания подаются дополнительные 8 тактов SDIO_CLK - SDIO_LL_SendClockCycles(8).
  5. Если чтение многоблочное, вызывается CMD12 (STOP_TRANISSION) для выхода из режима выдачи данных. В случае одноблочного режима карта сама вернется в состояние Transfer после выдачи одного блока данных.
  6. Подача дополнительных 8 тактов частоты.

Последовательность записи данных:

  1. CMD13 - проверка, что карта в состоянии Transfer.
  2. Если запись многоблочная, производится стирание сектора.
    • CMD23 - SET_BLK_COUNT для карт MMC.
    • ACMD23 - SET_WR_BLK_ERASE_COUNT для карт SD.
  3. Запрос на проведение операции записи, проверка ответа на отсутствие ошибок обмена данными.
    • CMD24 - WRITE_BLOCK
    • CMD25 - WRITE_MULTIPLE_BLOCK
  4. Цикл записи данных:
    • CMD13 - проверка, что карта в состоянии Transfer и выставлен бит готовности к приему данных.
    • Запись блока данных через функцию SDIO_LL_WriteBlock().
  5. Если запись многоблочная - вызывается CMD12 (STOP_TRANISSION) для выхода из режима приема данных. В случае одноблочного режима, карта сама вернется в состояние Transfer после приема одного блока данных.
  6. Подача дополнительных 8 бит тактовой частоты.

Последовательности чтения и записи заканчиваются подачей дополнительных 8-ми тактов на линии SDIO_CLK.

4. Тест файловой системы

Как было указано ранее, в проекте используется библиотека файловой системы FatFs от elm-chan.org. Она качается с сайта и подключается к проекту, Download. В файле diskio.c заведены прототипы функций, которые необходимо реализовать для работы файловой системы.

Иерархия проекта:

  • diskio.c - Функции IO файловой системы, работают через:
    • sd_card_protocol.c - Протокол обмена (команды и обмен данными с SD-картой), работает через:
      • sd_card_sdio_ll.c - Функции работы с блоком SDIO (генерация сигналов взаимодействия)
Функция IO драйвера FatFs Функция brdSD_Card.c
DSTATUS disk_initialize (BYTE pdrv) SD_CARD_CardDetect() - идентификация карты
DSTATUS disk_status (BYTE pdrv) Возврат переменной статуса
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) SD_CARD_CardRead() - чтение секторов
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) SD_CARD_CardWrite() - запись секторов
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) SD_CARD_IO_Ctrl() - вспомогательные операции IO

На сайте http://elm-chan.org/ предлагается модуль для теста функций IO - "A function checker for low level disk I/O module is available here". Модуль вызывает ранее перечисленные функции IO и, если тест проходит успешно, то выдается заключение о том, что реализация драйвера IO выполнена правильно и файловая система работоспособна.

Этот тест сохранен в проекте в функции TestFileSystem(), файл test_funcIO.c. Он вызывается по нажатию кнопки Down на отладочной плате. Если тест проходит успешно, то загорается светодиод LED_OK (PB15). Если тест не прошел, то загорается светодиод LED_FAULT (PB14).

В процессе исполнения TestFileSystem() отладочная информация выводится через функцию printf(). Для того чтобы получать эти логи, настроен вывод printf() через ITM. Следует обратить внимание, что если отсутствует реализация функции printf(), то есть не подключен реализующий функцию драйвер, проект не будет запускаться (при запуске ядро не будет доходить до функции main, "застревая" во внутренней функции инициализации).


Сохранить статью в PDF

Файлы для скачивания

Теги

Была ли статья полезной?