Главная » Хабрахабр » [Из песочницы] STM32 bootloader DFU mode с использованием CubeMX. Инструкция пошаговая, step by step

[Из песочницы] STM32 bootloader DFU mode с использованием CubeMX. Инструкция пошаговая, step by step

Итак, сочинение сего мандригала было сподвигнуто практически полным отсутствием пошаговой инструкции с использованием обычного инструментария предлагаемого STMicroelectronics.

Великое множество обнаруженных в сети bootloader-ов, иногда весьма занятных, к сожалению «заточены» под какой-либо конкретный кристалл.

Мы абстрагируем наши «хотелки» от железки, да простят меня гуру макроассемблера и даташита.
Готовим окружение… Предлагаемый материал содержит процедуру использования пакета CubeMX, «загружалки» DfuSeDemo и утилиты подготовки прошивки Dfu file manager, т. е.

Нам необходимы собственно сам CubeMX, загружалка DfuSeDemo+Dfu file manager, лежат в одном пекете, STM32 ST-LINK Utility, все изыскиваем на сайте STMicroelectronics совершенно бесплатно.

Наша подопытная жлезка с чипом STM32F103C8T6 от дядюшки Ляо

image

и программатор ST-Link оттуда же.

image

Ну и ваша любимая IDE, в данном конкретном изложении мы используем KEIL, настройки компиляции в других IDE не очень отличаются.

Итак, поехали…

Запускаем CubeMX и выбираем свой кристалл…

image

Отмечаем свои хотелки…

image

В данной конкретной задаче активируем устройство USB→Device FS и соответсвенно USB Device→ DownLoad Update Firmware class, и незабываем RCC→High Speed Clock→Cristal/Ceramic Resonator тот что на борту платы.

Далее необходимо выбрать переключалку режима bootloader-a, в данном примере просто задействуем имеющуюся перемычку boot1.

image

Смотрим схемку и в соответствии с ней boot1 прицеплен к ноге PB2, вот ее и задействуем в режиме GPIO_Input.

Готово, активируем закладку Clock Configuration и запускаем автомат выбора конфигурации.

image
Прыгаем на закладку Cofiguration…

image

Выбираем кнопку GPIO…

image

И в поле…

image
пишем пользовательскую метку, пусть это будет boot1.

Далее настраиваем проект…

image

Выбираем Project → Setting…

image

Выбираем и заполняем….

image

Соответсвенно выбираем для какого IDE нам Cub сгенерит проект, в нашем случае, MDK-ARM V5.

Закладку Code Generator в данном воплощении оставим без изменений…

image

Ну собственно и все, запускаем генерацию проекта Project→Generate Code

image

По окончании Cub предложит сразу запустить вашу IDE… как поступать выбирать вам.

image

image

Запускаем компиляцию и сборку и загрузку в кристалл… F7, F8…

image

Конечный итог…

Переключаем пины на нашей плате в режим работы и подключаем USB кабель…

image

image

И смотрим список устройств, Windows немого пошуршит и установит драйвер STM Device in DFU Mode (если он уже не стоял). Открываем в Windows панель управления→ система→ диспечер устройтв→ USB контроллер.

Итак, драйвер встал и определился, запускаем «загружалку» DfuSeDemo…

image

Смотрим что у нас поймалось DFU Device и дажды кликаем в поле Select Target …

image

Внимательно смотрим и дивимся, что флеш вплоть до адреса 0x0800C000 закрыт для записи и записываем этот адрес, он нам понадобится…

С самого начала… почему, в нашем варианте не так, неясно, да и не копал, где то зарыто, но явно не прописано, не есть комильфо, потому что большой кусок пропадает безхозно… может кто и подскажет где копать… К слову, пробовал на STM32F407VE, там память открыта для записи с 0x08000000 т. е.

Итак, «стрижка только начата»…

Нам понадобится только два файла исходников…

image

Открываем их в IDE и правим- дополняем…

Учитываем, что CubeMX НЕ ТОГАЕТ при перегенерации вставки между USER CODE BEGIN и USER CODE END… там и будем вписывать наши дополнения…

Начнем с main.c

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
typedef void (*pFunction)(void); pFunction JumpToApplication;
uint32_t JumpAddress; /* USER CODE END PV */
.
.
.
/* USER CODE BEGIN 0 */ uint32_t AddressMyApplicationBegin = 0x0800C000; uint32_t AddressMyApplicationEnd = 0x0800FBFC; /* USER CODE END 0 */
.
.
.
/* USER CODE BEGIN 2 */ /* Check if the KEY Button is pressed */
if(HAL_GPIO_ReadPin(boot1_GPIO_Port, boot1_Pin ) == GPIO_PIN_SET)

} MX_USB_DEVICE_Init(); /* эту функцию просто переносим сверху */ /* USER CODE END 2 */
.
.
.

на этом с main.c все…

переходим на в usbd_conf.h и в

#define USBD_DFU_APP_DEFAULT_ADD 0x0800000

приводим к виду…

#define USBD_DFU_APP_DEFAULT_ADD 0x080C000 // наш адрес записанный на бумажке…

переходим к usbd_dfu_it.c, тут поболее….

.
.
.
/* USER CODE BEGIN PRIVATE_TYPES */
extern uint32_t AddressMyApplicationBegin; extern uint32_t AddressMyApplicationEnd; /* USER CODE END PRIVATE_TYPES */ .
.
.
/* USER CODE BEGIN PRIVATE_DEFINES */
#define FLASH_ERASE_TIME (uint16_t)50
#define FLASH_PROGRAM_TIME (uint16_t)50
/* USER CODE END PRIVATE_DEFINES */
.
.
.
и собственно правим, а вернее заполняем «пустышки» рабочим кодом… uint16_t MEM_If_Init_FS(void)
{ /* USER CODE BEGIN 0 */ HAL_StatusTypeDef flash_ok = HAL_ERROR; //Делаем память открытой while(flash_ok != HAL_OK){ flash_ok = HAL_FLASH_Unlock(); } return (USBD_OK); /* USER CODE END 0 */ }
.
.
.
uint16_t MEM_If_DeInit_FS(void)
{ /* USER CODE BEGIN 1 */ HAL_StatusTypeDef flash_ok = HAL_ERROR; //Закрываем память flash_ok = HAL_ERROR; while(flash_ok != HAL_OK){ flash_ok = HAL_FLASH_Lock(); } return (USBD_OK); /* USER CODE END 1 */ }
.
.
. uint16_t MEM_If_Erase_FS(uint32_t Add)
{ /* USER CODE BEGIN 2 */ uint32_t NbOfPages = 0; uint32_t PageError = 0; /* Variable contains Flash operation status */ HAL_StatusTypeDef status; FLASH_EraseInitTypeDef eraseinitstruct; /* Get the number of sector to erase from 1st sector*/ NbOfPages = ((AddressMyApplicationEnd - AddressMyApplicationBegin) / FLASH_PAGE_SIZE) + 1; eraseinitstruct.TypeErase = FLASH_TYPEERASE_PAGES; eraseinitstruct.PageAddress = AddressMyApplicationBegin; eraseinitstruct.NbPages = NbOfPages; status = HAL_FLASHEx_Erase(&eraseinitstruct, &PageError); if (status != HAL_OK) { return (!USBD_OK); } return (USBD_OK); /* USER CODE END 2 */ }
.
.
.
uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{ /* USER CODE BEGIN 3 */ uint32_t i = 0; for(i = 0; i < Len; i+=4) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by byte */ if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest+i), *(uint32_t*)(src+i)) == HAL_OK) {
// Usart1_Send_String("MEM_If_Write_FS OK!"); /* Check the written value */ if(*(uint32_t *)(src + i) != *(uint32_t*)(dest+i)) { /* Flash content doesn't match SRAM content */ return 2; } } else { /* Error occurred while writing data in Flash memory */ return (!USBD_OK); } } return (USBD_OK); /* USER CODE END 3 */ }
.
.
.
uint8_t *MEM_If_Read_FS (uint8_t *src, uint8_t *dest, uint32_t Len)
{ /* Return a valid address to avoid HardFault */ /* USER CODE BEGIN 4 */ uint32_t i = 0; uint8_t *psrc = src; for (i = 0; i < Len; i++) { dest[i] = *psrc++; } return (uint8_t*)(dest); /* ВНИМАТЕЛЬНО, В ГЕНЕРАЦИИ ПО УМОЛЧАНИЮ ДРУГОЕ*/ /* USER CODE END 4 */ }
.
.
.
uint16_t MEM_If_GetStatus_FS (uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{ /* USER CODE BEGIN 5 */ switch (Cmd) { case DFU_MEDIA_PROGRAM: buffer[1] = (uint8_t)FLASH_PROGRAM_TIME; buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8); buffer[3] = 0; break; case DFU_MEDIA_ERASE: default: buffer[1] = (uint8_t)FLASH_ERASE_TIME; buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8); buffer[3] = 0; break; } return (USBD_OK); /* USER CODE END 5 */ }

Собственно и все…

Подключаем программатор, перекидываем перемычки в режим программирования, F7, F8 и botloader записан…

Можно пользоваться…

Теперь подготовим наше приложение для загрузки посредством bootloder…
Любимое приложение будет моргать светодиодиком…

Готовим и отлаживаем приложение, и меняем в компиляторе и теле программы отдельные места на предмет изменения адреса запуска программы и векторов прерываний…

А именно в KEIL → Configure → Flash Tools

image

Меняем адрес начала программы…

image

Говорим чтобы генерировал HEX файл

image

и меняем адрес таблицы векторов…

собираем программу F7…

полученный HEX преобразуем в dfo файл утилитой Dfu file manager…

image

указываем наш HEX файл кнопкой S19 or HEX… и жмем Generate…

image

получаем dfu файл.

Собственно и все готово.

Загрузка в контроллер…

Подключаем нашу подопытную плату с уже загруженным botloader-ом к USB, предварительно установив перемычки в режим DFU Mode.

image

Можно проконтролировать появлением STM Device in DFU Mode в списке устройст…
запускаем «загружалку».

image
указываем ей наш dfu файл…

image

Жмем Upgrade и наблюдаем результат загрузки… для уверенности, жмем проверку.

image

все удачно… можно запускать…

если ошибка вылезла, значит где-то косяк…

image

например…

Итак, будем считать что все удачно… переключаем перемыку в режим работы приложения

image

Столько букоффф. и наслаждаемся миганием диодика…

Уффф. Устал копипастить картинки 🙂

Все, спасибо за внимание…


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Перенос конфигурации АТС в сервис 3CX PBX Express

В этой статье мы расскажем, как в сервисе 3CX PBX Express восстанавливать резервные копии существующих инсталляций АТС. Возможность восстановления конфигурации позволяет, например, переместить локальный сервер в облако, сменить хостинг или восстановить АТС в облаке после серьезного локального сбоя. Единственное требование ...

Первые штрафы по GDPR: кого уже наказали

GDRP вступил в силу больше шести месяцев назад, но первые «письма счастья» регуляторы начали выписывать лишь недавно. В материале — о тех компаниях, которые их уже получили. / фото Kiefer CC BY-SA «Мягкий запуск» GDPR GDPR вступил в силу 25 ...