STM32F2: Makefile, скрипт компоновщика и стартовый файл без коммерческой IDE

16

Я работал с STM32F2 (в частности, STM32F217IGH6 на плате разработки) около двух месяцев. Безусловно, моя самая большая проблема была связана с «установкой», которая включает make-файл, скрипт компоновщика и файл запуска.

В частности, я не смог правильно настроить таблицу векторов прерываний и вызвал обработчики прерываний. ST предоставляет примеры, адаптированные для коммерческих IDE. Вместо этого я использую бесплатную Yagarto перекомпиляцию цепочки инструментов GCC (и OpenOCD для загрузки изображения через JTAG).

Существуют ли примеры проектов для моей доски (или ближайших родственников), которые содержат соответствующий make-файл, сценарий компоновщика и комбинацию файлов запуска для некоммерческих сред IDE, которые настроены для вызова обработчиков прерываний?

Randomblue
источник
2
Вы должны искать примеры Cortex M3, точная плата и процессор не так важны для того, что вы просите. Вероятно, вам нужно изменить расположение памяти в скрипте компоновщика и метод перепрошивки в make-файле, но это все.
Starblue
1
Вы можете поместить все это в репозиторий git и поместить его на github или что-то?
AngryEE
1
Именно поэтому я перестал использовать STM, как только попробовал. Если они сделают мою жизнь трудной из-за скверной цепочки инструментов, то я пойду куда-нибудь еще. Когда я попробовал IDE для PSoC3 и PSoC5, это была огромная разница.
Ракетный магнит
Вы преданы Ягарто? Это совершенно нормально и делает отличный вопрос, но я знаком с инструментарием CodeSourcery Lite . Ответ на другой набор инструментов, вероятно, можно адаптировать, но он не будет работать «из коробки».
Кевин Вермеер

Ответы:

20

http://github.com/dwelch67

stm32f4 и stm32vld в частности, но другие могут быть полезны для вас. mbed и каталог mzero в mbed (cortex-m0).

Мне нравится простой и глупый подход, минимальные сценарии компоновщика, минимальный загрузочный код и т. Д. Работа выполняется кодом, а не каким-либо конкретным набором инструментов.

Большинство форм gcc и binutils (способных работать с большим пальцем) будут работать с этими примерами, так как я использую компилятор не как ресурс для библиотечных вызовов, я не использую скрипты стандартного компоновщика и т. Д. Старые gcc и binutils не будут знать о новые части thumb2, поэтому могут потребоваться некоторые изменения.

Я создаю свои собственные gcc, binutils и llvm / clang, а также использую, например, источник кодов (сейчас наставник графики, но вы все еще можете получить бесплатную / облегченную версию).

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

Посмотрите на stm32f4d / blinker02 например. Он начинается с vectors.s таблица исключений / векторов плюс некоторые подпрограммы поддержки asm:

/* vectors.s */
.cpu cortex-m3
.thumb

.word   0x20002000  /* stack top address */
.word   _start      /* 1 Reset */
.word   hang        /* 2 NMI */
.word   hang        /* 3 HardFault */
.word   hang        /* 4 MemManage */
.word   hang        /* 5 BusFault */
.word   hang        /* 6 UsageFault */
.word   hang        /* 7 RESERVED */
.word   hang        /* 8 RESERVED */
.word   hang        /* 9 RESERVED*/
.word   hang        /* 10 RESERVED */
.word   hang        /* 11 SVCall */
.word   hang        /* 12 Debug Monitor */
.word   hang        /* 13 RESERVED */
.word   hang        /* 14 PendSV */
.word   hang        /* 15 SysTick */
.word   hang        /* 16 External Interrupt(0) */
.word   hang        /* 17 External Interrupt(1) */
.word   hang        /* 18 External Interrupt(2) */
.word   hang        /* 19 ...   */

.thumb_func
.global _start
_start:
    /*ldr r0,stacktop */
    /*mov sp,r0*/
    bl notmain
    b hang

.thumb_func
hang:   b .

/*.align
stacktop: .word 0x20001000*/

;@-----------------------
.thumb_func
.globl PUT16
PUT16:
    strh r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET16
GET16:
    ldrh r0,[r0]
    bx lr

.end

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

blinker02.c содержит основную часть кода C с точкой входа C, которую я вызываю notmain (), чтобы не называть ее главной (некоторые компиляторы добавляют ненужные файлы в ваш двоичный файл, когда у вас есть main ()).

избавит вас от кроя и пасты. make-файл рассказывает историю компиляции и компоновки. Обратите внимание, что ряд моих примеров компилирует два или более двоичных файла из одного и того же кода. компилятор gcc, clang-компилятор llvm, только thumb и thumb2, различные оптимизации и т. д.

Начните с создания объектных файлов из исходных файлов.

vectors.o : vectors.s
    $(ARMGNU)-as vectors.s -o vectors.o

blinker02.gcc.thumb.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker02.c -o blinker02.gcc.thumb.o

blinker02.gcc.thumb2.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker02.c -o blinker02.gcc.thumb2.o

blinker02.gcc.thumb.bin : memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb.elf -T memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb.elf > blinker02.gcc.thumb.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb.elf blinker02.gcc.thumb.bin -O binary

blinker02.gcc.thumb2.bin : memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb2.elf -T memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb2.elf > blinker02.gcc.thumb2.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb2.elf blinker02.gcc.thumb2.bin -O binary

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

Я обычно не использую .data (ну, почти никогда), и в этом примере нет необходимости в .bss, так что вот сценарий компоновщика, которого достаточно, чтобы разместить программу (.text) там, где она должна быть для этого процессора. используй это.

MEMORY
{
    ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

У меня есть область памяти, чтобы определить, что нет ничего особенного в имени памяти, которую вы можете назвать foo, bar или bob или ted, не имеет значения, просто связывает элементы памяти с разделами. Разделы определяют такие вещи, как .text, .data, .bss, .rodata и где они находятся на карте памяти.

когда вы создаете это, вы видите, я разбираю все (objdump -D), вы видите это

Disassembly of section .text:

08000000 <_start-0x50>:
 8000000:       20002000        andcs   r2, r0, r0
 8000004:       08000051        stmdaeq r0, {r0, r4, r6}
 8000008:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 800000c:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 8000010:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}

Ключевым моментом, который стоит отметить, является адрес слева, где мы его и хотели, код vectors.s сначала находится в двоичном файле (поскольку он находится первым в командной строке ld, если вы не сделаете что-то в сценарии компоновщика, элементы будут отображаться в двоичном виде в том порядке, в котором они находятся в командной строке ld). Для правильной загрузки вы должны убедиться, что ваша таблица векторов находится в нужном месте. Первый элемент - мой адрес стека, это нормально. Второй элемент - это адрес _start, и он должен быть нечетным числом. использование .thumb_func перед меткой приводит к тому, что это происходит, поэтому вам не нужно делать другие уродливые вещи.

08000050 <_start>:
 8000050:       f000 f822       bl      8000098 <notmain>
 8000054:       e7ff            b.n     8000056 <hang>

08000056 <hang>:
 8000056:       e7fe          

поэтому 0x08000051 и 0x08000057 являются правильными векторными записями для _start и hang. начать звонки notmain ()

08000098 <notmain>:
 8000098:       b510            push    {

Это выглядит хорошо (они не показывают нечетные адреса в разборке).

Все хорошо.

Перейдите к примеру blinker05, этот поддерживает прерывания. и нуждается в некотором оперативной памяти, поэтому .bss определен.

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x100000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .bss  : { *(.bss*) } > ram
}

помните, что ram и rom - произвольные имена, bob and ted, foo и bar - все работает отлично.

Не собираюсь показывать целые векторы. Потому что cortex-m3 имеет миллион записей в таблице векторов, если вы делаете полную (варьируется от ядра к ядру и, возможно, в пределах одного и того же ядра в зависимости от параметров, выбранных производителем чипа) Соответствующие части находятся здесь после разборки:

08000000 <_start-0x148>:
 8000000:       20020000        andcs   r0, r2, r0
 8000004:       08000149        stmdaeq r0, {r0, r3, r6, r8}
 8000008:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
...
8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

Требуется некоторое количество проб и ошибок, чтобы поместить этот обработчик точно в нужное место, проверить с вашим чипом, где он должен быть, он не обязательно находится в том же месте, что и этот, и с таким количеством прерываний вы все равно можете искать другое прерывание. процессоры cortex-m, в отличие от обычных рук, делают это таким образом, чтобы вам не требовался батутный код для прерываний, они сохраняют определенное количество регистров и управляют переключением режимов процессора через содержимое регистров связи. до тех пор, пока аппаратное обеспечение и интерфейс для компилятора достаточно близки, все это работает. В этом случае я сделал обработчик в C, в отличие от других платформ и прошлого, вам не нужно делать ничего особенного с компилятором / синтаксисом, просто сделайте функцию (но не делайте глупых вещей в функции / обработчике)

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//-------------------------------------------------------------------

Makefile для blinker05 должен напоминать пример blinker02, в большинстве случаев он вырезан и вставлен. превратить отдельные исходные файлы в объекты, а затем связать. Я делаю сборку для большого пальца, thumb2, используя gcc и clang. Вы можете изменить строку all: на тот момент, чтобы включить элементы gcc, только если вы не включили / хотите использовать clang (llvm). Я использую binutils, чтобы собрать и связать вывод clang между прочим.

Во всех этих проектах используются бесплатные, готовые к использованию инструменты с открытым исходным кодом. нет IDE, только командная строка. Да, я связываюсь только с Linux, но не с Windows, но эти инструменты также доступны для пользователей Windows, меняя что-то вроде rm -f на что-то, что делится в make-файле, и тому подобное при сборке на windows. Это или запустить Linux на VMware или VirtualBox или QEMU. Отсутствие IDE означает, что вы также выбираете свой текстовый редактор, я не буду вдаваться в подробности, у меня есть мои любимые. Обратите внимание, что чрезвычайно раздражающей особенностью программы gnu make является то, что она требует наличия реальных вкладок в make-файле, я страстно ненавижу невидимые вкладки. Итак, один текстовый редактор для make-файлов, который оставляет вкладки, другой для исходного кода, который создает пробелы. Я не знаю об окнах,

Надеюсь, это поможет, это не точная микросхема / плата, а скважина m4 cortex-m4, а не m3, достаточно близкая для этого обсуждения. см. каталог mbed или stm32vld для получения информации о действительном cortex-m3 (не достаточно отличий от m4 для make-файлов, загрузочного кода и т. д.), но не сделанных st. Ядра cortex-m3 должны быть одинаковыми у разных поставщиков, cortex-m3 и cortex-m4 оба ARMv7m и ближе, чем различаются. Cortex-m0 - это ARMv6m, вряд ли у него достаточно инструкций thumb2, чтобы компиляторы его не догоняли, поэтому используйте только большой палец (представьте, что вы строите для ARMv4T (только большой палец), если это необходимо). Мой симулятор большого пальца - это только thumb, но не thumb2, он может быть полезен и вам, я думаю, я заставил его выполнять прерывания в той или иной форме.

Старожил
источник
Я читал ответ и думаю, что автором этого ответа будет ВЫ. Ваши ответы очень помогли мне и побудили меня перейти на процессоры ARM, а не на AVR и PIC Fanboy. Спасибо
MaNyYaCk
Пожалуйста
2

Вы можете взглянуть на этот сайт, где он пытается объяснить основы компоновщика и low_level_init в коде.

Обратите внимание, что страница сфокусирована на описании проблемы, поэтому вектор nvic является минимальным.

Затем у вас есть более полные примеры в «библиотеке стандартных периферийных устройств STM32F2xx», просто посмотрите разделы gcc (поскольку Yagarto основан на gcc). И там есть пример кода, который поможет вам с правильной настройкой nvic (таблицы векторов прерываний).

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

Johan
источник