Это моя первая статья для сообщества Хабрахабр и написать ее я решил про то что сейчас волнует меня самого: написание программ для микроконтроллеров STM32 (семейство АRМ) на языке ассемблера. Я использую отладочную плату на основе микроконтроллера STM32F407 (STM32F4 Discovery, Open407I-C), но статья будет не менее полезна и для программирования других микроконтроллеров STM32.
После поисков по интернету так и не удалось найти сколь нить понятного для новичка способа написания прошивок для STM32- и ARM- контроллеров вообще на языке ассемблера. Нет, конечно любой поисковик по сочетанию «STM32 ассемблер» дает очень много результатов, но после внимательного их изучения выясняется что 98% результатов поиска ведут на описание сред в которых по заверению производителей языком программирования микроконтроллеров является С, С++, Assembler.
Более того, как только Вы начинаете искать информацию о том как же все таки программировать на ассемблере в конкретной среде для конкретного микроконтроллера — выясняется, что «гуру не пишут проекты на ассемблере», и в средах ассемблер используется максимум для написания процедур и функций требующих максимального быстродействия, или генерации кода содержащего специфические команды микроконтроллера аналог которых не предлагается языком Си (С++ или библиотеками) in-line вставками.
Дальше было еще интереснее, я выяснил что компиляторов ассемблера на ARM платформу существует как минимум два: GNU AS, и ARMASM. И у них различные форматы исходных файлов… Нет, конечно команды ассемблера одинаковые (слава богу), но вот как они пишутся, как указываются операнды, особенно служебные токены — отличаются так, что компиляция без «танцев» исходных файлов GNU AS на ARMASM (и наоборот) становится невозможна. Причем если GNU AS используется в бесплатно распространяемых средах (например CooCox), то ARMASM идет в составе далеко не самой дешевой среды Keil MDK. Насколько мне удалось выяснить для кода размером не более 32 кб среда является бесплатной, но не думаю что 32 кб для 32-разрядного микроконтроллера является каким то выдающимся размером для прошивки: немного кода работающего с дисплеем, немного шрифтов под дисплей, образов иконок — и 32 кб может и не хватить. Сообщество любителей нашло выход — это использование отдельных образов кода по 32 кб и потом объединение их различными способами — но как то хочется нормальной разработки, а не попыток «впихнуть и распределить невпихуемое» (использование пиратских программ мне не интересно). Есть ли ограничение на размер кода у самого компилятора ARMASM или это ограничение Keil MDK — я не стал выяснять, не очень приятно проделать работу основываясь на данных что все бесплатно, и в середине какого нить уже не тестового проекта получить ошибку компиляции из-за ограничений по размеру…
Таким образом, несмотря на то что в сети проектов написанных под ARMASM больше (по крайней мере так мне показалось исходя из результатов поиска), я решил разобраться с GNU AS — который бесплатен для любых размеров прошивок.
В результате поисков ресурсов (другие 2% результатов по запросу «STM32 ассемблер») на тему ассемблера для STM32 я наткнулся на отсутствие какого то начального состояния у многочисленных авторов. У кого то хорошо описаны инструкции ARM, у кого то сделаны попытки раскрыть параметры ассемблера и линковщика, где то описана минимальная (по мнению автора статьи) конфигурация от которой можно оттолкнуться — но вся эта информация так раскидана — что для начального вхождения практически не пригодна, тем более когда в проекте появляется что-то новое и вы просто не понимаете какие исправления нужно внести чтобы все «заработало»… Особенно тяжело если вы раньше не задумывались о том что делает IDE при компиляции ваших проектов. Теоретически конечно все представляют, что есть ассемблер, линковщик и другие вспомогательные утилиты, но вот какие файлы настроек, ключи для запуска, файлы для работы нужны — все это как то на уровне «ликбеза».
Поэтому,
цель первого этапа — создать с нуля минимальную конфигурацию программных и настроечных файлов для возможности написания программ на языке ассемблера.
Я постараюсь описать все более менее последовательно, чтобы Вы могли не только просто повторить то, что я сделал, но и сделать собственные настройки для своего микроконтроллера, а так же менять эти настройки когда это будет необходимо (это пожалуй самое главное!). Вообще не думаю что все что я написал нужно повторять — просто внимательно прочитайте! Это тот путь который вы должны были бы пройти если бы начинали разбираться во всем сами. Я не буду описывать каким образом я дошел до того или иного шага, это сборная «солянка» от поиска в интернете, просмотра примеров других авторов, разбирательства в файлах которые генерирует CoIDE (CooCox), это не интересно и не нужно, но то что узнал в ключевых моментах, и что реально будет нужно для написания своих проектов я постараюсь отметить.
Для начала необходимо скачать пакет разработчика
GNU GCC (из него можно взять программы компилятора ассемблера), это можно сделать например
отсюда (справа выбираем пакет в зависимости от операционной системы).
Этот пакет можно распаковать на диск (я распаковал в каталог
gcc каталога
CooCox, у меня этот пакет используется и для программирования в среде CooCox).
Нужные нам файлы я выделил:
Теперь небольшое отступление для тех кто не задумывался о том как происходит преобразование написанной программы в исполняемый код.
Программа написанная в текстовом редакторе (это может быть как блокнот, так и среды разработки по типу CooCox, Keil) сначала компилируется ассемблером.
Все более менее серьезные программы состоят из различных частей которые размещаются в разных исходных файлах программы, эти части могут иметь различное назначение (код, константы, данные), располагаться в различных областях памяти (FLASH, SRAM, Backup SRAM и т. д.) — поэтому мало просто откомпилировать программу, нужно еще правильно расположить ее части в памяти микроконтроллера. Этим важным делом занимается линковщик — в зависимости от схемы линковки он располагает части программы по так называемым сегментам которые и представляют собой различные области памяти микроконтроллера.
Нам осталась самая малость: разобраться как скомпилировать и как распределить части нашей прошивки.
Здесь очень желательно чтобы вы представляли с чего начинается исполнение программы у микроконтроллера
STM32F4, если это не откровение для вас можете пропустить пару абзацев:
При включении микроконтроллер:
- По адресу 0х0800 0000(*) загружает значение регистра указателя стека SP. Обычно стек начинается с конца доступной RAM и при заполнении движется от старших адресов к младшим
- По адресу 0x0800 0004 загружает значение регистра PC (Program counter) — то есть фактически осуществляет переход по адресу указанному по адресу 0x0800 0004
- Осуществляется исполнение программы по адресу загруженному в PC
(*) Адреса разделены пробелом для удобства чтения, в программах правильно писать конечно же 0x08000000
Исходя из выявленных шагов находим в документации на контроллер в каких адресах располагается
SRAM у
STM32F4 (или у Вашего микроконтроллера, так как различные микроконтроллеры имеют различный объем памяти). Для моего микроконтроллера открываем «
RM0090 Reference manual» (для других микроконтроллеров ST посмотрите
здесь).
Смотрим оглавление на предмет «чего нить про память»:
Идем на страницу 59
Внимательно читаем! У нашего микроконтроллера есть два банка памяти
SRAM1 и
SRAM2 размерами 112 кб и 16 кб. Другая интересующая нас информация находится на странице 68.
У микроконтроллера проекта
STM32F407 фактически 3 блока памяти расположенных в разных областях адресного пространства:
- объединенный блок SRAM1 и SRAM2 начинающийся с адреса 0x2000 0000 и имеющий размер 112 кб + 16 кб (всего 128 кб)
- отдельный блок CCM — начинающийся с адреса 0x1000 0000. Согласно написанному «на борту» у контроллера 192 кб — следовательно блок CCM у нас на 64 кб.
- Отдельный блок backup SRAM размером в 4 кб
Не стоит обвинять разработчиков микроконтроллера в раскидывании памятью по адресному пространству — эти 3 разных блока памяти исполняют различные функции:
- SRAM1 и SRAM2 — хранение переменных и данных
- CCM — хранение переменных и данных, а так же программ исполняющихся из оперативной памяти (!)
- backup SRAM – хранение переменных и данных с питанием от внешней батареи энергонезависимого питания. В микроконтроллере STM32F4 нет энергонезависимой памяти для хранения констант, и предложен способ хранения переменных в ОЗУ с питанием контроллера от миниатюрной батарейки (типа часовой) с минимальным потреблением
Возьмем банки памяти
SRAM1 и
SRAM2 и в их конце разместим стек. Вычислим адрес последней ячейки стека:
0x2000 0000 + 128kб = 0x2000 0000 + 0x0002 0000 = 0x2002 0000
Таким образом указатель стека нужно будет установить на значение
0x20020000. Получаем следующую «карту» памяти:
Адрес |
Значение |
0x08000000 |
0x20020000 |
Со вторым пунктом проще — мы укажем адрес следующий после нашей таблицы переходов. Поскольку один указатель у нас занимает 4 байта, таких указателей у нас 2 — получается что программу мы можем начинать писать с адреса
0x08000008.
Получаем следующую табличку:
Адрес |
Значение |
Примечание |
0x08000000 |
0x20020000 |
Значение для загрузки в SP (указатель стека) |
0x08000004 |
0x08000008 |
Значение для перехода по сбросу (включению) |
Значения указателей 4-х байтные, формат этот называется word (это вам должно быть известно из курса программирования на любом языке)
Теперь немного «шаманства». Дело в том что платформа
ARM имеет очень большое количество микропроцессоров, с различными форматами команд. Для того чтобы определить какой формат команды используется используются 2 младших бита адреса команды. Так вот младший бит установленный в «1» показывает, что команда подлежащая исполнению указана в формате
Thumb. В случае, если оба младших бита сброшены — микропроцессор считает что нужно исполнить команду в формате
ARM. Для микроконтроллеров
STM32 при осуществлении переходов допустим только набор команд
Thumb! В случае если мы попробуем «заставить» микроконтроллер перейти на команду в формате
ARM — произойдет ошибка!
Если посмотреть двухзначное представление полученного нами адреса то мы увидим что в нашем адресе «закодирована» система команд
ARM.
Младший байт адреса (0x08) в двоичном виде:
Бит |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Значение |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
Полубайт |
0 |
8 |
А должно быть:
Бит |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Значение |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
1 |
Флаг типа команды |
часть адреса |
Флаг |
Полубайт |
0 |
9 |
Фактически добавление младшего бита установленного в «1» — это просто увеличение адреса на 1.
Запоминаем правило: при указании указателей в таблице векторов прерываний необходимо увеличивать значение адреса на 1
В качестве программы будем использовать примитивный бесконечный цикл. Чтобы не отправлять Вас в «копание» в документации — это команда «
B».
Если вы задумались об ассемблере, или писали на ассемблере для AVR (или i8080, или Z80), то наверное команда «
JMP» восьмибитников вам знакома, так вот «
B» ее аналог.
Получается что наша программа должна выглядеть следующим образом:
.word 0x20020000 @ Указатель вершину стека
.word Reset + 1 @ Указатель на программу
Reset: B Reset
Займемся средой компиляции. Компилятор ассемблера имеет название
arm-none-eabi-as.exe. Вызывая компилятор мы должны указать ему файл нашей программы, и файл в который он должен сохранить результат компиляции. Если запустить компилятор с ключем
—help, можно найти какие для этого нужны ключи, берем минимально необходимый ключ
-о:
arm-none-eabi-as.exe -o <файл результат> <файл исходник>
Нашу программу мы разместим в файле
main.asm. Файл-результат работы компилятора называется «объектный файл», общепринятое расширение таких файлов «.о» — пусть будет называться
main.o. Таким образом компилятор мы вызовем строкой:
arm-none-eabi-as.exe -o main.o main.asm
Но это еще не все (к сожалению) — дело в том что этот компилятор может быть использован для различных семейств и типов микроконтроллеров и процессоров и мы до сих пор не указали ему какой же микроконтроллер собираемся использовать. Исходя из того что нам сообщает сам компилятор его устроит указание семейства
cortex-m4.
Указать можно двумя путями:
- Указать при компиляции при помощи ключа «-mcpu=cortex-m4»
- Указать в тексте программы строкой «.cpu cortex-m4»
Дополнительно нужно указать систему команд которую мы будем использовать: «
.thumb». Ну и еще дополнительно указывается параметр «
.syntax unified» — этот параметр задает некоторые особенности при написании программы, например, разрешает перед числами не ставить префикс «#», иногда не писать вручную некоторые инструкции ассемблера (IT) — компилятор это будет делать за нас (в случае необходимости) и так далее (в этом будем разбираться позже). Почитать дополнительно об этом
можно здесь.
Получаем следующую программу:
@GNU AS – просто комментарий в котором указываем компилятор (для себя)
@ Настройки для компилятора:
.syntax unified
.thumb @ тип используемых инструкций Thumb
.cpu cortex-m4 @ семейство микроконтроллера
@ Наша программа:
@ Таблица указателей перехода которая должная быть размещена с адреса 0x08000000
.word 0x20020000 @ Стек
.word Reset+1 @ Адрес перехода при сбросе.
@ Внимание! Для корректности работы необходимо к адресу
@ прибавить "1" - это показывает процессору что команда
@ по адресу перехода будет в формате Thumb (а не ARM),
@ если этого не сделать, то микроконтроллер
@ будет уходить в ошибку (в прерывание Hard Fault)
@ Наша программа (должна быть размещена после таблицы указателей переходов)
Reset: B Reset
Теперь, запустив компилятор командой:
bin/arm-none-eabi-as.exe -o main.o main.asm
мы увидим что в папке появился файл main.o — таким образом компиляция прошла успешно, объектный файл создан.
Небольшое отступление:
Для удобства я поместил все программы пакета разработчика в отдельный каталог bin в папке проекта (объем всего около 5 мб), а сам запуск компилятора делаю из .bat файла make_project.bat, поскольку компилятор оставляет сообщения об ошибках в консоле — удобнее всего запускать bat файл из FAR.

Для полноты привожу содержимое файла
make_project.bat на данном этапе:
CLS
:: Компиляция
bin\arm-none-eabi-as.exe -o main.o main.asm
Теперь из файла
main.o при помощи программы-линковщика нужно сделать файл прошивки. Для программы-линковщика необходим файл настройки в котором собственно говоря и будет описано какую часть нашей программы куда нужно поместить.
Здесь могу рекомендовать почитать статью на этом же ресурсе
habrahabr.ru/post/191058 — там можно найти один из примеров карты линковщика, есть и другие ресурсы где можно посмотреть какими бывают файлы линковщика, но к сожалению простых решений нигде не предлагается.
Один из самых простых файлов линковщика приведенный по ссылке выше выглядит так:
MEMORY {
rom(RX) : ORIGIN = 0x00000000, LENGTH = 0x8000
ram(WAIL) : ORIGIN = 0x10000000, LENGTH = 0x2000
} ENTRY(public_function)
SECTIONS {
.text : { *(.text) } > rom
_data_start = .;
.data : { *(.data) } > ram AT> rom
_bss_start = .;
.bss : { *(.bss) } > ram
_bss_end = .;
}
Для того чтобы понимать что, как и зачем, давайте попробуем составить свою карту линковщика с нуля, используя данную как подсказку (вместе со статьей автора ее написавшего, ну и подглядывайте в интернет — там море информации на эту тему).
ИТАК, первое и самое заметное: карта линковщика состоит как бы из двух больших секций
MEMORY и
SECTIONS
В первом блоке (
MEMORY) указывается какая память установлена в микроконтроллере, в каких адресах, и какого размера. Адреса и размеры
SRAM мы уже выясняли, а вот для
FLASH памяти эту информацию нужно поискать в том же «
RM0090 Reference manual» или просто вспомнить сколько flash памяти у вашего микроконтроллера (например по полному наименованию микроконтроллера).
После указания имени типа памяти (произвольно, кто то пишет
ROM /
RAM, кто то
MEMORY, я пишу
FLASH /
SRAM) указываются режимы доступа к памяти: для
FLASH памяти
R — чтение,
X-исполнение. И далее начальный адрес памяти в адресном пространстве и размер.
Должно получиться примерно так:
MEMORY {
FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 1024kb
}
Далее идет определение областей или секций. Как вы могли уже прочитать по ссылке выше — основные секции прошивки имеют имена:
- .text – исполняемый код (размещается во FLASH)
- .data – переменные (размещаются в SRAM)
- .rodata – константы (размещаются во FLASH)
- .bss – переменные с нулевым значением при старте (SRAM)
Имена этих секций в прошивке «забиты» в самих утилитах компиляции, поэтому произвольно их менять не получится. Количество секций в исходных файлах задается вами самостоятельно, и для языков высокого уровня сильно зависит от компилятора языка программы, для Си компиляторов количество секций нередко доходит до 10… Секции исходных файлов всегда приводятся к секциям прошивки.
Конструкция блока
SECTIONS в общем виде строиться следующим образом:
.text : { /* <--- Тип секции: исполняемый код, в прошивке */
*(.text); /*<-- Тип секции в main.asm */
*(.code); /*<-- Тип секции в main.asm */
*(.flashdata); /*<-- Тип секции в main.asm */
*(.datar); /*<-- Тип секции в main.asm */
} > FLASH /* Размещать в памяти FLASH */
Еще раз резюмирую: у нас есть два разных набора секций: один набор секций — это секции описанные в исходных файлах нашей программы, другой набор секций — это секции которые будут записаны в прошивке. Соответственно сначала объявляем секцию прошивки, и внутри указываем какие секции описанные в исходных файлов в нее входят. Секции прошивки называются так как называются, секции в исходных файлах — называем мы сами (в определенных пределах к сожалению, но об этом позже).
Пока вам (и мне) повезло, у нас только одна секция прошивки и одна секция исходного файла — исполняемый код.
Получаем следующее:
/* STM32F40x, flash 1 mb, sram 192 kb, bkpsram 4 kb */
MEMORY
{
/* FLASH - Программная flash память */
FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 1024K
}
SECTIONS
{
.text : { /* Секция прошивки */
*(.text); /* Секция исходников */
} > FLASH
}
Примечания пишутся внутри скобок /* */, все примечания пишутся «для себя» и «чтобы не забыть». Этот текст карты линковщика я поместил в файл
stm32f40_map.ld.
Я намеренно упростил нашу карту линковщика по максимуму чтобы вы могли понять идею ее написания. Несмотря на упрощение (которое наверняка мне не простят «гуру» программирования и напишут в комментариях, что так писать нельзя) эта карта линковщика для нашего примера полностью работоспособна (а иначе не стоило и мучаться с ее написанием)!
Теперь, коль у нас появились секции — совершенно очевидным становиться необходимость указания в прошивке что и к какой секции относиться! Делается это при помощи команды
.section, секция у нас одна
.text, правим наш
main.asm.
Секция «вроде бы» должна заканчиваться командой «.end», я еще не выяснил до конца нужна это команда на самом деле или нет и поэтому добавил в конце.
Файл исходного текста нашей программы теперь выглядит вот так:
@GNU AS
@ Настройки компилятора arm-none-eabi-as.exe
.syntax unified
.thumb @ тип используемых инструкций Thumb
.cpu cortex-m4 @ процессор
@ Наша программа
.section .text
.word 0x20020000 @ Стек
.word Reset+1 @ Адрес перехода при сбросе.
@ Внимание! Для корректности работы необходимо к адресу
@ прибавить "1" - это показывает процессору что команда
@ по адресу перехода будет в формате Thumb (а не ARM),
@ если этого не сделать то младшие линейки (F0, F1)
@ будут уходить в ошибку (в прерывание Hard Fault)
@ Наша программа (должна быть размещена после таблицы указателей переходов)
Reset: B Reset
.end
Еще одно отступление: для нашего примера можно не указывать секции вовсе! Дело в том, что если секции не указаны, то при компиляции и последующей линковке будет выбрана «самая подходящая»… Конечно не стоит надеяться на компилятор и лучше самостоятельно указывать что и где должно быть размещено.
Линковщик это утилита
arm-none-eabi-ld.exe, при попытке запросить помощь запуская линковщик с ключем
-–help выходит не маленькая «портянка», но мы не будем строить монстроидальный запуск, нам нужно только сделать линковку полученной после ассемблера прошивки.
Используем ключ
-T для указания файла карты памяти, и ключ
-o для задания имени файла-прошивки, это будет файл с расширением
.elf.
Чтобы руками не набирать правим наш
make_project.bat:
CLS
:: Компиляция
bin\arm-none-eabi-as.exe -o main.o main.asm
:: Линковка
bin\arm-none-eabi-ld.exe -T stm32f40_map.ld -o main.elf main.o
После запуска у нас появляется файл с расширением
.elf.
Теперь нужно сделать остановку и поразмыслить — а что же мы получили? Ну да, ассемблер «что то» скомпилировал (файл
main.o), а линковщик на основании этого сделал «какую-то» прошивку (файл
main.elf), но как нам проверить, что у нас получилось?
По логике действий мы должны залить прошивку в микроконтроллер и посмотреть на результат… И тут мы вспоминаем что прошивка то у нас ничего не делает — поэтому никакого мигающего светодиода не будет! Вообще ничего не будет! Внешне, по пинам микроконтроллера мы не узнаем работает он, или прошивка оказалась ошибочной — и он завис.
По нашей программе проверку работы микроконтроллера пока сделать нельзя. А что можно? — с файлом прошивки
.elf — мы даже не можем посмотреть что и куда линковщик расположил (посмотреть хотелось бы не утилитами, а чем нить вроде того же
FAR, чтобы уж «точно и железно», перед тем как мы пойдем дальше нужно быть уверенными что на текущий момент все сделано верно).
Значит нужно сделать из прошивки
.elf прошивку в формате
.bin. Бинарный формат прошивки это фактически байты которые будут загружены в контроллер.
Сделать это можно при помощи утилиты
arm-none-eabi-objcopy.exe. Ключем
-O мы задаем формат который мы хотим получить, допустимы 2 значения:
binary и
ihex. Правим наш
make_project.bat:
CLS
:: Компиляция
bin\arm-none-eabi-as.exe -o main.o main.asm
:: Выполняем линковку
bin\arm-none-eabi-ld.exe -T stm32f40_def.ld -o main.elf main.o
::Выделяем из .elf файла - файл прошивки .bin
bin\arm-none-eabi-objcopy.exe -O binary main.elf output.bin
Запускаем и получаем «вожделенный» файлик
output.bin. Размер файла
output.bin 10 байт, в
FAR можно запустить его просмотр (F3) и в этом режиме переключиться в просмотр кода (F4):
Вот теперь нам есть что анализировать:
- В .bin прошивке не указываются адреса по которым происходит «заливка» прошивки в микроконтроллер — этот параметр указывается при программировании (в нашем микроконтроллере STM32F407 начальный адрес должен быть 0x08000000)
- Мы планировали что прошивка начнется с таблицы указателей переходов, первый указатель — SP, на конец SRAM1 и SRAM2 – 0x20020000. В прошивке идут байты 00 00 02 20 — вспоминаем (или узнаем сейчас) что все данные идут в порядке «младший — старший») и переворачиваем наши байты прошивки переписывая их побайтно справа-на-лево: 20 02 00 00 — вектор SP указан верно !
- После указателя SP должен идти вектор сброса: смотрим: 09 00 00 08, переворачиваем и получаем адрес для перехода: 08 00 00 09 — тоже правильно!
- Далее идет код команды на языке ассемблера.
Я бы рад вам подсказать способ дизассемблирования команды по ее коду — но к сожалению пока такого ресурса не знаю… Поэтому доверяю тому что получилось и считаю что сочетание E7 FE (я уже перевернул байты!) — это и есть наша строчка кода: «Reset: B Reset»
Нашел все таки документ в котором описано как кодируются команды ARM. Скачать можно по ссылке ARMv7-M Architecture Reference Manual.
Смотрим оглавление:

У нас код команды E7 FE — 16-ти битный, значит сразу идем на страницу 127, где будут определены старшие биты команд:
<img src="
Код нашей команды: 1110 0111 1111 1110, в указанном выше списке это последняя строчка «11100x Unconditional Branch, see B on page A7-207», значит идем на страницу 207.

Следовательно закодирована команда B относительным адресом 111 1111 1110. Как рассчитать адрес перехода можно понять из этого документа
у нас получается:
0x0800 0008 — 0x0800 000C= 0xFFFF FFFC (1111 1111 1111 1111 1111 1111 1111 1100) или -4
Кодируем -4 при помощи 12 бит: 1111 1111 1100. Теперь берем старшие 11 бит — и это будет поле смещения адреса:
1111 1111 1100 => 111 1111 1110
Наша команда полностью:
(код команды)=11100 (адрес)=111 1111 1110 => разобьем «по правильному»: 1110 0111 1111 1110 = E7 FE
На этом текущее повествование прекратим и
подведем итоги:
- Мы нашли файлы необходимые для компиляции проектов на языке ассемблера для микроконтроллера STM32F407
- Выбрали необходимые ключи компиляции и настройки компилятора
- Начали разбираться с картой памяти линковщика, и выяснили какие ключи необходимо использовать для линковки
- Получили файл прошивки, преобразовали этот файл в более понятный нам binary
- Мы проверили правильность формирования таблицы переходов, кода программы, размещения программы в прошивке на файле формата binary
В следующей статье будем писать прошивку микроконтроллера чтобы реально проверить его работу — будем мигать светодиодом!
комментарии (40)