El desarrollo de STM32 código del microcontrolador en Linux (parte 6 de 8, la construcción y la vinculación de programas STM32)

El primer post de esta serie cubre los pasos para generar y ejecutar código para el STM32. El segundo puesto cubierto cómo construir un compilador cruzado para el STM32. El tercer puesto cubierto cómo construir un depurador para el STM32. El cuarto puesto cubrió el edificio y la configuración OpenOCD para su entorno de desarrollo. El quinto puesto cubrió el edificio de la biblioteca de dispositivos, libopencm3. Este post cubrirá scripts de enlazador y las opciones de línea de comandos necesarios para la construcción y la vinculación de los programas que se ejecuten en el STM32. de
Una vez que tenemos todos los pasos previos realizados, somos dolorosamente cerca de ser capaz de construir y ejecutar código en nuestro procesador STM32 objetivo. Sin embargo, hay un conjunto más de los detalles de bajo nivel que tenemos que entender antes de que podamos llegar. Esos detalles giran en torno a cómo nuestro código C se convierte en código de máquina, y cómo se presenta ese código en la memoria. de
Como ustedes saben, la compilación de código para ejecutarse en un objetivo más o menos un proceso de dos pasos:

  1. Gire C / C + + código en código máquina del procesador de destino entiende. El resultado de este paso es lo que se conoce como ficheros objeto.
  2. Tome los archivos objeto y vincularlos entre sí para formar un binario coherente. El resultado de este paso es generalmente un archivo ELF.

Vamos a hablar de estos dos pasos con más detalle.

Compilar paso

Durante la compilación, el compilador analiza el / C + + de código C y lo convierte en un archivo objeto. Un poco más concretamente, ¿qué queremos tener nuestro compilador cruzado hacer es tomar nuestro código C, lo convierten en instrucciones ARM que se pueden ejecutar en el STM32, y luego la salida que en los archivos objeto.
Para ello, utilizamos nuestro compilador cruzado. Al igual que con cualquier versión de gcc, hay muchas banderas que se pueden pasar a nuestro compilador cruzado, y pueden tener muchos efectos en el código que se emite. Lo que voy a presentar aquí es un conjunto de banderas que he encontrado funciona bastante bien. Esto no es necesariamente óptima en cualquier dimensión, pero será al menos servir como un punto de partida para nuestro código. También voy a señalar que esto es donde empezamos a entrar en las diferencias entre los distintos procesadores STM32F *. Por ejemplo, el procesador STM32F4 tiene una FPU, mientras que el STM32F3 no lo hace. Esto afectará a las banderas que nosotros le pasaremos al compilador.
Para el procesador STM32F3, Cortex-M3 que estoy usando, aquí están las opciones del compilador: -Wall-Wextra-Wimplicit-función-declaración-Wredundant-decls-Wstrict-prototipos-Wundef-Wshadow -g-fno-common-mcpu = Cortex-M3-mthumb-mfloat-abi = hard-MD
Vamos a través de cada uno de ellos. -W banderas * dicen que el compilador genere advertencias en tiempo de compilación para varias clases de errores comunes. Me parece que la activación de estas advertencias y deshacerse de ellos por lo general hace que el código sea mucho mejor. La opción-g le indica al compilador que incluya símbolos de depuración en el binario, lo que hace que el código sea más fácil de depurar, a expensas de un poco de espacio de código. La bandera-fno común dice gcc para colocar las variables globales sin inicializar en la sección de datos del binario, lo que mejora el rendimiento un poco. El-mcpu = Cortex-M3 le dice al compilador que tenemos un Cortex-M3, y por lo tanto para generar código optimizado para el procesador Cortex-M3. El distintivo-mthumb dice gcc para generar código pulgar ARM, que es más pequeño y más compacto que el código ARM completo. El mfloat-abi = duro bandera dice gcc que queremos usar un flotador duro ABI, lo que no hace una gran diferencia en un procesador sin FPU, pero es un buen hábito para entrar. Por último, la opción-MD dice gcc para generar archivos de dependencia durante la compilación, que es útil para Makefiles. paso

Vinculación

Una vez que todos los archivos individuales han sido compilados, se ponen juntos en el binario final por el enlazador. Esto es más complicado cuando la orientación de una plataforma integrada frente a un programa regular. En particular, tenemos que decirle al enlazador no sólo los archivos que desea vincular juntos, pero también ¿ para poner el binario resultante fuera en flash y en la memoria.
Vamos a primera apertura hablando de las banderas que tenemos que pasar al enlazador para hacer este trabajo. Éstos son el conjunto de indicadores que vamos a comenzar con: - static-lc-lnosys-T tut.ld-nostartfiles-Wl, - GC-secciones-mcpu = Cortex-M3-mthumb-mfloat-abi = hard-lm-Wl,-Map = tut.map Tarjetas telefónicas Una vez más, vamos a ir a través de cada uno de ellos. La opción – static indica al vinculador para vincular una estática, no un enlace dinámico, binario. Esta bandera, probablemente no es estrictamente necesario en este caso, pero añadimos que de todos modos. El distintivo-lc indica al vinculador para vincular este binario con la librería C, que es newlib en nuestro caso. Eso nos da acceso a varias funciones útiles, tales como printf (), scanf (), etc-lnosys bandera indica al vinculador para vincular este binario en contra de la «nosys» biblioteca. Varias de las funciones de conveniencia en la biblioteca de C requieren implementaciones subyacentes de ciertas funciones para operar, como _write () para printf (). Dado que no tenemos un sistema operativo POSIX que puede proporcionar estos para nosotros, la biblioteca nosys proporciona funciones de código auxiliar vacío para estos. Si queremos, podemos definir más adelante en nuestras propias versiones de estas funciones stub que acostumbrarse lugar. El distintivo-T tut.ld indica al vinculador que utilizar tut.ld que el script enlazador; hablaremos más acerca de scripts de enlazador de abajo. Los-nostartfiles bandera indica al enlazador a no utilizar los archivos de inicio del sistema estándar. Dado que no tenemos un sistema operativo aquí, no podemos confiar en las utilidades del sistema operativo estándar para iniciar nuestro programa de arriba. El-Wl, – GC-secciones bandera indica al vinculador que recoger basura secciones no utilizadas. Es decir, todas las secciones que no se hace referencia se eliminan de la binario resultante, lo que puede reducir el tamaño del binario. El-mcpu = Cortex-M3,-mthumb, y mfloat-abi = banderas duras tienen el mismo significado que para las opciones del compilador. El distintivo-lm le indica al vinculador para vincular este binario en contra de la biblioteca matemática. No es estrictamente necesario para nuestros pequeños programas, pero la mayoría de los programas lo quiere más pronto o más tarde. Por último, la-Wl,-Map = tut.map indica al vinculador que genere un archivo de mapa y pegarlo en tut.map. El archivo de mapa es útil para la depuración, pero es sólo informativo.

vinculador de script

Como se mencionó antes, la secuencia de comandos del vinculador le dice al enlazador cómo diseñar el binario resultante en la memoria. Este script es altamente específico chip. Los detalles tienen que ver con el lugar donde el procesador salta a el reinicio, y donde se espera que ciertas cosas sean. Tenga en cuenta que la mayoría de los chips son realmente configurable (basado en algunas configuraciones de puente), así que donde salta a el reajuste pueden cambiar. Afortunadamente, para la mayoría de los diseños de off-the-shelf STM32, incluidas las placas DISCOVERY, siempre se configura para esperar que el código para iniciar en flash. Por lo tanto, la secuencia de comandos del vinculador le dice al enlazador para diseñar el código en flash, pero para poner los datos y bss en la memoria RAM.
Con todo esto dicho, libopencm3 en realidad lo hace fácil en usted. Tienen scripts de enlazador por defecto para cada una de las fichas que se admiten. Todo lo que necesitas hacer es rellenar un pequeño guión de enlazado con el tamaño de la memoria RAM y FLASH de su ficha, incluya el defecto libopencm3 uno, y ya está.
Así que vamos a poner todo lo anterior junto y escribir un Makefile y un guión de engarce en el directorio del proyecto que hemos creado en el tutorial anterior. Ninguno de estos son necesariamente los mejores ejemplos de lo que debe hacer, pero van a hacer el trabajo. Primero el Makefile:
$ cd ~ / STM32-project precio: $ cat < Makefile
CC = brazo--ningunos-eabi gcc
LD = $ (CC)
objcopy = arm-none-eabi-objcopy
OpenOCD = ~ / opt / / bin / OpenOCD
CFLAGS =-Wall-Wextra-Wimplicit-función-de declaración-Wredundant-decls transversales - Wstrict-prototipos-Wundef-Wshadow-g-fno--mcpu común = Cortex-M3-mthumb-mfloat-abi = hard-MD-DSTM32F3
LDFLAGS = - static-lc-lnosys-T tut.ld-nostartfiles -Wl, - GC-secciones-mcpu = Cortex-M3-mthumb-mfloat-abi = hard-lm-Wl,-Map = tut.map
OBJS = tut.o
todo: tut . bin
tut.bin: tut.elf precio: $ (echo-e " t") $ (objcopy)-Obinary tut.elf tut.bin
tut.elf: $ (OBJS) precio: $ (echo-e " t") $ (CC)-o tut.elf $ (OBJS) ~ / opt/cross/arm-none-eabi/lib/libopencm3_stm32f3.a - static -LC-lnosys-T tut.ld-nostartfiles-Wl, - GC-secciones-mcpu = Cortex-M3-mthumb-mfloat-abi = hard-lm-Wl,-Map = tut.map
Flash: tut.bin precio: $ (echo-e " t") sudo $ (OpenOCD)-f-STM32 openocd.cfg-c "init"-c "reset init"-c "Flash write_image borrado tut.bin 0x08000000 "-c" reset run shutdown "-c" "
limpia: precio: $ (echo-e".... t ") rm-f * elf * bin * Lista * mapa * . o *. d * ~
EOF
Usted debe notar un par de cosas en el Makefile. En primer lugar, utilizamos todas las opciones del compilador y enlazador que hemos hablado antes. En segundo lugar, nuestros objetos ($ OBJS) son tut.c, que vamos a crear en el próximo post. Y en tercer lugar, tenemos un objetivo en flash que realizará el proyecto, y el flash es en el procesador de destino. Esto requiere que el archivo de configuración OpenOCD que creamos hace un par de posts
Ahora el guión de enlazado:.

 /> 
tut.ld

MEMORIA {
rom (rx): ORIGEN = 0x08000000, LONGITUD = 256 K />
}

/ * Incluir el guión ld común. * /
CONTENER libopencm3_stm32f3.ld EOF />

Se dará cuenta de que no hay mucho aquí. Sólo tenemos que definir la posición de la RAM y el tamaño, y la ROM (Flash) ubicación y el tamaño, y la secuencia de comandos del vinculador libopencm3 defecto nos encargamos del resto.
Ahora tenemos todas las piezas en su lugar. El próximo post va a escribir, compilar y ejecutar un programa simple en el tablero.

Deja un comentario

Tu dirección de correo electrónico no será publicada.