http://github.com/dwelch67
stm32f4 e stm32vld em particular, mas os outros também podem ser úteis para você. mbed e o diretório mzero em mbed (córtex-m0).
Eu gosto de manter uma abordagem simples e estúpida, scripts mínimos de vinculador, código mínimo de inicialização etc. O trabalho é feito pelo código e não por qualquer cadeia de ferramentas específica.
A maioria das formas de gcc e binutils (capazes de usar o polegar) funcionará um pouco com esses exemplos, pois eu uso o compilador para compilar não como um recurso para chamadas de biblioteca, não uso scripts de vinculador de ações etc. O gcc e binutils mais antigos não sabem sobre as partes mais recentes do thumb2, portanto, algumas alterações podem ser necessárias.
Eu construo meu próprio gcc, binutils e llvm / clang, além de usar o codesourcery, por exemplo (agora mentor dos gráficos, mas você ainda pode obter a versão free / lite).
Esp Ao começar a montar um projeto para um novo alvo, você precisa desmontar. Em particular, para garantir que os itens estejam onde você deseja, a tabela de vetores, por exemplo.
Veja stm32f4d / blinker02 por exemplo. Começa com vectors.s, a tabela de exceção / vetor, além de algumas rotinas de suporte 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
Sem interrupções neste exemplo, mas as outras coisas que você precisa estão aqui.
O blinker02.c contém o corpo principal do código C com o ponto de entrada C que eu chamo de notmain () para evitar chamá-lo de principal (alguns compiladores adicionam lixo ao seu binário quando você tem um main ()).
você vai economizar um recorte e colar. o makefile conta a história sobre compilação e vinculação. Observe que vários dos meus exemplos compilam dois ou mais binários do mesmo código. compilador gcc, compilador clang do llvm, thumb only e thumb2, otimizações diferentes etc.
Comece criando arquivos de objeto a partir dos arquivos de origem.
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
o vinculador, ld, usa um script vinculador que eu chamo de memmap, que pode ser extremamente doloroso, às vezes por uma boa razão, às vezes não. Prefiro que menos seja mais abordagem para o tamanho único, tudo, menos a abordagem da pia da cozinha.
Eu não uso .data normalmente (bem quase nunca) e este exemplo não precisa .bss, então aqui está o script do vinculador, apenas o suficiente para colocar o programa (.text) onde ele precisa estar para esse processador do jeito que eu sou usando isso.
MEMORY
{
ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
}
Eu tenho uma região de memória para definir isso, não há nada de especial no nome ram que você pode chamar de foo ou bar ou bob ou ted, não importa, apenas vincula os itens de memória às seções. As seções definem coisas como .text, .data, .bss, .rodata e para onde elas vão no mapa de memória.
quando você constrói isso, você vê que eu desmonte tudo (objdump -D) você vê isso
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}
O ponto principal a ser observado é que o endereço à esquerda é o local onde desejávamos, o código vectors.s é o primeiro no binário (como é o primeiro na linha de comando ld, a menos que você faça algo no script do vinculador, os itens serão mostrados no binário na ordem em que estão na linha de comando ld). Para inicializar corretamente, você deve garantir que sua tabela de vetores esteja no lugar certo. O primeiro item é o endereço da minha pilha, tudo bem. O segundo item é o endereço para _start e deve ser um número ímpar. o uso de .thumb_func antes de um rótulo faz com que isso aconteça, assim você não precisa fazer outras coisas feias.
08000050 <_start>:
8000050: f000 f822 bl 8000098 <notmain>
8000054: e7ff b.n 8000056 <hang>
08000056 <hang>:
8000056: e7fe
portanto, 0x08000051 e 0x08000057 são as entradas de vetor adequadas para _start e travar. iniciar chamadas não principais ()
08000098 <notmain>:
8000098: b510 push {
Isso parece bom (eles não mostram o endereço numerado ímpar na desmontagem).
Tudo está bem.
Vá para o exemplo blinker05, este suporta interrupções. e precisa de um pouco de ram, então .bss é definido.
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x100000
ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
}
lembre-se ram e rom são nomes arbitrários, bob e ted, foo e bar funcionam bem.
Não mostrará os vetores inteiros porque o córtex-m3 possui um zilhão de entradas na tabela de vetores se você fizer um completo (varia de núcleo para núcleo e talvez dentro do mesmo núcleo, dependendo das opções escolhidas pelo fornecedor do chip) As partes relevantes estão aqui após a desmontagem:
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}
é preciso algumas tentativas e erros para colocar o manipulador exatamente no lugar certo, verifique com o seu chip onde ele precisa estar, não necessariamente no mesmo local que este e, com tantas interrupções, você pode estar procurando uma interrupção diferente. os processadores córtex-m, diferentemente dos braços normais, fazem com que você não precise de códigos de trampolim para interrupções, eles preservam um certo número de registros e gerenciam a alternância de modos de processador através do conteúdo do registro de links. desde que o hardware e a abi do compilador estejam próximos o suficiente, tudo funcionará. Neste caso, eu fiz o manipulador em C, ao contrário de outras plataformas e no passado, você não precisa fazer nada de especial com o compilador / sintaxe, basta criar uma função (mas não faz coisas estúpidas na função / manipulador)
//-------------------------------------------------------------------
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
//-------------------------------------------------------------------
O makefile para blinker05 deve se parecer com o exemplo blinker02, principalmente recortar e colar para a maioria deles. transforme os arquivos de origem individuais em objetos e vincule-os. Eu construo para thumb, thumb2 usando gcc e clang. você pode alterar a linha all: no momento para incluir apenas os itens do gcc se não tiver / deseja clang (llvm) envolvido. Eu uso binutils para montar e vincular a saída clang btw.
Todos esses projetos usam ferramentas gratuitas, prontas para uso, de código aberto. sem IDE, apenas linha de comando. Sim, eu apenas mexo no Linux e não no Windows, mas essas ferramentas também estão disponíveis para os usuários do Windows, alteram coisas como rm -f algo para deletar algo no makefile, coisas assim ao criar no Windows. Isso ou execute o linux no vmware, no virtualbox ou no qemu. Não usar um IDE significa que você escolhe seu editor de texto também, não vou entrar nisso, tenho meus favoritos. Note que uma característica extremamente irritante do programa gnu make é que ele requer abas reais no makefile, eu odeio abas invisíveis com paixão. Então, um editor de texto para makefiles que sai de abas, outro para código fonte que cria espaços. Eu não sei sobre janelas,
Espero que isso ajude, não é o chip / placa exato, mas um córtex-m4 bem m4 não m3, perto o suficiente para esta discussão. veja o dir mbed ou stm32vld para um córtex-m3 real (não há diferenças suficientes do m4 para makefiles e código de inicialização, etc.), mas não é feito por st. Os núcleos do córtex-m3 devem ser os mesmos entre os fornecedores, o córtex-m3 e o córtex-m4 são ambos ARMv7m e estão mais próximos do que diferentes. O córtex-m0 é um ARMv6m, dificilmente tem instruções para o polegar2 o suficiente para se preocupar, os compiladores não o alcançaram; portanto, use apenas o polegar (finja que você está construindo para um ARMv4T (apenas polegar), se necessário). Meu simulador de polegar é apenas polegar, sem polegar2, pode ser útil para você também, acho que o fiz executar interrupções de alguma forma ou moda.