>
Число комментариев: 1
Просмотров: 71

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

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