- PVSM.RU - https://www.pvsm.ru -

STM32F103C8T6 как накопитель flash с файловой системой FAT12

STM32F103C8T6 как накопитель flash с файловой системой FAT12

При разработках устройств часто бывает необходимым хранить настройки вне рабочей программы. Еще лучше иметь возможность их модификации без использования специальных средств.

Рассмотрим вариант хранения в пожалуй самых распространенных микроконтроллерах STM серии F103. Способствовала распространенности также всем известная макетная плата Blue Pill

image
Имеющаяся в ней flash позволяет не только хранить и модифицировать настройки используя файловую систему FAT12 во внутреннем flash, но и организовать обновление прошивки.

Согласно документации в STM32F103C8T6 имеется 64К flash памяти. Однако практически во всех STM32F103C8T6 установлено 128К. Об этом также упоминается в разных источниках — обычно ставят на 64К больше. Такая «фича» позволяет использовать микроконтроллер как flash накопитель объемом 128К — 20К (системные нужды FAT12) — размер прошивки.

Многие энтузиасты, пытавшиеся использовать данный контроллер как накопитель flash, сталкивались с проблемой его использования в режиме файловой системы FAT12. Использовать для снятия/заливки образа диска получалось. А вот при работе как с файловым накопителем начинались проблемы.

Эта проблема заключается в разной последовательности доступа к секторам (блокам). При загрузке образа диска запись происходит последовательно, например:

-запись блока №1,
-запись блока №2,
-запись блока №3.

При записи данных FAT12 запись может происходить произвольно:

-запись блока №3,
-запись блока №1,
-запись блока №2.

И, так как для записи во flash требуется стирать всю страницу размером 1К, то при использовании в накопителе секторов размером 512 байт (а использовать другие размеры сектора не удается), если используется произвольный доступ — стирается информация в соседнем секторе. Чтобы этого не происходило, в приведенном примере используется массив 512 байт для хранения соседнего сектора. И запись должна происходить следующим образом:

— определяем адрес начала страницы,
— запоминаем соседний сектор,
— стираем страницу,
— пишем запомненный сектор,
— пишем данные.

Чтобы не углубляться в дебри железа без требуемой необходимости, проект я подготовил в CubeMX.

Приведу пример функции записи во flash через HAL (usbd_storage_if.c)

// функция записи во flash
void writeBuf (uint32_t page_addr, uint8_t *buf){
   uint32_t erase_addr=get_erase_addr(page_addr);
   uint32_t buf_erase_addr;
   uint32_t buf32;
   if (page_addr != erase_addr) { 
       buf_erase_addr=erase_addr;
   }   else    {
       buf_erase_addr=erase_addr+STORAGE_BLK_SIZ;
     }
    HAL_FLASH_Unlock();

// вызываем функцию сохранения соседнего сектора
   set_buf_before_erase(buf_erase_addr);

// заполняем структуру записи сектора и стираем
   FLASH_EraseInitTypeDef EraseInitStruct;
   uint32_t PAGEError = 0;
   EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
   EraseInitStruct.PageAddress = erase_addr;
   EraseInitStruct.NbPages     = 1;
   HAL_FLASHEx_Erase(&EraseInitStruct,&PAGEError);

   // запишем сохраненный буфер
   for (int i=0; i<STORAGE_BLK_SIZ/4;i++) {
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,buf_erase_addr,blk_buff[i]);
    buf_erase_addr+=4;
    }
   // запишем данные
   for (int i=0; i<STORAGE_BLK_SIZ/4;i++) {
    buf32=*(uint32_t *)&buf[i*4];
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, page_addr,buf32);
    page_addr+=4;
    }
    HAL_FLASH_Lock();
}

Размер бинарного файла у меня получился около 20К, поэтому страница памяти данных у меня определена с 0x08006000 (24K).

Компилируем (исходники примера можно взять здесь). [1]

Подключаем:

[ 8193.499792] sd 4:0:0:0: Attached scsi generic sg2 type 0
[ 8193.502050] sd 4:0:0:0: [sdb] 128 512-byte logical blocks: (65.5 kB/64.0 KiB)
[ 8193.502719] sd 4:0:0:0: [sdb] Write Protect is off
[ 8193.502722] sd 4:0:0:0: [sdb] Mode Sense: 00 00 00 00
[ 8193.503439] sd 4:0:0:0: [sdb] Asking for cache data failed
[ 8193.503445] sd 4:0:0:0: [sdb] Assuming drive cache: write through
[ 8193.523812]  sdb:
[ 8193.526914] sd 4:0:0:0: [sdb] Attached SCSI removable disk

Диск определился, все отлично!

Приступим к формированию раздела и форматированию нашего диска.

В Linux это делать достаточно просто из командной строки:

sudo fdisk /dev/sdb

STM32F103C8T6 как накопитель flash с файловой системой FAT12 - 2

отформатируем в FAT12:

sudo mkfs.fat /dev/sdb -F 12

Копируем файл для теста:

STM32F103C8T6 как накопитель flash с файловой системой FAT12 - 3

Однако, не следует забывать, что по документации, число циклов перезаписи flash
гарантировано лишь в пределах 100000. К примеру, форматирование и запись одного файла 30К займет (по отладочному журналу данного примера):

00106 44 67 Write_FS blk_addr=003 0x08006600 

106 циклов перезаписи.

На этом — все. Спасибо за внимание!

Автор: VladimirKuzmin

Источник [2]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/stm32/309858

Ссылки в тексте:

[1] Компилируем (исходники примера можно взять здесь).: https://github.com/vvkuzmin1973/STM32F103FlashDrive

[2] Источник: https://habr.com/ru/post/441660/?utm_source=habrahabr&utm_medium=rss&utm_campaign=441660