При разработках устройств часто бывает необходимым хранить настройки вне рабочей программы. Еще лучше иметь возможность их модификации без использования специальных средств.
Рассмотрим вариант хранения в пожалуй самых распространенных микроконтроллерах STM серии F103. Способствовала распространенности также всем известная макетная плата Blue Pill
Имеющаяся в ней 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)
Размер бинарного файла у меня получился около 20К, поэтому страница памяти данных у меня определена с 0x08006000 (24K).
Компилируем (исходники примера можно взять здесь).
Подключаем:
Диск определился, все отлично!
Приступим к формированию раздела и форматированию нашего диска.
В Linux это делать достаточно просто из командной строки:
отформатируем в FAT12:
Копируем файл для теста:
Однако, не следует забывать, что по документации, число циклов перезаписи flash
гарантировано лишь в пределах 100000. К примеру, форматирование и запись одного файла 30К займет (по отладочному журналу данного примера):
106 циклов перезаписи.
Остается вопрос — как можно читать данные, обращаясь непосредственно к файлам FAT12?
Об этом — в следующей статье.
Спасибо за внимание!
Рассмотрим вариант хранения в пожалуй самых распространенных микроконтроллерах STM серии F103. Способствовала распространенности также всем известная макетная плата Blue Pill
Имеющаяся в ней 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?
Об этом — в следующей статье.
Спасибо за внимание!