Pull to refresh

Упрощенный доступ к данным внутренней FAT12 для STM32

Reading time 3 min
Views 4.8K
В предыдущей статье был рассмотрен вариант использования микроконтроллера STM32F103C8T6 как flash накопителя с внутренней файловой системой FAT12. Теперь можно рассмотреть, каким образом получить данные из нашей внутренней файловой системы. К примеру нам необходимо хранить некие настройки нашей программы.
Для хранения именованных настроек особого усложнения структур формата данных не потребуется. Примем следующий формат — одна настройка = один файл. К примеру, нам необходимо хранить скорость подключения по UART и допустим, задержку в миллисекундах мигания светодиода. Создадим (в любом текстовом редакторе) в нашей файловой системе файлы UART_SPD.SET и DELAY_BL.SET. Запишем в них значения: соответственно 115200 и 1000.
Чтобы получить эти данные, обратившись к нашей внутренней FAT12 потребуется либо взять стандартную библиотеку HAL FatFs и попытаться ее приспособить под внутреннюю flash. Или пойти более простым и удобным способом — написать свою функцию чтения файловых данных FAT12, что мы и сделаем:

uint8_t f12_read_data (
char *file_name,                // имя файла для поиска в формате 11 символов - "NAME    TXT"
char **file_data,               // здесь будут данные найденного файла
char *file_list,                // здесь будет список файлов
uint16_t file_list_size)  {     // размер для списка файлов
 // FAT12 - http://elm-chan.org/docs/fat_e.html
  uint16_t BPB_BytsPerSec;
  uint8_t  BPB_NumFATs;
  uint16_t BPB_RootEntCnt;
  uint16_t BPB_RsvdSecCnt;
  uint16_t BPB_FATSz16;
  uint8_t  BPB_SecPerClus;
  uint16_t BS_BootSign;
  uint8_t  found=0;
  uint16_t cluster_no;

  char     *fname;
  uint32_t SEEK_FAT12_NAMES_OFFSET;
  uint32_t SEEK_FAT12_NAMES_OFFSET_END;
  uint32_t SEEK_DATA_OFFSET;
  uint32_t fs;

  // Получим данные FAT12
  BPB_BytsPerSec=uint16_t_from_internal_flash(PAGE_ADDR+11);
  BPB_NumFATs=uint8_t_from_internal_flash(PAGE_ADDR+16);
  BPB_RootEntCnt=uint16_t_from_internal_flash(PAGE_ADDR+17);
  BPB_RsvdSecCnt=uint16_t_from_internal_flash(PAGE_ADDR+14);
  BPB_FATSz16=uint16_t_from_internal_flash(PAGE_ADDR+22);
  BPB_SecPerClus=uint8_t_from_internal_flash(PAGE_ADDR+13);
  BS_BootSign=uint16_t_from_internal_flash(PAGE_ADDR+510);

  if (BS_BootSign != 0xAA55) { // неверная сигнатура boot сектора FAT
      return FAT12_ERR_BAD_FAT;
  }

  SEEK_FAT12_NAMES_OFFSET = (BPB_RsvdSecCnt+(BPB_FATSz16 * BPB_NumFATs)) * BPB_BytsPerSec; // отступ на начало имен
  SEEK_FAT12_NAMES_OFFSET_END=SEEK_FAT12_NAMES_OFFSET +
                            (((32 * BPB_RootEntCnt + BPB_BytsPerSec - 1) / BPB_BytsPerSec) * BPB_BytsPerSec); // отступ на конец имен

  SEEK_DATA_OFFSET= BPB_BytsPerSec * BPB_RsvdSecCnt+ // Boot сектор + резерв
                     ((BPB_FATSz16 * BPB_NumFATs) * BPB_BytsPerSec) + // Размер FAT
                     BPB_RootEntCnt*32; // Размер имен и хар-к файлов

  if (file_list_size > 0) // обнулить строку списка файлов
             file_list[0]=0;
  while (SEEK_FAT12_NAMES_OFFSET < SEEK_FAT12_NAMES_OFFSET_END)  {
    fname = char_from_internal_flash(PAGE_ADDR+SEEK_FAT12_NAMES_OFFSET);
    cluster_no  = uint16_t_from_internal_flash(PAGE_ADDR + SEEK_FAT12_NAMES_OFFSET + 0x1A);
    fs = uint32_t_from_internal_flash(PAGE_ADDR + SEEK_FAT12_NAMES_OFFSET + 0x1C);
       if ((file_list_size > 0) && 
           (strlen(file_list)+20 < file_list_size) && 
           (cluster_no  > 0)) {
              sprintf(file_list,"%s%11s %06d bytes\r\n",
                      file_list,fname, fs); // дополним полный список файлов
       }
       for (int i=0;i<9;i++) { // упрощенный поиск по имени файла
        	  if (fname[i] != file_name[i]) {
			  found=0;
			  break;
        	  }
        	found=1;
       }

       if (found==1) 
       break;

       SEEK_FAT12_NAMES_OFFSET+=0x20;
  }
     if (found == 0) {
         return FAT12_ERR_FILE_NOT_FOUND;
     }
    if ( *file_data != 0 ) {
      *file_data=char_from_internal_flash(PAGE_ADDR+(cluster_no-2) *
              (BPB_SecPerClus * BPB_BytsPerSec) + // Размер кластера
              SEEK_DATA_OFFSET);
     }
      return 0;
 }

Теперь — получаем значение необходимой настройки:

f12_read_data("UART_SPDSET" /*имена без точек, дополнение по 11 символов - пробелами*/,&fdata, file_list, 200);


В массиве fdata будет находится строка «115200», которую можно перевести в целое используя функцию atoi():
Проект с исходниками можно взять здесь.

На этом — всё. Спасибо за внимание!
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+10
Comments 12
Comments Comments 12

Articles