Минимально необходимый код для Cortex-M4


С подачей питания или по сигналу сброса, процессорное ядро Cortex-M4 работает от встроенного RC генератора на частоте ~16 МГц и начинает выполнять программу с нулевого адреса встроенной флешки. Это абсолютно штатный режим ядра, можно ничего не трогать и сразу начинать работу. Потребуются только две строки в начале кода, которые по сути являются началом таблицы векторов:

    .word    0x2001BFFF    @ Вершина стека, зависит от размера ОЗУ
    .word    Start+1    @ Вектор сброса

    Start:      ....... отсюда начинается код


На этом статью можно было бы закончить. Всё настолько просто, что даже не верится! Буквально с третьей строки можно вставлять ассемблерный код и он будет выполняться. Код должен начинаться от метки Start. Можете придумать своё имя для этой метки, не важно. Стек настроен, калибровочный байт считан, и это всё делается ядром автоматически.

Помните, как это было в тинках и мегах? Нужно "вручную" установить вершину стека, прописать калибровочный байт, отрубить пса! А сколько народу на этом отрубилось! Ведь кто-же его поймёт, что по умолчанию пёс всегда включен и будет сбрасывать процессор до тех пор, пока не вырубишь? А калибровочный байт - его нужно предварительно считать из камня программатором и где-то сохранить во флешке. В каждом камне свой уникальный байт. Очень много возни.. По умолчанию 8-битный AVR не был готов к работе..

А вот с кортексами гораздо проще. Я только начал с ними работать. Но уже обратил внимание на более логичную, укладистую организацию периферии. Например, что бы целиком настроить порт, нужны всего 3 инструкции. Другая периферия настраивается так же просто, шаг за шагом, путём расталкивания бит и байтов в управляющие регистры.

На основании выше сказанного, мною был написан минимально необходимый код для платы STM32F4DISCOVERY, который позволяет убедиться, что плата живая и она работает. Аналогичный код принято считать "Hello world!" для микроконтроллера - подрыгать ножками, поморгать светодиодом.

Наверное в это трудно будет поверить, но размер кода составил 19 ассемблерных инструкций. А размер прошивки составил умопомрачительные 84 байта. Если вам лень разбираться в кодах, скачайте прошивку и залейте её в камень через утилиту ST-LINK. Хочу ещё раз обратить ваше внимание, что код написан для отладочной платы STM32F4DISCOVERY.

Скачать прошивку

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

На что стоит обратить внимание. В начале располагаются несколько полезных макросов. Затем идёт таблица векторов прерываний, которой по сути нет, потому что прерывания мы не используем и все они по умолчанию в камне отключены.
И ещё, макросы и метки теперь могут быть русскими! Так что ассемблер в составе GCC обладает хорошим потенциалом. Я только начал с ним работать, понравился! А через макросы можно исправить ассемблерный синтаксис на более привычный.

    @ Синтаксис GCC AS
    .syntax unified
    .section .text

.macro    MOV32 regnum,number
    MOVW \regnum,:lower16:\number
    MOVT \regnum,:upper16:\number
.endm
.macro    MOVLo regnum,number
    MOVW \regnum,\number
.endm
.macro    MOVUp regnum,number
    MOVT \regnum,\number
.endm
.macro    CALL address
    BL \address
.endm
.macro    RET
    BX LR
.endm
.macro    JMP address
    B \address
.endm

.equ RCC_AHB1ENR, 0x40023830
.equ GPIOD_MODER, 0x40020C00
.equ GPIOD_ODR, 0x40020C14
.equ GPIODEN_BB, (RCC_AHB1ENR & 0x00FFFFFF) * 0x20 + 0x42000000 + 3 * 4


    @ Это таблица векторов прерываний
    @ Если прерывания не используются,
    @ таблицу можно сократить до двух строк
    .word    0x2001BFFF    @ Вершина стека, зависит от размера ОЗУ
    .word    Start+1    @ Вектор сброса, обязательно +1

Start:

    @ Разрешить тактирование PORTD от шины
    @ Для настройки используем метод BitBand
    MOV32 R0, GPIODEN_BB
    MOV R1, 1
    STR R1, [R0]

    @ Ножки 12, 13, 14, 15 на выход
    MOV32 R0, GPIOD_MODER
    MOV32 R1, 0x55000000
    STR R1, [R0]

    @ По умолчанию светодиоды отключены
    MOV R1, 0            @ Обнулить регистр
    MOV32 R2, GPIOD_ODR    @ Выходной порт светодиодов

Моргалка:

    MOVLo R1, 0xA000        @ Переключить светодиоды
    STR R1, [R2]

    CALL Пауза

    MOVLo R1, 0x5000        @ Переключить светодиоды
    STR R1, [R2]

    CALL Пауза

    JMP Моргалка


Пауза:
    @ Почти 1 секунда на частоте 16 мгц
    MOVUp R0, 0x004C
    Пауза1:
    SUBS R0, R0, 1
    BNE Пауза1
    RET

.end



Очень сложно, правда?