Хабрахабр

[Из песочницы] Программирование stm32f103 с самых основ

В статье я хотел бы описать шаги на пути к написанию прошивки для микроконтроллеров stm32 без использования специальных сред разработки типа keil, eclipse и тому подобных. Я опишу подготовку прошивки с самых основ, начиная с написания загрузчика на ассемблере, скрипта для линкера и заканчивая основной программы на C. В коде на C буду использовать заголовочные файлы из CMSIS. Редактор кода может быть любым на ваш вкус, vim, emacs, блокнот, все что угодно. Для сборки проекта буду использовать утилиту make. Итак, начнем!
Почему так сурово, спросите вы. Во-первых, чтобы что-то хорошо освоить, необходимо начинать с основ. Я не хочу, чтобы мой читатель бездумно щелкал клавишами клавиатуры набирая текст очередной супер-программы для устройства, не понимая, как работает устройство. Stm32 гораздо более сложный микроконтроллер по сравнению, например с atmega8 — atmega328 (микроконтроллером, установленным на самой популярной плате серии arduino). Во-вторых, я люблю сам разбираться в любом деле с нуля, и можно сказать, данная статья — это заметки для меня в будущем, чтобы открыть и вспомнить некоторые нюансы.

Подойдет любой дистрибутив, например, у меня это Arch Linux. Да, я забыл еще сказать, что разработку буду вести под Linux. Можете попробовать Windows, MacOS, но для этого вам самим придется разобраться, как установить необходимые утилиты для компиляции и прошивки. Для ubuntu процесс установки необходимых утилит я постараюсь описать в следующих частях.

У меня это blue pill: Первое, что вам нужно сделать, это приобрести плату для разработки на основе контроллера stm32f103.

image

Еще одна вещь, необходимая для старта, это программатор st-link:

image

за все вместе.
Второе, что необходимо сделать, это скачать набор для компиляции кода под arm GNU GCC. Плату blue pill и программатор я приобрел на aliexpress, заплатив 200 руб.

Для arch linux необходимо поставить пакет gcc-arm-none-eabi:

yaourt -Syy arm-none-eabi-gcc

Далее нам понадобится утилита st-link для работы с одноименным программатором st-link2:

yaourt -Syy stlink

Теперь давайте попробуем подключить нашу плату к компьютеру через программатор.

Соединяем программатор с платой blue pill в таком порядке:

  • Подключить к пину GND (ground — земля, пина два, возьмите любой, например, 4-й) на программаторе провод (желательно следовать некоторым стандартам, для земли используйте черный или синий) и подключите к пину на плате подписанному GND;
  • Подключить пин SWCLK (clock — синхронизация) на программаторе к пину SWCLK на плате;
  • Подключить пин SWDIO (IO — ввод/ввод) на прогамматоре к пину SWIO на плате;
  • И наконец, пин 3,3V на программаторе соедините с пином 3,3V на плате.

Пока все очень просто. Теперь подключаем программатор в USB порт компьютера, открываем терминал и проверяем, что устройство успешно определилось в системе:

dmesg

image

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

Для этого в терминале запускаем команду st-info из установленного до этого пакета stlink: Теперь давайте проверим характеристики нашей демо-платы.

image

На выбор можем посмотреть:

--version — текущая версии утилиты st-info
--flash — выведет информацию о размере flash-памяти программ микроконтроллера, в моем случае это 0x10000 (65536 байт)
--sram — объем статической памяти — 0x5000 (4096 байт)
--descr — описание — F1 Medium-density device
--pagesize — размер страницы памяти — 0x400 (256 байт)
--hla-serial — "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x31"
--probe — Found 1 stlink programmers
serial: 303030303030303030303031
openocd: "\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x31"
flash: 65536 (pagesize: 1024)
sram: 20480
chipid: 0x0410
descr: F1 Medium-density device

Из важного для нас — размер flash-памяти и размер статической памяти, а также стоит запомнить что у нас устройство Medium-density.

Во-первых следует скачать с официального сайта Reference Manual. Не следует начинать разработку без документации под рукой. Во-вторых, скачиваем Programmer Manual по той же ссылке. В нем полное описание всей периферии, регистров периферии микроконтроллера. В нем узнаете о микропроцессоре семейства контроллеров STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3, его архитектуре, наборе команд.

Далее разберем, с чего вообще начинается исполнение программы на микроконтроллере.

  1. Наш микроконтроллер stm32f103c8 сразу после включения начинает считывать по адресу 0x08000000 (для удобства чтения я буду делить тетрады пробелом — 0x0800 0000) значение для регистра SP. SP (Stack pointer) — регистр указателя стека (стр. 15 Programmer Manual). Стек начинается с конца доступной RAM-памяти и растет “вверх”;
  2. По адресу 0x0800 0004 считывает значение в регистр PC — Program counter. Это значение — адрес точки входа в нашу основную программу, другими словами по адресу 0x0800 0004 flash должен лежать адрес C — функции main(), определенной нами далее;
  3. Микроконтроллер начинает выполнение программы.

Чтобы вычислить начальное расположение стека (значение для SP регистра), обратимся к мануалу Reference Manual на стр. 65. Там указано, что RAM начинается с адреса 0x2000 0000. Ранее мы определили, что у микроконтроллера 4096 байт:

0x2000 0000 + 0x5000 = 0x2000 5000

Каждый указатель имеет размер 4 байта, значит следующий адрес за 0x0800 0004 во flash памяти будет 0x0800 0004 + 4 = 0x0800 0008. То есть по адресу 0x0800 0000 мы должны поместить значение 0x2000 5000.
По адресу 0x0800 0004 мы должны положить указатель на начало нашей программы. Это значение и необходимо поместить по адресу 0x0800 0004.

Так будет выглядеть начальный участок нашей прошивки:

+-------------+-------------+ | Адрес flash | Значение +-------------+-------------+
| 0x0800 0000 | 0x2000 5000 |
| 0x0800 0004 | 0x0800 0008 |
+-------------+-------------+

Теперь об одной особенности микроконтроллеров stm32. Дело в том, что формат команд для stm32 должен быть в Thumb представлении вместо стандартного ARM. Это значит, что при указании указателей мы должны прибавлять 1. Запомните это правило.

Надеюсь, вы еще не спите. Хватит теории, пора переходить к практике. Мы начнем с startup файла и он будет написан на ассемблере. Открывайте ваш любимый редактор кода, будем писать начальный файл для запуска нашего контроллера. Это будет единственный раз, когда я заставляю вас писать на скучном ассемблере, зато вы начнете понимать и “чувствовать” устройство изнутри.

Пишем в самом начале:

@stm32f103

Это комментарий на языке ассемблера, каждый комментарий начинается с символа @.
Далее указываем директивы ассемблеру

.syntax unified @тип команд для stm32 - Thumb! .thumb @семейство процессора микроконтроллера cortex-m3 @(в этом можно убедиться из мануала) .cpu cortex-m3

И далее коротенькая bootstrap-программа:

Пишем без пробелов!
@.equ директива ассемблера это почти
@тоже что и define в C или на худой конец
@думайте, что это обычное присваивание переменной
.equ StackPointer 0x20005000 @указатель на вершину стека.

@.word - указываем, что здесь машинное слово - 4 байта
@по сути отсюда (0x0800 0000) процессор
@начинает свою работу после включения
.word StackPointer

@”кладем” указатель на начало основной программы.
@Reset в данном случае - метка, адрес точки входа.
@не забываем о том, что у нас набор команд Thumb,
@поэтому к указателю прибавляем единицу
.word Reset + 1

Здесь мы встречаем первую, настоящую и
@единственную команду, которая нам понадобится на
@протяжении всего руководства. @метка Reset. Это команда B -
@безусловный переход в системе команд ARM,
@аналог JMP в ассемблере для x86, или простыми
@словами goto в языках более высокого уровня.
@Аргумент команды B - это адрес безусловного перехода, в нашем случае мы пока
@указываем метку Reset, тем самым заводим процессор в бесконечный цикл.
Reset: B Reset
Программу целиком вы можете скачать по ссылке https://bit.ly/2rc7bcf
Сохраните ее под названием bootstrap.s.

А теперь давайте скомпилируем и прошьем нашу плату.

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

Снова вставляем программатор с подключенной платой в usb и запускаем в терминале Linux команду:

st-flash read ./default.bin 0x08000000 0x10000

Здесь мы указываем, что хотим прочитать в файл default.bin flash-память начиная с адреса 0x08000000 и размером 0x10000 (64K), то есть всю flash-память.

st-flash — утилита для работы с прошивкой микроконтроллера, полное описание ее читайте в терминале: st-flash --help.

Загрузим ее вновь, перезаписывая старую. После этого проверим, что прошивка корректно считалась.

st-flash write ./default.bin 0x08000000

Что означает записать default.bin в flash память контроллера начиная с адреса 0x08000000.

Выньте и снова вставьте программатор, на плате зеленый диод должен как и раньше мигать.

В терминале в той же директории, что и сохранили запустите: Теперь давайте скомпилируем нашу самописную прошивку.

arm-none-eabi-as -o bootstrap.o bootstrap.s

Здесь мы компилируем наш исходный файл в объектный код. Это еще не готовая прошивка, годная для заливки в микроконтроллер. Нам необходимо еще “указать” куда, по каким адресам размещать нашу программу. Этим занимается компоновщик. Мы воспользуемся самым популярным компоновщиком LD, который входит в поставку пакета arm-none-eabi-gcc. Подробнее о компоновщике и описание скрипта для компоновщика ld я расскажу в следующей части, когда мы перейдем к автоматической сборке нашей супер-простой прошивки. А пока просто скачайте этот маленький файл stm32f103.ld https://bit.ly/2HXIydu, и выполните команду:

arm-none-eabi-ld -o main.elf -T stm32f103.ld bootstrap.o

Этой командой мы компонуем наш объектный файл с помощью скрипта stm32f103.ld, на выходе получаем elf файл.

Чтобы окончательно подготовить исполнимый elf файл к прошиванию, выполним последнюю команду:

arm-none-eabi-objcopy main.elf main.bin -O binary

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

Прошиваем! Итак, наша первая программа для контроллера stm32 готова!

st-flash write ./main.bin 0x08000000

Поздравляю! Теперь микроконтроллер обречен на вечное выполнение безусловного перехода. До следующей встречи!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть