Pull to refresh

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

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

Рассмотрим вариант хранения в пожалуй самых распространенных микроконтроллерах 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).

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

Подключаем:

[ 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



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

sudo mkfs.fat /dev/sdb -F 12

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



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

00106 44 67 Write_FS blk_addr=003 0x08006600 

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

Остается вопрос — как можно читать данные, обращаясь непосредственно к файлам FAT12?
Об этом — в следующей статье.
Спасибо за внимание!
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 38: ↑37 and ↓1+36
Comments12

Articles