Top.Mail.Ru

STM32 и SDIO. Подключение SD-карты к микроконтроллеру.

Всем доброго дня! Сегодня мы поговорим о подключении SD-карты к микроконтроллеру STM32.

Казалось бы, памяти у контроллеров STM32F10x и так много, зачем там еще дополнительная, но это впечатление обманчиво ) Вот, например, надо нам на дисплей вывести пару-тройку разных изображений - формат 320*240 - то есть 76800 пикселей, каждому из которых соответствует целых 2 байта. Вот и получаем около 150 кБ на одну картинку. А это немало по меркам микроконтроллера, и не факт, что две разные картинки удастся запихать в его Flash-память.

Или надо нам хранить большие объемы информации, данные с какого-нибудь датчика, к примеру. Да еще так, чтобы эти данные были доступны и после отключения питания. Вот тут то нам и пригодится внешняя память. И отличным решением будет SD-карта. К слову в этой статье мы будем проводить опыты над картой microSD.

Для начала пара слов о самой карте памяти, точнее о ее распиновке. Выглядит все это дело следующим образом:

Распиновка SD-карты

Итак, что тут у нас? Ну сразу видно, что выводов у нее целых восемь штук. Назначение выводов следующее:

Распиновка карты памяти

Колонка SPI Mode нам намекает на то, что SD-карта взаимодействует с микроконтроллером при помощи интерфейса SPI. НО! Мы пойдем по другому пути. Все дело в том, что STM32 имеют на своем борту готовый периферийный модуль для работы именно с картами памяти, и называется он SDIO.

Вообще взаимодействие с картами памяти заключается в передаче им определенных команд. Некоторые команды требует наличия аргумента, некоторые нет. Команды можно найти в официальной документации. Так вот встроенный модуль SDIO дает возможность значительно упростить процесс передачи команд, да и вообще процесс работы с внешними картами памяти. Например, вот регистр SDIO_CMD - туда мы просто напросто записываем код команды, которую хотим передать карте. Или вот статусный регистр SDIO_STA - там целых 24 флага на каждый чих, то есть для большого количества событий.

Кстати STM радует еще и добротной документацией на все это дело. Вот, к примеру, подробное описание инициализации для карты памяти SD (аналогично все описано для других типов карт):

Процесс инициализации

Время традиционной вставки: поскольку компания STMicroelectronics прекратила поддержку библиотеки SPL, которая использовалась в этом курсе, я создал новый, посвященный работе уже с новыми инструментами, так что буду рад видеть вас там - STM32CubeMx. Кроме того, вот глобальная рубрика по STM32, а также статья на смежную тему из нового курса: STM32 и SD-карта. Настройка FatFs в STM32CubeMx.

Ну, собственно, пора перейти к практическому примерчику. Поковыряем-ка SPL.

В файле stm32f10x_sdio.h по традиции находим структуры для всевозможной настройки - то есть для выбора источника тактового сигнала, частоты контроллера SDIO, настройки количества передаваемых байт. Там все так щедро откомментировано, что даже не хочется отдельно это повторять ) Просто смотрите:

typedef struct
{
	uint32_t SDIO_ClockEdge;            /* Specifies the clock transition on which the bit capture is made.
	                                    This parameter can be a value of @ref SDIO_Clock_Edge */

	uint32_t SDIO_ClockBypass;          /* Specifies whether the SDIO Clock divider bypass is enabled or disabled.
	                                    This parameter can be a value of @ref SDIO_Clock_Bypass */

	uint32_t SDIO_ClockPowerSave;       /* Specifies whether SDIO Clock output is enabled or
	                                    disabled when the bus is idle.
	                                    This parameter can be a value of @ref SDIO_Clock_Power_Save */

	uint32_t SDIO_BusWide;              /* Specifies the SDIO bus width.
	                                    This parameter can be a value of @ref SDIO_Bus_Wide */

	uint32_t SDIO_HardwareFlowControl;  /* Specifies whether the SDIO hardware flow control is enabled or disabled.
	                                    This parameter can be a value of @ref SDIO_Hardware_Flow_Control */

	uint8_t SDIO_ClockDiv;              /* Specifies the clock frequency of the SDIO controller.
	                                    This parameter can be a value between 0x00 and 0xFF.*/

} SDIO_InitTypeDef;

typedef struct
{
	uint32_t SDIO_Argument;             /* Specifies the SDIO command argument which is sent
	                                    to a card as part of a command message. If a command
	                                    contains an argument, it must be loaded into this register
	                                    before writing the command to the command register */

	uint32_t SDIO_CmdIndex;             /* Specifies the SDIO command index. It must be lower than 0x40. */

	uint32_t SDIO_Response;             /* Specifies the SDIO response type.
	                                    This parameter can be a value of @ref SDIO_Response_Type */

	uint32_t SDIO_Wait;                 /* Specifies whether SDIO wait-for-interrupt request is enabled or disabled.
	                                    This parameter can be a value of @ref SDIO_Wait_Interrupt_State */

	uint32_t SDIO_CPSM;	                /* Specifies whether SDIO Command path state machine (CPSM)
	                                    is enabled or disabled.
	                                    This parameter can be a value of @ref SDIO_CPSM_State */
} SDIO_CmdInitTypeDef;

typedef struct
{
	uint32_t SDIO_DataTimeOut;          /* Specifies the data timeout period in card bus clock periods. */

	uint32_t SDIO_DataLength;           /* Specifies the number of data bytes to be transferred. */

	uint32_t SDIO_DataBlockSize;        /* Specifies the data block size for block transfer.
	                                    This parameter can be a value of @ref SDIO_Data_Block_Size */

	uint32_t SDIO_TransferDir;          /* Specifies the data transfer direction, whether the transfer
	                                    is a read or write.
	                                    This parameter can be a value of @ref SDIO_Transfer_Direction */

	uint32_t SDIO_TransferMode;         /* Specifies whether data transfer is in stream or block mode.
	                                    This parameter can be a value of @ref SDIO_Transfer_Type */

	uint32_t SDIO_DPSM;                 /* Specifies whether SDIO Data path state machine (DPSM)
	                                    is enabled or disabled.
	                                    This parameter can be a value of @ref SDIO_DPSM_State */
} SDIO_DataInitTypeDef;

Отметим как в SPL реализована передача команд карте памяти. Для этих целей отведена отдельная структура SDIO_CmdInitTypeDef. В поле SDIO_CmdIndex вводим код команды, в поле SDIO_Argument - аргумент команды, также заполняем остальные поля. Осталось как-то эти данные запихать в карту памяти. А для этого нам приготовили функцию:

  • SDIO_SendCommand (SDIO_CmdInitTypeDef *SDIO_CmdInitStruct).

В качестве аргумента передаем ей как раз таки созданную нами структуру. Для записи данных есть функция - SDIO_WriteData(uint32_t Data). После вызова этой функции данные окажутся в специально предназначенном для этого регистре - SDIO_FIFO.

Теперь перейдем наконец-то к практике . Я снова буду работать с платой Mini STM32, поскольку добрые китайцы озадачились установкой на нее слота для microSD. Вот схема подключения разъема для карты к микроконтроллеру:

Схема подключения

Для написания программы воспользуемся готовым примером для Keil'а - стащим оттуда два файла, в которых реализовано что-то вроде драйвера для работы с картами - это файлы sdcard.c и sdcard.h. Создаем новый проект, цепляем туда эти файлы, а кроме того, естественно, файлы CMSIS и SPL. Вот готовый проект, в который все уже добавлено - остается только написать код функции main():

В файле sdcard.c реализованы всевозможные функции для работы с картой памяти, нам теперь остается их только использовать. Пишем код, и для примера запишем на microSD 512 байт тестовых данных, а затем попробуем их считать:

/***************************************************************************************/
// Цепляем нужные файлы
#include "stm32f10x.h"
#include "sdcard.h"


/***************************************************************************************/
// Массивы входных и выходных данных и переменная для хранения данных о нашей карте
uint8_t writeBuffer[512];
uint8_t readBuffer[512];
SD_CardInfo SDCardInfo;


/***************************************************************************************/
int main()
{
	// Тестовые данные для записи
	for (uint16_t i = 0; i < 512; i++)
	{
		writeBuffer[i] = i % 256;
		readBuffer[i] = 0;
	}

	// Иницилизация карты
	SD_Init();
	
	// Получаем информацию о карте
	SD_GetCardInfo(&SDCardInfo);
	
	// Выбор карты и настройка режима работы
	SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));
	SD_SetDeviceMode(SD_POLLING_MODE);
	
	// И вот наконец-то запись и чтение
	SD_WriteBlock(0x00, writeBuffer, 512);
	SD_ReadBlock(0x00, readBuffer, 512);

	while(1)
	{
	}
}


/***************************************************************************************/

Обратите внимание, что SD-карта поддерживает запись блоками по 512 байт.

Если мы запустим программу под отладчиком, то увидим, что считанные данные соответствуют записанным, так что эксперимент можно считать удавшимся ) В дальнейшем можно добавить к проекту поддержку файловой системы FatFs, как, например тут или тут.

На этом на сегодня заканчиваем, до скорых встреч!

Подписаться
Уведомить о
guest

51 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Сергей
Сергей
11 лет назад

Спасибо! Очень полезно и познавательно ! Хотелось бы видеть такое также для PIC32 и Stellaris LaunchPad .

Alouette
Alouette
11 лет назад

А возможно ли записать на SD исполняемый код? Запустить на микроконтроллере операционную систему реального времени?

Cat
Cat
11 лет назад

Потратил на поиск несколько часов, слава богу нашел тут! Спасибо!!

george
george
11 лет назад

Отличная статья: нужная тема , короткое ясное изложение материала. Спасибо!

Tima
11 лет назад

Скажите, пожалуйста, а почему оно не компилируется в ИАРЕ? И какую версию ИАРА Вы использовали?

Тимофей
11 лет назад

Скажите, пожалуйста, а какую версию Кейла Вы использовали? )

Maxim
Maxim
11 лет назад

SD_WriteBlock(0x00, writeBuffer, 512) - и МК простаивает, ожидая записи в медленную FLASH память.
Эти функции надо использовать только в RTOS.

Maxim
Maxim
Ответ на комментарий  Aveal
11 лет назад

Я просто тоже так начинал программировать МК (после программирования в Windows). Только когда задачи пошли посложнее - пришлось переучиваться - использовать прерывания, иначе МК не успевал обрабатывать показания датчиков и т.д.

Anton
Anton
Ответ на комментарий  Maxim
2 лет назад

Тогда уж dma и прерывания

Валерий
Валерий
11 лет назад

А какие объемы sd-card можно использовать? 16Гб, например, потянет? Или это не имеет значения?

Falkon_99
Falkon_99
11 лет назад

Спасибо!

Прочитал в даташите что в STM32 интерфейс SDIO поддерживает (Full compliance with SD Memory Card Specifications Version 2.0)
А как насчёт Ver.3.0 (Class 10)? Будет работать???

Виктор
Виктор
11 лет назад

Уважаемый Aveal ответьте пожалуйста адресация SD карты байтовая и третий аргумент функции - SD_WriteBlock(0x00, writeBuffer, 512); число байт, в тоже время в модуль SDIO запись словами. На сколько надо увеличивать первый аргумент этой функции для записи следующего блока на 512(число байт) или на 128(число слов) ?

Nikita
Nikita
10 лет назад

Доброго времени суток.
Третий день сижу - уже до уровня регистров спустился (SDIO)...хоть убиться, карта не отвечает ни на одну команду. Причем после отправки, флаг в регистре статуса ставится, что ответ принят, а регистр ответа пуст...единственное, подключил без внешних подтягивающих резисторов(подтянул внутри МК)...

Nikita
Nikita
10 лет назад

Проблему решил внешними резисторами, спасибо, но есть еще проблема, может еще раз поможете? Никак флаг busy не снимается при инициализации. Вроде все правильно посылаю.
Может быть такое, что stm32f4 не поддерживает SDHC?

Илья
Илья
Ответ на комментарий  Nikita
6 лет назад

Нужно активировать DMA! Библиотека BSP его использует, а так как у вас оно не инициализировано, то контроллер и повисает в ожидании флага, который никогда не придет.

Nikita
Nikita
10 лет назад

Ладно, буду копать, если что, возьму у соседа SD)))

GLEP
GLEP
10 лет назад

Доброго времени суток, будет продолжение для SD про поддержку FAT?

Glep
Glep
10 лет назад

Я уверен что это все оценят положительно! ))

mirjalol
mirjalol
10 лет назад

вы мог дать принципиальный схема подключение сдкарты

mirjalol
mirjalol
10 лет назад

как можно соединит cd kartam в микроконроллера atmega8

mirjalol
mirjalol
10 лет назад

я должен записать звуковой сигнал на микроконтроллеру. но память не достаточно память мироконтроллера. есть такие устройства, что бы имеют 0.5-1Mb память

HexChanger
HexChanger
10 лет назад

Спасибо за драйвер, но у меня проект запустился после небольшой правки в файлах (запускал под СооСох). Просто так не заработал, ругается

Asferarum
Asferarum
9 лет назад

Сама статья полезная, но не сильно примечательная, но всё равно спасибо! А вот stm'овский проект с работой с sdio это просто сказка! Спасибо что выложили здесь! Пришлось поправить его, конечно, для stm32f4, с dma не разбирался, поэтому выключил её полностью. Ещё есть особенность, что в функции инициализации между deinit() и sdcard_on () необходимо вставить небольшую задержку, у меня иначе не начиналась работа с картой. Вообще перефирия молчала.
А можно привести ссылку или какую полезную инфу на связь sdio и fat?

Антон
8 лет назад

А распиновка точно правильная?
9й пин вообще находится в начале карты немного смещен от первого, а на этой схеме 9й это 1й?

илья
илья
8 лет назад

Здравствуйте, реализовал данный пример на stm32f4DISCO дма и конфигурацию пинов исправил, однако программа зацикливается в CmdResp1Error(). C чем это м.б. связано. Использую флешку на 4Gb.

while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
{
status = SDIO->STA;
} //Вот здесь циклит

Vano Pupkin
Ответ на комментарий  илья
8 лет назад

Ну с чем это может быть связано?
Капитан Очевидность: не взводится ни один флаг - SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT
Физический интерфейс правильно настроен? осциллограф или анализатор есть?

илья
илья
Ответ на комментарий  Vano Pupkin
8 лет назад

нету

teplofizik
teplofizik
8 лет назад

Запись с мусором ещё ладно, но вот это кажется мне весьма неосмотрительным:

uint32_t readBuffer[4];
SD_ReadBlock(0x00, readBuffer, 512);

Куда попадут лишние 496 байт знает только линкёр =)
SDCardInfo, скорее всего, придёт после этого в негодность.

Василий
Василий
7 лет назад

Взаимодействие с картой происходит через обычные порты ввода-вывода или SDIO это специальный физический интерфейс, привязанный к определенным ногам МК?

Василий
Василий
Ответ на комментарий  Василий
7 лет назад

Да. нашел. SDIO это специальный модуль. Только далеко на на всех STM32 он есть на борту.

AFZ
AFZ
6 лет назад

А где взять эти sdcard.c и sdcard.h? Поиск в папке Keil_v5 ничего не находит.

Александр
Александр
3 лет назад

Краткое и понятное изложение темы. Спасибо!

51
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x