В такой нагруженной системе важна аккуратность. У меня на столе STM32F407VET6 со 128 кБ SRAM и 512 кБ FLASH. И на ней реализован Modbus TCP/IP, Modbus RTU RS485, Modbus RTU RS232, +CAN шлюз. Под FreeRTOS работают LwIP, FATFS. Для начальной "завязки" необходимо выделить память
- Под кучу FreeRTOS 32-48 kB
- Под стек LwIP 2048 B
Со временем постепенно можно увеличивать или оптимизировать эти значения, менять количество PBUF'ов, NETCONN'ов, размер стека задач и т.д. Но я привел значения, при которых минимальный объем задач FreeRTOS с остальными стеками, работающими одновременно, будет выполняться без глюков.
Статья по настройке и реализации LwIP еще пишется и когда будет готова, тогда можно будет посмотреть подробнее про реализацию стека.
SDIO настраивается в пользу универсальности по однобитной шине.
Вы можете использовать 4 битную, 8 битную, как угодно. Меня смущает один момент, что при инициализации 4 битной шины или 1 битной куб прописывает параметр 1-битной шины.
static void MX_SDIO_SD_Init(void)
{
...
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
...
}
SDIO и FATFS под FreeRTOS работают только с использованием DMA. Поэтому нужно включить DMA и прерывания для SDIO.
* * *
* * *
* * *
FATFS настраивается с использованием SD карты.
Все остается по дефолту за исключением выделенных моментов:
- Разрешить MKFS (форматирование флешки)
- Использовать кодовую страницу с поддержкой русскоязычных имен файлов
- Использовать длинные имена файлов (от 12 до 255 символов) с рабочим буфером в куче
- Ограничить длину файлов до 63 для экономии места в куче
- Работать во всем диапазоне размера секторов (доступны для FATFS - 512 - 4096 байт)
* * *
В расширенных настройках используется шаблон работы с DMA, а ввиду того, что FATFS работает под RTOS, этот параметр Forced и изменить его нельзя.
* * *
Так же потребуется организовать цифровой вход для определения наличия карты в слоте. Когда карты в слоте нет, то пин Detect висит в воздухе, когда карта есть, замкнут на землю.
* * *
У меня на прототипе этот пин никуда не подключен (и Detect на слоте, и PA15 на MCU), поэтому я подтяну его программно к земле. Когда он действительно подключен, то нужно подтягивать его к Vdd. Это нельзя упускать из виду иначе будут Error'ы при инициализации BSP_SD_Init.
в сгенерированном кубом коде, в функции DefaulTaskStart можно уже сделать первые действия:
- Инициализировать карточку
- Посмотреть информацию о ней
- Смонтировать
- Форматнуть
- Создать пустой файлик
BSP_SD_Init();
MX_FATFS_Init();
HAL_SD_CardInfoTypeDef Card_Info;
int8_t const card_type[3][15] = {"CARD_SDSC\0","CARD_SDHC_SDXC\0","CARD_SECURED\0"};
int8_t const card_ver [2][10] = {"CARD_V1_X\0","CARD_V1_X\0"};
volatile FRESULT fres;
printf("\n\rStart testing SDCARD\n\r");
BSP_SD_GetCardInfo(&Card_Info);
printf("Card Type -> %s\n", card_type[Card_Info.CardType]);
printf("Card Version -> %s\n", card_ver[Card_Info.CardVersion]);
printf("Block Size -> 0x%x\n", (int)Card_Info.BlockSize);
printf("Card Capacity in blocks -> 0x%x(%uGB)\n\r", (int)Card_Info.BlockNbr,(int)((((float)Card_Info.BlockNbr/1000)*(float)Card_Info.BlockSize/1000000)+0.5));
osDelay(5000);
fres = f_mount(&SDFatFS, (const TCHAR*)SDPath, 0);
printf("Mount FAT FS request sent\n");
printf("Formatting storage device\n");
void* work = malloc(512);
fres = f_mkfs((const TCHAR*)SDPath, FM_FAT32, 0, work, 512);
if (fres != FR_OK) {
printf("Formatting SD failed\n");
}
else {
printf("SD formatted\n");
}
free(work);
printf("Opening file\n");
fres = f_open(&SDFile, (const TCHAR*)"UMC2020-02-12.log", FA_CREATE_NEW | FA_WRITE);
if (fres == FR_OK) {
printf ("File opened\n");
f_close(&SDFile);
}
else {
printf("Error opening file. ExitCode = %i\n", fres);
}
osDelay(5000);
В заключение приведу важные тонкости:
- Переменные SDDataFS, SDPath, SDFile уже созданы в fatfs.h и они глобальные
- Коды ошибок, которые может вернуть FAT_FS:
- /* File function return code (FRESULT) */
- typedef enum {
- FR_OK = 0, /* (0) Succeeded */
- FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
- FR_INT_ERR, /* (2) Assertion failed */
- FR_NOT_READY, /* (3) The physical drive cannot work */
- FR_NO_FILE, /* (4) Could not find the file */
- FR_NO_PATH, /* (5) Could not find the path */
- FR_INVALID_NAME, /* (6) The path name format is invalid */
- FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
- FR_EXIST, /* (8) Access denied due to prohibited access */
- FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
- FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
- FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
- FR_NOT_ENABLED, /* (12) The volume has no work area */
- FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
- FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
- FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
- FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
- FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
- FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
- FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
- f_mount - монтирование файловой системы может происходить в фоновом режиме (последний параметр 0) или немедленно (последний параметр 1). В первом случае функция всегда вернет "успех" не зависимо от того примонтировалась флешка или нет.
- По-умолчанию создаваемые файлы не имеют даты создания, даты изменения и каких-либо прав.
- Файловая система, созданная в Windows, а так же файлы, созданные там же могут работать некорректно, если у файлов ограничены права доступа или размер сектора ФС не поддерживается FATFS. Для работы в FATFS лучше переформатировать флешку тут же, в FATFS.
- FATFS использует отдельную задачу FreeRTOS и обменивается сообщениями по прерыванию DMA.
- Вне задачи FreeRTOS инициализация не пройдет.
- Все операции с файлами нужно делать в задачах FreeRTOS
- Тонкости работы с драйвером SD карты прописаны в sd_diskio.c
- Зависает в vPortRaiseBASEPRI - FATFS/SDIO/DMA имеет приоритет прерываний выше, чем RTOS или задаче не хватает памяти в стеке.
- Функция f_printf не записывает данные в файл немедленно, а делает это отложенной задачей. Функция всегда вернет успех.
- Для записи лучше использовать функцию f_write, она пишет в файл просто буфер байт (без форматирования а-ля printf), но зато более строга в проверке файловой системы и устройства.
- Обе операции пишут в буфер. Чтобы из буфера переместить данные на флешку, нужно использовать f_sync(&file);
- fr = f_write(&SDFile, "ABCDEFG", 7, (UINT*)&temp);
- if (fr != FR_OK) printf("Fail to write. Error: %i\n", fr);
- else {
- printf("Buffer written\nDo sync\n");
- fr = f_sync(&SDFile);
- if (fr != FR_OK) printf("Fail to sync file & buf. Error: %i", fr);
- else printf("Write success. Written %i bytes\n", temp);
- }
На этом, пожалуй, все.