- PVSM.RU - https://www.pvsm.ru -

Заливка прошивки в STM32 через USB

image

В своем проекте я использую микроконтроллер STM32F103C8 [1] и фреймворк stm32duino [2]. Этот клон Ардуино предлагает специальный бутлоадер, который позволяет заливать прошивку через USB, без использования внешних компонентов типа ST-Link или USB-UART переходника.

Сегодня мне понадобилось поработать с голым контроллером из-под CooCox и без stm32duino. Но вот в чем проблема. Даже простая моргалка лампочкой влитая через этот бутлоадер не работает.

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

Я ничего не имею против ST-Link и других отладчиков. Но в моем готовом устройстве его не будет, но точно будет USB. Почему бы сразу не заложить возможность обновлять прошивку через USB? Лично я нахожу этот способ удобным. тем более что все равно у меня уже подключен шнурок по которому идет питание и USB Serial.

Давайте посмотрим как работает бутлоадер. Для начала на примере контроллеров AVR. Почему я о нем вспомнил? Я переходил с Arduino и подсознательно ожидал такого же поведения. Но в STM32 оказалось все по другому. Потому хочу рассказать о разнице этих двух микроконтроллеров.

Итак. В микроконтроллерах AVR ATMega под бутлоадер можно зарезервировать некоторое количество памяти ближе к концу флеша. С помощью fuse битов можно регулировать с какого адреса будет стартовать программа. Если бутлоадера нет — программа стартует с адреса 0x0000. Если бутлоадер есть — он запускается с некоторого другого адреса (скажем, в ATMega32 с 0x3C00, если размер бутлоадера выбран 2к).

image

Когда бутлоадер сделал свои дела он передает управление основной программе с адреса 0x0000. Т.е. программа всегда стартует с адреса 0x0000. Компилятор и линковщик работают с учетом того, что код будет находится в начале адресного пространства.

В микроконтроллерах STM32 все не так. Все программы стартуют с адреса 0x0800000. Бутлоадер не является чем-то таким особенным. Это такая же программа, которая стартует с того же самого начального адреса. В процессе работы бутлоадер может принять прошивку (через USB или UART, считать с флешки, принять со спутника, достать из подпространства, whatever...) и записать ее по адресам выше чем находится сам загрузчик. Ну и, конечно же, в конце своей работы передать управление основной программе.

image

Так вот при компиляции прошивки нужно знать куда же бутлоадер запишет прошивку и соответствующим образом скорректировать адреса.

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

Есть, правда, некоторые ограничения по схемотехнике. Тут я, к сожалению, не силен. ЯТП нужен подтягивающий резистор 1.5к для порта PA12 (он же USB D+). Это позволяет загрузчику в нужные моменты времени подключаться и отключаться от USB.

Инструкция:

  • Качаем github.com/rogerclarkmelbourne/STM32duino-bootloader [3]. В директории STM32F1binaries уже есть пакет скомпилированых бутлоадеров под разные платы. Индекс в конце названия файла указывает куда подключен светодиод. В случае моей платы [1] где светодиод подключен к пину C13, я использовал файл generic_boot20_pc13.bin.
  • Прошивем согласно инструкции [4]. Да, тут понадобится USB-UART переходник, но наверняка можно и с помощью отладчика
  • Теперь микроконтроллер готов ппрошиваться через USB загрузчик. Но ведь еще нужно саму прошивку подправить. А сделать нужно 2 вещи:
    • Указать линкеру стартовый адрес. В CooCox это делается в настройках проекта, вкладка Link, раздел Memory Areas, Адрес IROM1 Start Address. Бутлоадер занимает первые 8 килобайт, значит стартовый адрес прошивки будет 0x0800000 + 0x2000 = 0x08002000. Поле Size, наверное, тоже стоит уменьшить на 8к
    • Где нибудь вначале программы перед инициализацией периферии сделать вызов
      NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x2000);
  • Заливатор прошивки можно взять из проекта stm32duino [2]. В директории tools ищите скрипт под называнием maple_upload. Я пользовал только виндовую версию — maple_upload.bat
  • Запускать так:
    "maple_upload.bat" COM20 2 1EAF:0003 "PathToFirmware.bin"

    Вместо COM20 нужно подставить свой порт куда прицепился микроконтроллер.

    Заливатор штука очень нежная, относительных путей не любит. так что путь к прошивке нужно указывать полностью.

    1EAF:0003 — это VID и PID

    2 — это параметр AltID, который указывает что прошивку нужно заливать по адресу 0x08002000 (читать тут [5])

Еще чуток нюансов. Перед тем как заливать прошивку нужно запустить бутлоадер. Самый простой способ — нажать кнопку ресет. После этого запустится загрузчик и несколько секунд будет ждать прошивку. Если в этот момент никто не запустил maple_upload, загрузчик передаст управление основной прошивке.

Чтобы не нажимать каждый раз ресет, платы основанные на libmaple/stm32duino используют трюк. Они слушают usb serial порт. Если там возникает сигнал DTR и передается ключевая последовательность байт, то микроконтроллер перегружается в бутлоадер. Смотреть в функцию rxHook() [6]

Из-за этого может возникнуть неудобство. Если микроконтроллер заглючил и повис, то он уже не слушает порт. Следовательно он не может услышать ключевую последовательность и перегрузиться в бутлоадер. Тогда только ресет в помощь.

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

Автор: grafalex

Источник [7]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/arduino/252174

Ссылки в тексте:

[1] микроконтроллер STM32F103C8: https://ru.aliexpress.com/item/Arm-cortex-m3-stm32f103c8t6-stm32-core-board-development-board/1539984258.html

[2] фреймворк stm32duino: https://github.com/rogerclarkmelbourne/Arduino_STM32

[3] github.com/rogerclarkmelbourne/STM32duino-bootloader: https://github.com/rogerclarkmelbourne/STM32duino-bootloader

[4] согласно инструкции: https://geektimes.ru/post/277928/

[5] тут: http://www.rogerclark.net/improved-maple-bootloader-for-stm32/

[6] в функцию rxHook(): https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/cores/maple/usb_serial.cpp

[7] Источник: https://geektimes.ru/post/287866/