STM32F4 Работа с Flash SDIO (MicroSD) под FreeRTOS

В такой нагруженной системе важна аккуратность. У меня на столе 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 карты.

Все остается по дефолту за исключением выделенных моментов:

  1. Разрешить MKFS (форматирование флешки)
  2. Использовать кодовую страницу с поддержкой русскоязычных имен файлов
  3. Использовать длинные имена файлов (от 12 до 255 символов) с рабочим буфером в куче
  4. Ограничить длину файлов до 63 для экономии места в куче
  5. Работать во всем диапазоне размера секторов (доступны для FATFS - 512 - 4096 байт)

* * *

В расширенных настройках используется шаблон работы с DMA, а ввиду того, что FATFS работает под RTOS, этот параметр Forced и изменить его нельзя.

* * *

Так же потребуется организовать цифровой вход для определения наличия карты в слоте. Когда карты в слоте нет, то пин Detect висит в воздухе, когда карта есть, замкнут на землю.

* * *

У меня на прототипе этот пин никуда не подключен (и Detect на слоте, и PA15 на MCU), поэтому я подтяну его программно к земле. Когда он действительно подключен, то нужно подтягивать его к Vdd. Это нельзя упускать из виду иначе будут Error'ы при инициализации BSP_SD_Init.

в сгенерированном кубом коде, в функции DefaulTaskStart можно уже сделать первые действия:

  1. Инициализировать карточку
  2. Посмотреть информацию о ней
  3. Смонтировать
  4. Форматнуть
  5. Создать пустой файлик

  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);
  • }

На этом, пожалуй, все.