При проектировании устройства на микроконтроллере бывает встает вопрос об обновлении прошивки прибора. Причем сам процесс обновления прошивки должен быть простым и доступным для обыкновенного пользователя. И конкретно для микроконтроллера STM32F103C8 возможна загрузка прошивки по UART. То есть к схеме необходимо добавлять микросхему конвертера USB-UART. Либо воспользоваться аппаратными возможностями USB микроконтроллера, что я и сделал. Меня заинтересовал вопрос о возможности обновления прошивки по USB. На некоторых МК даже есть аппаратный USB-загрузчик, но только не на STM32F103C8, поэтому пришлось все программно реализовывать. По программной части для STM32 существует USB Library от STMicroelectronics с реализованными классами USB и примерами. В частности заинтересовал класс DFU т.е. загрузка прошивки по USB. В данном классе уже реализован свой набор команд для взаимодействия МК и приложения на ПК "STM32CubeProgrammer". Но мне хотелось что-то своё, кастомное и неограниченное данным набором команд. И пришла мысль "А почему бы не реализовать всё это в классе CDC?". Тут и размер загрузчика примерно таким же оказался, но главное можно реализовать свой набор команд, работать на ПК с последовательным портом и соответственно понятнее, как написать приложение для ПК. У меня есть небольшой опыт написания приложений с использованием библиотеки QT на С++, поэтому с ее помощью была создана программа для USB загрузчика.
Рассмотрим работу и настройку самого загрузчика на МК. Проект создан в STM32CubeIDE, размер загрузчика получился 15 кБ. В файле main.c есть условие при котором МК работает в режиме загрузчика, либо управление передается пользовательскому приложению:
if((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==GPIO_PIN_RESET));
Мы можем по желанию задать любое условие входа в режим загрузчика, в моем случае нужно замкнуть ножку В0 на землю при загрузке МК. И тогда МК перейдет в режим загрузчика и при подключении по USB на стороне ПК будет определяться как виртуальный COM порт. В ином случае будет выполняться основная прошивка. В файле Memory.h заданы адреса начала основной прошивки и конца памяти программ:
#define APPLICATION_ADDRESS 0x08003C00
#define FLASH_END 0x0801FFFF
Теперь подготовим пользовательскую прошивку к загрузке. Для примера возьмем простое моргание светодиодом. В проекте для CubeIDE в файле STM32F103C8TX_FLASH.ld нужно изменить адрес начала выполнения программы на 0х8003С00:
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8003C00, LENGTH = 64K
}
В файле system_stm32f1xx.c задать смещение таблицы векторов 0х3С00:
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x3C00 /*!< Vector Table base offset field.
This value must be a multiple of 0x200.
*/
Теперь можно перейти к загрузке данной прошивки. Ставим перемычку на ножке B0 и подключаем по USB плату. Запускаем приложение "USB CDC Программатор":
Для поиска доступных COM портов нажимаем "Обновить", в списке выбираем появившийся порт и нажимаем "Подключить". Выдаст сообщение об успешном подключении платы и название кнопки подключения изменится на "Отключить":
Если до этого в плату была загружена другая прошивка, то ее необходимо удалить, нажав на "Стереть". При этом затирается вся область памяти начиная с адреса 0х8003С00 и до конца памяти программ. Далее нажимаем "Открыть" и в диалоговом окне выбираем файл прошивки в формате .bin (Пока поддерживается только такой формат файлов). В таблице появляются данные прошивки, в логах название и размер файла. Нажимаем "Загрузить" и через некоторое время прошивка будет загружена:
Теперь можно отключить плату, убрать перемычку и убедиться в работоспособности прошивки. При необходимости возможно считать прошивку и сохранить ее в файле на компьютере. Считывание памяти МК происходит начиная с адреса 0х8003С00 и до первого числа 0хFFFFFFFF.
К статье прикладываю: