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, он может быть полезен и вам, я думаю, я заставил его выполнять прерывания в той или иной форме.