STM32F2: Makefile, script de enlazador y combinación de archivo de inicio sin IDE comercial


16

He estado trabajando con un STM32F2 (específicamente, el STM32F217IGH6 en una placa de desarrollo) durante aproximadamente dos meses. Con mucho, mi mayor problema tenía que ver con la "configuración", que incluye el archivo MAKE, el script de enlace y el archivo de inicio.

En particular, no he podido configurar correctamente mi tabla de vectores de interrupciones y he llamado a los manejadores de interrupciones. ST proporciona ejemplos adaptados a IDEs comerciales. En cambio, estoy usando la compilación gratuita de Yagarto de la cadena de herramientas GCC (y OpenOCD para cargar la imagen a través de JTAG).

¿Hay proyectos de ejemplo para mi tablero (o un primo cercano) que contengan el archivo MAKE apropiado, la secuencia de comandos del enlazador y la combinación de archivos de inicio para IDE no comerciales que están configurados para que se llamen los manejadores de interrupciones?


2
Debes buscar ejemplos de Cortex M3, la placa y el procesador exactos no son tan importantes para las cosas que pides. Probablemente necesite modificar el diseño de la memoria en el script del enlazador y el método para flashear el archivo MAKE, pero eso debería ser todo.
starblue

1
¿Puedes poner todo esto en un repositorio de git y ponerlo en github o algo así?
AngryEE

1
Esta es exactamente la razón por la que dejé de usar el STM tan pronto como lo probé. Si van a hacerme la vida difícil con la desagradable cadena de herramientas, entonces me iré a otro lado. Cuando probé el IDE para PSoC3 y PSoC5, fue un mundo de diferencia.
Rocketmagnet

¿Estás comprometido con Yagarto? Eso está completamente bien y es una gran pregunta, pero estoy familiarizado con la cadena de herramientas CodeSourcery Lite . Probablemente podría adaptarse una respuesta para una cadena de herramientas diferente, pero no funcionaría de manera inmediata.
Kevin Vermeer

Respuestas:


20

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.


Estaba leyendo la respuesta y supongo que el autor de esta respuesta sería USTED. Sus respuestas me ayudaron mucho y me motivaron a pasar a los procesadores ARM que ser un Fanboy AVR y PIC. Gracias
MaNyYaCk

De nada ... pagar adelante ...
old_timer

2

Puede echar un vistazo a este sitio donde intenta explicar los conceptos básicos del vinculador y low_level_init en el código.

Tenga en cuenta que la página se centra en describir el problema, por lo que el vector nvic es un poco mínimo.

Luego tiene ejemplos más completos en la "biblioteca de periféricos estándar STM32F2xx", solo mire las secciones de gcc (ya que Yagarto está basado en gcc). Y hay un código de ejemplo que lo ayudará con una configuración correcta de nvic (tabla de vectores de interrupción).

Entonces, incluso si esta no es una respuesta completa, espero que sea de alguna manera útil.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.