Перейти к загрузчику в STM32 с помощью приложения, используя Boot 0 и Boot 1 Pins в режиме загрузки из пользовательской вспышки

Вопрос:У меня есть требование для обновления прошивки. Я планирую использовать класс USB DFU. Но команда для обновления прошивки будет поступать из приложения для ПК в моем случае. поэтому мне нужно переключиться на загрузчик, который есть в Системной памяти. Как изначально я запускаю приложение, поэтому он загружается из User flash. У меня есть Boot0 и Boot

Вопрос:

У меня есть требование для обновления прошивки. Я планирую использовать класс USB DFU. Но команда для обновления прошивки будет поступать из приложения для ПК в моем случае. поэтому мне нужно переключиться на загрузчик, который есть в Системной памяти. Как изначально я запускаю приложение, поэтому он загружается из User flash. У меня есть Boot0 и Boot 1 булавки, настроенные для User flash. Поскольку загрузчик DFU находится в System flash, теперь для этих настроек Boot0 и Boot1 необходимо изменить настройки. есть ли способ, как Boot 0, и настройки Boot 1 остаются такими же, как пользовательская флэш-память, а в приложении мы переходим к системной памяти?

Лучший ответ:

Бутылки Boot0/1 отбираются только при запуске процессора, чтобы проверить, следует ли загружать код пользователя из памяти или загружать загрузчик.
Состояние этих контактов не влияет на загрузчик после этого.

Я столкнулся с аналогичным запросом и нашел два способа загрузки загрузчика по требованию.

Во-первых, вы можете “JUMP” от пользовательского кода к загрузчику. Например, вы можете перейти к загрузчику при нажатии кнопки.

Но… это намного сложнее, чем простая инструкция JUMP: некоторые регистры и устройства должны быть перенастроены правильно для работы с загрузчиком, вы должны убедиться, что IRQ не будет запущен во время JUMP,… In факт, вы должны перенастроить процессор, как будто он был запущен только после reset.
Вы можете найти информацию об этой технике: на этом видео с ST.

Мне удалось сделать такие вещи в проекте STM32F1xx.
Однако в более сложном проекте, основанном на STM32F4, это станет действительно трудным… Я должен был бы остановить все устройства (таймеры, интерфейс связи, ADC, ЦАП,…), гарантировать, что IRQ не будет запущен, переконфигурируйте все часы,…

Вместо этого я решил реализовать это второе решение: когда я хочу перейти к загрузчику, я пишу байт в одном из резервных регистров, а затем выдаю soft- reset. Затем, когда процессор перезагрузится, в самом начале программы он будет читать этот регистр. Этот регистр содержит значение, указывающее, что он должен перезагружаться в режиме загрузчика. Затем переход к загрузчику намного проще, как представлено в видео youtube.

Ответ №1

Чтобы перейти к новому изображению, это не так сложно. Я сделал это успешно как часть самотестирования.

  • Вам нужно передать адрес, где ваше второе изображение (загрузчик в этом случае) находится во флэш-памяти для компоновщика, когда вы связываете второе изображение. Вместо этого вы можете использовать код с независимой позицией, но у него есть другие проблемы.
  • Вы должны, очевидно, запустить программу второго изображения, начиная с того же адреса, что и вы предоставили компоновщик.
  • Задайте функцию перехода: void (* const jumpFunction)(void) = (void (*)(void))(APPLICATION_ADDRESS + 4ul + 1ul); Смещение на четыре означает пройти указатель стека, смещение на единицу для Thumbmode.
  • Укажите новый стартовый указатель стека: __set_MSP((uint32_t)*APPLICATION_ADDRESS), первые четыре байта со второго изображения будут содержать новый указатель стека.
  • Перейдите, вызвав функцию: jumpFunction();
  • Во второй программе инициализация по умолчанию попытается установить смещение таблицы векторов (VTOR) SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;. Вы должны изменить это на SCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET;

У меня есть программа POST в FLASH_BASE, которая использует связанный с базой SRAM для своего стека, а затем запускает проверки памяти на основной SRAM, проверяет подлинность основной программы и затем переходит к основной программе.

Я все еще могу отлаживать основную программу, как будто ничего не изменилось.

NB! Я только недавно сделал это сам. Есть несколько вещей, которые мне нужно проверить. Одна из проблем заключается в том, что произойдет с программным обеспечением reset. Если вы вызовете из второй программы, то, по моему мнению, она будет выполняться в reset подпрограмме второй программы, а не первой.

Ответ №2

В MicroPython есть функция pyb.bootloader(), которая используется для входа в режим DFU.

Код C, который реализует это, можно найти в исходном репозитории.

Я широко использовал версию STM32F4 (блок #else) и вариант F7 несколько раз (хотя его в то время).

Я поместил бы тело функции здесь, так как вышеупомянутые ссылки могут стать устаревшими, если этот файл изменится:

// Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { pyb_usb_dev_deinit(); storage_flush(); HAL_RCC_DeInit(); HAL_DeInit(); #if defined(MCU_SERIES_F7) // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x1FF00000)); __ASM volatile («movw r3, #0x0000nmovt r3, #0x1FF0nldr r3, [r3, #0]nMSR msp, r3n» : : : «r3», «sp»); ((void (*)(void)) *((uint32_t*) 0x1FF00004))(); #else __HAL_REMAPMEMORY_SYSTEMFLASH(); // arm-none-eabi-gcc 4.9.0 does not correctly inline this // MSP function, so we write it out explicitly here. //__set_MSP(*((uint32_t*) 0x00000000)); __ASM volatile («movs r3, #0nldr r3, [r3, #0]nMSR msp, r3n» : : : «r3», «sp»); ((void (*)(void)) *((uint32_t*) 0x00000004))(); #endif while (1); }

Функция pyb_usb_dev_deinit() отключает USB, а storage_flush записывает данные кэшированной файловой системы. Функции HAL исходят из файлов HAL STM32Cube.

Если вы используете более новую версию dfu-util (IIRC 0.8 или новее), вы можете указать опцию командной строки -s :leave, чтобы ваша недавно сверкнувшая программа выполнялась в конце мигания. Объединяясь с вышеизложенным, я прохожу через циклы вспышки/тестирования, не прикасаясь к плате, и используйте только BOOT0/RESET, когда прошивка жестко сработает.

Существует также python DFU flasher, называемый pydfu.py: https://github.com/micropython/micropython/blob/master/tools/pydfu.py, который немного быстрее, чем dfu-util.

Ответ №3

Вы можете имитировать состояние загрузчика. Подключите конденсатор и резистор параллеля от штыря BOOT к земле. Подключите другой свободный штырь к штырю BOOT. Конденсатор может заряжаться внешним штырем и разряжается резистором. Я не помню точные значения, которые вы можете рассчитать/поэкспериментировать (важна постоянная времени RC-схемы).

Зарядите этот конденсатор, установив внешний контакт на 1, выполните программное обеспечение reset на NVIC_SystemReset. После reset он запустит загрузчик. Резистор, подключенный к конденсатору, будет выполнять разрядку. После обновления прошивки вы можете reset устройство и оно будет работать в вашем приложении.

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

Оцените статью
Добавить комментарий