http://github.com/dwelch67
stm32f4 y stm32vld en particular, pero los otros también pueden serle útiles. mbed y el directorio mzero debajo de mbed (cortex-m0).
Me gusta el enfoque estúpido simple, guiones de enlace mínimos, código de inicio mínimo, etc. El trabajo lo realiza el código, no ninguna cadena de herramientas en particular.
La mayoría de las formas de gcc y binutils (capaces de pulgar) funcionarán de alguna manera con estos ejemplos, ya que uso el compilador para compilar no como un recurso para las llamadas a la biblioteca, no uso los scripts del enlazador de acciones, etc. las partes más nuevas del thumb2 por lo que pueden ser necesarios algunos cambios
Construyo mi propio gcc, binutils y llvm / clang, así como también uso el código fuente (por ejemplo, ahora mentores gráficos, pero aún puede obtener la versión gratuita / lite).
Esp al comenzar a armar un proyecto para un nuevo objetivo, necesita hacer un poco de desmontaje. En particular para asegurarse de que los elementos estén donde los desea, por ejemplo, la tabla de vectores.
Mire stm32f4d / blinker02 por ejemplo. Comienza con vectors.s la tabla de excepción / vector más algunas rutinas de soporte de 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
No hay interrupciones en este ejemplo, pero las otras cosas que necesita están aquí.
blinker02.c contiene el cuerpo principal del código C con el punto de entrada C que llamo notmain () para evitar llamarlo main (algunos compiladores agregan basura a su binario cuando tiene un main ()).
te ahorrará cortar y pegar. El archivo MAKE cuenta la historia sobre compilación y vinculación. Tenga en cuenta que varios de mis ejemplos compilan dos o más archivos binarios del mismo código. compilador gcc, compilador clang de llvm, solo thumb y thumb2, diferentes optimizaciones, etc.
Comience haciendo archivos de objetos a partir de los archivos de origen.
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
el enlazador, ld, usa un script enlazador que llamo memmap, estos pueden ser extremadamente dolorosos, a veces por una buena razón, a veces no. Prefiero cuanto menos se acerque más a la talla única, todo menos el enfoque del fregadero de la cocina.
Normalmente no uso .data (bueno, casi nunca) y este ejemplo no necesita .bss, así que aquí está el script de enlace, solo lo suficiente para colocar el programa (.text) donde debe estar para este procesador como estoy. usándolo
MEMORY
{
ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
}
Tengo una región de memoria para definir eso, no hay nada especial sobre el nombre ram que puede llamar foo o bar o bob o ted, no importa, solo vincula los elementos de memoria a las secciones. Las secciones definen cosas como .text, .data, .bss, .rodata y dónde van en el mapa de memoria.
cuando construyes esto, ves que desmonto todo (objdump -D) ves esto
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}
La clave a tener en cuenta es que la dirección a la izquierda es donde la queríamos, el código vectors.s es el primero en el binario (porque es el primero en la línea de comando ld, a menos que haga algo en el script del enlazador, los elementos mostrarán arriba en el binario en el orden en que están en la línea de comando ld). Para arrancar correctamente, debe asegurarse de que su tabla de vectores esté en el lugar correcto. El primer elemento es mi dirección de pila, eso está bien. El segundo elemento es la dirección para iniciar y debe ser un número impar. el uso de .thumb_func antes de una etiqueta hace que esto suceda, por lo que no tiene que hacer otras cosas feas.
08000050 <_start>:
8000050: f000 f822 bl 8000098 <notmain>
8000054: e7ff b.n 8000056 <hang>
08000056 <hang>:
8000056: e7fe
entonces 0x08000051 y 0x08000057 son las entradas de vector apropiadas para _start y hang. iniciar llamadas notmain ()
08000098 <notmain>:
8000098: b510 push {
Eso se ve bien (no muestran la dirección impar en el desmontaje).
Todo está bien.
Pase al ejemplo blinker05, este admite interrupciones. y necesita algo de ram, por lo que se define .bss.
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x100000
ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
}
recuerda que ram y rom son nombres arbitrarios, bob y ted, foo y bar funcionan bien.
No se mostrarán los vectores completos porque el cortex-m3 tiene un billón de entradas en la tabla de vectores si realiza uno completo (varía de núcleo a núcleo y tal vez dentro del mismo núcleo dependiendo de las opciones elegidas por el proveedor del chip) Las porciones relevantes están aquí después del desmontaje:
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}
requiere un poco de prueba y error para colocar ese controlador exactamente en el lugar correcto, verifique con su chip dónde debe estar, no necesariamente en el mismo lugar que este, y con tantas interrupciones puede estar buscando una interrupción diferente de todos modos. Los procesadores Cortex-M, a diferencia de los brazos normales, hacen que no NECESITES código de trampolín para las interrupciones, conservan un cierto número de registros y gestionan el cambio de modos de procesador a través del contenido del registro de enlace. siempre y cuando el hardware y el abi para el compilador estén lo suficientemente cerca, todo funciona. En este caso, hice el controlador en C, a diferencia de otras plataformas y el pasado, no necesita hacer nada especial con el compilador / sintaxis, solo haga una función (pero no haga cosas estúpidas en la función / controlador)
//-------------------------------------------------------------------
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
//-------------------------------------------------------------------
El archivo MAKE para blinker05 debe parecerse al ejemplo de blinker02, principalmente cortar y pegar para la mayoría de estos. convertir los archivos de origen individuales en objetos y luego vincularlos. Construyo para thumb, thumb2 usando gcc y clang. puede cambiar la línea all: en ese momento para incluir solo los elementos gcc si no tiene / quiere un sonido metálico (llvm) involucrado. Utilizo binutils para ensamblar y vincular la salida de sonido por cierto.
Todos estos proyectos utilizan herramientas gratuitas, de código abierto, de código abierto. sin IDE, solo línea de comando. Sí, solo me meto con Linux y no con Windows, pero estas herramientas también están disponibles para los usuarios de Windows, cambian cosas como rm -f algo a algo en el archivo MAKE, cosas así al construir en Windows. Eso o ejecutar Linux en vmware o virtualbox o qemu. No usar un IDE significa que también eliges tu editor de texto, no voy a entrar en eso, tengo mis favoritos. Tenga en cuenta que una característica extremadamente molesta del programa gnu make es que requiere pestañas reales en el archivo MAKE, odio las pestañas invisibles con pasión. Entonces, un editor de texto para makefiles que deja pestañas, el otro para el código fuente que crea espacios. No sé sobre ventanas
Espero que esto ayude, no es el chip / placa exacto sino un cortex-m4 y m4 no m3, lo suficientemente cerca para esta discusión. vea el directorio mbed o stm32vld para un cortex-m3 real (no hay suficientes diferencias con respecto al m4 para los archivos MAKE y el código de arranque, etc.), pero no está hecho por st. Los núcleos de cortex-m3 deben ser los mismos en todos los proveedores, el cortex-m3 y el cortex-m4 son ARMv7m y están más cerca que son diferentes. El cortex-m0 es un ARMv6m, apenas tiene instrucciones suficientes para el pulgar2, los compiladores no lo han alcanzado, así que solo use el pulgar (pretenda que está construyendo un ARMv4T (solo el pulgar) si es necesario). Mi simulador de thumbulator es solo thumb, no thumb2, también podría ser útil para usted, creo que lo hice realizar interrupciones de alguna forma o forma.