Tabla de contenido:

Parte 1 Ensamblaje del brazo TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 pasos
Parte 1 Ensamblaje del brazo TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 pasos

Video: Parte 1 Ensamblaje del brazo TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 pasos

Video: Parte 1 Ensamblaje del brazo TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 pasos
Video: TI-RSLK MAX Assembly Guide 2024, Mes de julio
Anonim
Image
Image

El enfoque de este Instructable es el microcontrolador STM32 Nucleo. La motivación para esto es poder crear un proyecto de montaje a partir de los huesos. Esto nos ayudará a profundizar y comprender el proyecto MSP432 Launchpad (el TI-RSLK) que ya ha sido el tema de varios Instructables.

No hay mucha ayuda en línea para crear un proyecto de solo ensamblaje para MSP432, usando Code Composer Studio. Hasta ahora solo hemos estado copiando / pegando de un proyecto de ensamblaje preexistente. Este enfoque nos ha sido de gran utilidad.

Sin embargo, ahora, para Lab 7, nos encontramos con un pequeño problema. O al menos un hipo temporal. El Laboratorio 7 presenta máquinas de estados finitos, y lo primero que encontramos es la necesidad de crear y usar una matriz de valores. Dado que el curso de TI utiliza principalmente programación en C, esto no es un problema. Pero estos Instructables se han centrado en el montaje, no en C.

Además, dado que la matriz es de valores de solo lectura, sería bueno colocarla en la memoria flash, no en la RAM.

Parece haber mucha más ayuda en línea para proyectos de ensamblaje que usan el MCU STM32, por lo tanto, comenzamos con este Instructable, con el objetivo de usar lo aprendido, para luego aplicarlo al MSP432 y Code Composer Studio.

En el camino hacia ese objetivo, también habremos adquirido experiencia con otro microcontrolador más popular.

Paso 1: prueba inicial del dispositivo

Prueba inicial del dispositivo
Prueba inicial del dispositivo
Prueba inicial del dispositivo
Prueba inicial del dispositivo
Prueba inicial del dispositivo
Prueba inicial del dispositivo

Nuevamente, ¿por qué elegir el STM32 Nucleo en particular?

¿Honestamente? Porque estaba buscando buenos artículos sobre proyectos de ensamblaje completo para controladores ARM, y encontré esta serie. Y también porque el STM32 parece ser un MCU popular.

Investigué un poco (hay muchas versiones para elegir, vea la imagen de arriba), pero al final se convirtió en lo que realmente puedo obtener, ya que iba a usar Amazon (en los EE. UU.).

Viene en un paquete simple pero profesional, con algunas instrucciones de inicio. Fue un poco divertido ver que la demostración grabada en el controlador era casi exactamente lo que hicimos en Instructables anteriores: un LED parpadea y cambia de velocidad de acuerdo con la presión de un botón.

Parece que esta placa de desarrollo es muy similar a la MSP432 en que hay 2 LED y un botón de usuario. El MSP432 tiene 2 botones de usuario.

Como puede ver en las fotos, me sorprendió un poco que la placa tenga un mini y no un micro USB. Tuve que salir corriendo para comprar un cable.

Otra buena prueba es que cuando lo conectas a tu computadora (estoy usando una caja de Linux), aparece en mi administrador de archivos, como un sistema de archivos, llamado "NODE_F303RE". Apertura que revela dos archivos, uno HTML y otro de texto.

Eso es todo, pero al menos también dice que la conectividad parece bastante fácil.

Ahora estamos listos para comenzar.

Intentaré no repetir la buena información de la serie de artículos de IVONOMICON Bare Metal, sino aumentarla.

Paso 2: Lo esencial

Lo primero que necesitamos es un compilador.

Y luego, necesitamos un depurador:

devchu @ chubox: ~ $ sudo apt-get install gdb-arm-none-eabi Leyendo listas de paquetes… Listo Construyendo árbol de dependencias Leyendo información de estado… Listo Se instalarán los siguientes NUEVOS paquetes: gdb-arm-none-eabi 0 actualizado, 1 nuevo instalado, 0 para eliminar y 8 no actualizado. Necesita obtener 2, 722 kB de archivos. Después de esta operación, se utilizarán 7, 738 kB de espacio adicional en disco. Obtener: 1 https://us.archive.ubuntu.com/ubuntu xenial / universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3 + 9 [2, 722 kB] Obtenido 2, 722 kB en 1s (1, 988 kB / s) Seleccionando el paquete gdb-arm-none-eabi previamente no seleccionado. (Leyendo la base de datos… 262428 archivos y directorios instalados actualmente.) Preparándose para descomprimir… / gdb-arm-none-eabi_7.10-1ubuntu3 + 9_amd64.deb… Desempaquetando gdb-arm-none-eabi (7.10-1ubuntu3 + 9)… Procesando disparadores para man-db (2.7.5-1)… Configurando gdb-arm-none-eabi (7.10-1ubuntu3 + 9)…

Paso 3: Lo esencial - Windows

El paso anterior asumió que estamos usando Linux. ¿Y si usamos Windows?

Puede ir al sitio para desarrolladores de arm y hay varias opciones de descarga disponibles. Estoy usando una máquina con Windows 8.

Durante la instalación, elegí instalarlo en la unidad raíz "C: \" en lugar de Archivos de programa solo porque también estoy usando cygwin, y fue más fácil crear un enlace desde mi contenedor local a una carpeta raíz C: que todos los lío en la ruta de los archivos de programa (con espacios, etc.).

Por lo tanto, mi entorno y ruta cygwin, etc., se ve así:

C: / cygwin64 / home / bin / arm-none-eabi-gcc, donde arm-none-eabi-gcc es un enlace a C: / GNUToolsArmEmbedded / 7.2018.q2.update / bin / arm-none-eabi- gcc.

Luego creé una carpeta "dev" en cygwin home, y ahí es donde coloqué el archivo core. S y ejecuté el comando del compilador. (ver más abajo para el material del compilador).

Hice exactamente lo mismo para gdb (arm-none-eabi-gdb).

Paso 4: ¿Cuáles son los elementos esenciales?

Entonces, ¿qué es "gcc-arm-none-eabi"?

El compilador gnu (GCC) compilará lenguajes de programación (como C) en código nativo para la máquina en la que se está ejecutando. Por ejemplo, si tuviera que compilar algún código C usando GCC en su máquina con Windows, estaría construido para ejecutarse en la máquina con Windows. El ejecutable generado no se ejecutará (normalmente) en el microcontrolador ARM.

Entonces, para construir programas para descargarlos y grabarlos en el microcontrolador ARM (en nuestro caso actual sería el STM32 Nucelo), necesitamos darle a GCC algo más: la capacidad de "compilar de forma cruzada". Es decir, la capacidad de generar un ejecutable, no para su sistema nativo (y procesador), sino para el sistema de destino (el microcontrolador ARM). Ahí es donde entra en juego "gcc-arm-none-eabi".

Entonces, ¿qué es "gdb-arm-none-eabi"?

Una vez que hayamos descargado y grabado (flasheado) el ejecutable recién generado en el microcontrolador, probablemente querremos depurarlo, paso a paso línea por línea del código. GDB es el depurador gnu y también necesita una forma de hacer su trabajo, pero apuntando a un sistema diferente.

Por lo tanto, gdb-arm-none-eabi es para GDB, lo que gcc-arm-none-eabi es para GCC.

Otra instalación de paquete sugerida fue "libnewlib-arm-none-eabi". ¿Qué es ése?

Newlib es una biblioteca C y una biblioteca matemática diseñada para su uso en sistemas integrados. Es un conglomerado de varias partes de la biblioteca, todas bajo licencias de software libre que las hacen fácilmente utilizables en productos integrados.

Y finalmente, el paquete "libstdc ++ - arm-none-eabi". Ese es bastante obvio; es la biblioteca C ++ para el compilador cruzado; para microcontroladores ARM integrados.

Paso 5: el archivo del vinculador

El archivo del vinculador
El archivo del vinculador
El archivo del vinculador
El archivo del vinculador

Creemos un script de creación de enlaces.

Una parte o bloque clave en este archivo sería el comando MEMORY.

--- de sourceware.org:

La configuración predeterminada del vinculador permite la asignación de toda la memoria disponible. Puede anular esto usando el comando MEMORY. El comando MEMORY describe la ubicación y el tamaño de los bloques de memoria en el destino. Puede usarlo para describir qué regiones de memoria puede usar el enlazador y qué regiones de memoria debe evitar. Luego puede asignar secciones a regiones de memoria particulares. El enlazador establecerá direcciones de sección basadas en las regiones de memoria y advertirá sobre regiones que se llenen demasiado. El enlazador no mezclará las secciones para que quepan en las regiones disponibles. Un script del enlazador puede contener muchos usos del comando MEMORY, sin embargo, todos los bloques de memoria definidos se tratan como si estuvieran especificados dentro de un solo comando MEMORY.:

MEMORIA

{nombre [(atributo)]: ORIGEN = origen, LONGITUD = longitud…}

El ejemplo del artículo:

/ * Definir el final de la RAM y el límite de la memoria de pila * // * (SRAM de 4 KB en la línea STM32F031x6, 4096 = 0x1000) * / / * (La RAM comienza en la dirección 0x20000000) _estack = 0x20001000;

MEMORIA

{FLASH (rx): ORIGEN = 0x08000000, LENGTH = 32K RAM (rxw): ORIGIN = 0x20000000, LENGTH = 4K}

Así que necesitamos averiguar cuánto FLASH (para nuestro programa y constantes, etc.) y cuánta RAM (para uso del programa; pila y pila, etc.) para nuestra placa en particular. Esto se pone un poco interesante.

La pequeña tarjeta que viene con el Nucleo dice que tiene memoria flash de 512 Kbytes y SRAM de 80 Kbytes. Sin embargo, al conectarlo a USB, se monta como un sistema de archivos con dos archivos, y tanto el administrador de archivos como GParted indican que tiene más de 540 Kbytes de espacio. (¿RAM?).

PERO, al intentar eliminar los dos archivos usando el administrador de archivos, desconectar y volver a conectar el dispositivo, todavía se muestran los dos archivos. (y el administrador de archivos reconoció algo porque hay un pequeño icono de "candado" en cada archivo.

Así que vayamos con las cifras de la tarjeta. Así que ahora tomamos el ejemplo anterior y lo convertimos a nuestra placa específica.

Es posible que desee utilizar algo como este convertidor de memoria en línea, para pasar de la KB general a una cantidad específica de bytes.

Entonces es posible que desee utilizar un convertidor de decimal a hexadecimal en línea.

/ * Definir el final de la RAM y el límite de la memoria de pila * /

/ * (4KB SRAM en la línea STM32F031x6, 4096 = 0x1000) * // * el ejemplo * /

/ * paso 1: (80KB SRAM en el STM32F303RE, 81920 = 0x14000) * // * nuestra placa * /

/ * paso 2, agregue el tamaño hexadecimal a la dirección inicial hexadecimal (a continuación). * /

/ * (RAM comienza en la dirección 0x20000000) * /

_estack = 0x20001000; /* el ejemplo */

_estack = 0x20014000; / * nuestro tablero * /

MEMORIA {

DESTELLO (rx): ORIGEN = 0x08000000, LONGITUD = 512K

RAM (rxw): ORIGEN = 0x20000000, LONGITUD = 80K

}

Llamemos al archivo anterior "linker.script.ld".

Paso 6: la tabla de vectores

La tabla de vectores
La tabla de vectores

Ahora vamos a crear un pequeño archivo de ensamblaje (con directivas) para hacer un manejo de interrupciones muy básico. Seguiremos el ejemplo del artículo y crearemos un archivo llamado "core. S".

Nuevamente, aquí está el contenido del archivo de ejemplo, pero hice un cambio para nuestra placa específica:

// Estas instrucciones definen atributos de nuestro chip y

// el lenguaje ensamblador que usaremos:.syntax unified / * Ver más abajo después de este área de código * / /*.cpu cortex-m0 * / / * comentar esta línea del ejemplo * /.cpu cortex-m4 / * agregue en su lugar la corteza de nuestro tablero. vea la imagen de arriba en este paso * / /*.fpu softvfp * / / * comente esta línea del ejemplo * /.fpu vfpv4 / * agregue en su lugar nuestro tablero; tiene una FPU * /.thumb // Ubicaciones de memoria global..global vtable.global reset_handler / * * La tabla de vectores real. * Solo se incluye el tamaño de la RAM y el controlador de 'reinicio' *, por simplicidad. * /.type vtable,% object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Hmm … No hay directiva '.align'

Sin embargo, eso no es crítico. Más sobre eso (tal vez) más adelante.

.syntax unificado

.syntax [unificado | dividido]

Esta directiva establece la sintaxis del conjunto de instrucciones como se describe en la sección ARM-Instruction-Set

9.4.2.1 Sintaxis del conjunto de instrucciones Dos sintaxis ligeramente diferentes son compatibles con las instrucciones ARM y THUMB. El predeterminado, dividido, usa el estilo antiguo donde las instrucciones ARM y THUMB tenían sus propias sintaxis separadas. La nueva sintaxis unificada, que se puede seleccionar mediante la directiva.syntax.

.fpu vfpv4

El compilador GCC puede producir binarios con varias opciones con respecto al punto flotante: suave - adecuado para ejecutarse en CPU sin FPU - los cálculos se realizan en software mediante softfp generado por el compilador - adecuado para ejecutarse en CPU con o sin FPU - usará una FPU si está presente. Para nuestro caso específico (tendrá que hacer su propia investigación), la FPU de esta placa en particular se ajusta a vfpv4. Puede que tengas que jugar con esto. O incluso déjelo en softfp.

.pulgar (vs. brazo)

Estos microcontroladores ARM en realidad tienen una combinación de conjuntos de instrucciones. Uno es BRAZO, otro es PULGAR. Una diferencia son las instrucciones de 16 bits frente a las instrucciones de 32 bits. Por lo tanto, esta directiva le dice al compilador que trate las instrucciones posteriores como THUMB o ARM.

Vamos a tomar el resto del archivo como está, ya que estos Instructables aún no han profundizado en la programación de ensamblajes controlados por interrupciones.

Paso 7: la versión de ensamblaje de un programa 'Hola mundo'

Lo siguiente también puede ir al archivo "core. S" creado previamente. Esto, nuevamente, es del ejemplo del artículo.

/ * * El controlador Reset. Llamado al reiniciar. * /.type reset_handler,% function reset_handler: // Establece el puntero de la pila al final de la pila. // El valor '_estack' está definido en nuestro script de enlazador. LDR r0, = _apilamiento MOV sp, r0

// Establece algunos valores ficticios. Cuando vemos estos valores

// en nuestro depurador, sabremos que nuestro programa // está cargado en el chip y funcionando. LDR r7, = 0xDEADBEEF MOVS r0, # 0 main_loop: // Agregar 1 para registrar 'r0'. ADDS r0, r0, # 1 // Bucle hacia atrás. B main_loop.size reset_handler,.-Reset_handler

Entonces, el impulso del programa anterior es cargar un patrón reconocible en un registro MCU central (en este caso R7), y un valor creciente que comienza en cero en otro registro MCU central (en este caso R0). Si recorremos el código de ejecución, deberíamos ver el incremento de datos de R0.

Si ha estado siguiendo los Instructables con respecto al MSP432 y los cursos / laboratorios de TI-RSLK, entonces casi todo el programa anterior le resultará familiar.

Lo único nuevo que puedo ver es el uso de "=" al cargar "DEADBEEF" para registrar R7. No lo habíamos usado.

El archivo "core. S" adjunto aquí ahora contiene la fuente completa.

Paso 8: compilar el código

Es hora de hacer algunas cosas con la línea de comandos. Algo real, finalmente.

Sin embargo, no estamos del todo ahí. Nuevamente tenemos que ajustar el comando dado en el artículo y modificarlo a nuestra propia situación.

Aquí está el código de ejemplo:

arm-none-eabi-gcc -x ensamblador-con-cpp -c -O0 -mcpu = cortex-m0 -mthumb -Wall core. S -o core.o

Si vamos al sitio gnu.org para GCC, (en este caso la versión 7.3),

X

La -x es para especificar el idioma. De lo contrario, si no -x, el compilador intentará adivinar utilizando la extensión del archivo. (en nuestro caso, *. S).

El ejemplo anterior del artículo especifica ensamblador-con-cpp, pero podríamos hacer ensamblador.

C

La -c dice compilar pero no vincular.

O0

El -O es para establecer el nivel de optimización. El uso de -O0 (oh-zero) dice "reducir el tiempo de compilación y hacer que la depuración produzca los resultados esperados. Este es el valor predeterminado".

mcpu = corteza-m0

-Mcpu especifica el nombre del procesador de destino. En nuestro caso, sería cortex-m4.

mthumb

-Mthumb especifica la selección entre generar código que ejecuta los estados ARM y THUMB.

Pared

El -Wall es, por supuesto, muy común y conocido. Enciende todas las banderas de advertencia.

Finalmente, al final del comando tenemos el archivo de entrada core. S y el archivo de salida core.o.

Aquí está la nueva línea de comando resultante para adaptarse a nuestro caso específico.

arm-none-eabi-gcc -x ensamblador -c -O0 -mcpu = cortex-m4 -mthumb -Wall core. S -o core.o

Y eso compilado.

Paso 9: Vinculación del programa

Directamente del ejemplo del artículo, tenemos esto:

arm-none-eabi-gcc core.o -mcpu = cortex-m0 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

La mayor parte de lo anterior que has visto. A continuación se muestran las novedades.

specs = nosys.specs

Este es un poco complicado de explicar.

Tiene que ver con "semihosting" y "retargeting", y tiene que ver con entrada / salida. También tiene que ver con las llamadas al sistema y las bibliotecas.

Normalmente, los sistemas integrados no proporcionan dispositivos de entrada / salida estándar. Esto afectaría las llamadas al sistema o a la biblioteca (ejemplo: printf ()).

Semihosting significa que el depurador (vea la imagen del Paso 11 con la parte del depurador en un círculo rojo) tiene un canal especial y usa el protocolo de semihosting, y puede ver la salida de printf () en la máquina host (a través del depurador).

Retargeting, por otro lado, significa que esas mismas llamadas al sistema o biblioteca significan algo más. Hacen otra cosa que tiene sentido para el sistema integrado. En cierto sentido, digamos para printf (), hay una nueva implementación, una implementación reorientada de esa función.

Habiendo dicho todo eso, --specs = nosys.specs significa que no seremos semihospedadores. Eso normalmente significaría que estamos reorientando. Eso nos lleva a la siguiente bandera.

nostdlib

La opción de enlazador -nostdlib se utiliza para enlazar un programa destinado a ejecutarse de forma independiente. -nostdlib implica las opciones individuales -nodefaultlibs y -nostartfiles. A continuación, discutimos las dos opciones por separado, pero el uso más típico es simplemente nostdlib para una ventanilla única. Cuando se vincula un programa alojado, las bibliotecas estándar del sistema como libc están vinculadas de manera predeterminada, lo que le da al programa acceso a todas las funciones estándar (printf, strlen y amigos). La opción del enlazador -nodefaultlibs deshabilita el enlace con esas bibliotecas predeterminadas; las únicas bibliotecas vinculadas son exactamente aquellas a las que le asigna un nombre explícito al vinculador mediante el indicador -l.

lgcc

libgcc.a es una biblioteca estándar que proporciona subrutinas internas para superar las deficiencias de máquinas particulares. Por ejemplo, el procesador ARM no incluye una instrucción de división. La versión ARM de libgcc.a incluye una función de división y el compilador emite llamadas a esa función donde sea necesario.

T

Esta es solo una forma de decirle al vinculador que use este archivo como secuencia de comandos del vinculador. En nuestro caso, el nombre del archivo es linker.script.ld.

o main.elf

Finalmente, le decimos al enlazador cuál será el nombre del archivo de imagen de salida final que se grabará / flasheará en nuestro dispositivo.

Aquí está nuestra versión de la línea de comandos completa, modificada para nuestra situación específica:

arm-none-eabi-gcc core.o -mcpu = cortex-m4 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Nos aseguramos de que el archivo de secuencia de comandos y el archivo core.o estén en el mismo directorio, donde ejecutaremos la línea de comandos anterior.

Y enlaza sin problemas.

Un cheque

Luego ejecutamos:

arm-none-eabi-nm main.elf

y obtenemos:

devchu @ chubox: ~ / Desarrollo / Atollic / TrueSTUDIO / STM32_workspace_9.1 $ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Se ve bien. El comando arm-none-eabi-nm es una forma de listar símbolos dentro de archivos de objetos.

Paso 10: Prueba de la conexión al STM32 Nucleo-64

Prueba de la conexión al STM32 Nucleo-64
Prueba de la conexión al STM32 Nucleo-64
Prueba de conexión al STM32 Nucleo-64
Prueba de conexión al STM32 Nucleo-64

Su primera misión, si decide aceptarla, es hacer que su sistema vea su placa de desarrollo.

Usando Windows

Para Windows, decidí instalar TrueSTUDIO de Atollic (versión gratuita). Fue una instalación sencilla y automáticamente instaló el controlador para que pudiera usar st-link para probar la conexión. Una vez que instalé TrueSTUDIO y el administrador de dispositivos vio el dispositivo, descargué las herramientas texan / stlink sugeridas por el artículo de Bare Metal que hemos estado siguiendo. Volví a colocar la carpeta directamente debajo de "C: \", y nuevamente creé algunos enlaces desde mi contenedor de inicio cygwin local a los comandos.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~ / bin / st-info

Como prueba inicial para ver si realmente podemos comunicarnos con el dispositivo, ejecuté:

st-info --probe

Y regresé:

Se encontraron 1 programadores de stlink

Entonces ahora sabemos que podemos hablar / consultar nuestra placa de desarrollo.

Usando Linux

Para Linux, realmente no necesita un controlador. Pero para Debian, tendrá que construir las herramientas st desde el código fuente.

clon de git

Asegúrese de tener instalado libusb-1.0-0-dev.

lista de aptos | grep -E "* libusb. * dev *"

Deberías ver:

libusb-1.0-0-dev / xenial, ahora 2: 1.0.20-1 amd64 [instalado]

o algo así.

Para instalarlo:

sudo apt-get install libusb-1.0-0-dev

Tenga en cuenta que lo anterior no es lo mismo que:

sudo apt-get install libusb-dev

El dev libusb correcto que falta puede hacer que cmake tenga problemas.

Error de CMake: Las siguientes variables se utilizan en este proyecto, pero están configuradas como NOTFOUND. Configúrelas o asegúrese de que estén configuradas y probadas correctamente en los archivos de CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Cambie al directorio raíz del proyecto (… blah / blah / stlink). Haz un "lanzamiento de liberación".

Después de que se compila, las herramientas deben estar en ".. / build / Release".

A continuación, puede ejecutar "st-info --probe". Aquí está la salida con el Nucleo conectado, entonces no.

devchu @ chubox: ~ / Development / stlink $./build/Release/st-info --probeFound 1 programadores stlink serie: 303636414646353034393535363537 openocd: "\ x30 / x36 / x36 / x41 / x46 / x46 / x35 / x30 / x34 / x39 / x35 / x35 / x36 / x35 / x37 "flash: 524288 (tamaño de página: 2048) sram: 65536 chipid: 0x0446 descr: F303 dispositivo de alta densidad devchu @ chubox: ~ / Development / stlink $./build/Release/st- info --probe Se encontraron 0 programadores stlink devchu @ chubox: ~ / Development / stlink $

Paso 11: Usemos GDB con Linux

Usemos GDB con Linux
Usemos GDB con Linux
Usemos GDB con Linux
Usemos GDB con Linux

Si ha estado probando todo esto y ha llegado hasta aquí, ¡genial! Excelente. Divirtámonos un poco ahora.

Cuando compra estas placas de desarrollo ARM, ya sea el Launchpad MSP432 de Texas Instruments, o el que estamos discutiendo ahora, el Nucleo-F303 (STM32 Nucleo-64), generalmente llegan ya con un programa en ejecución, generalmente algún programa parpadeante que también incluye presionar un interruptor para cambiar la velocidad a la que parpadean los LED.

Antes de que nos apresuremos a sobrescribir eso, veamos qué hay para ver y hacer.

Con Linux, abra una terminal, cambie el directorio del proyecto stlink git que acabamos de construir y busque la herramienta st-util.

devchu @ chubox: ~ / Desarrollo / stlink $ find. -nombre st-util

./build/Release/src/gdbserver/st-util

Ejecute esa herramienta. Como ya hemos probado previamente nuestra conexión con st-info --probe, deberíamos obtener un resultado como este:

devchu @ chubox: ~ / Desarrollo / stlink $./build/Release/src/gdbserver/st-util

st-util 1.4.0-50-g7fafee2 2018-10-20T18: 33: 23 INFO common.c: Cargando parámetros del dispositivo…. 2018-10-20T18: 33: 23 INFO common.c: El dispositivo conectado es: dispositivo de alta densidad F303, id 0x10036446 2018-10-20T18: 33: 23 INFO common.c: Tamaño de SRAM: 0x10000 bytes (64 KiB), Flash: 0x80000 bytes (512 KiB) en páginas de 2048 bytes 2018-10-20T18: 33: 23 INFO gdb-server.c: El ID del chip es 00000446, el ID del núcleo es 2ba01477. 2018-10-20T18: 33: 23 INFO gdb-server.c: Escuchando en *: 4242…

Ese es el servidor GDB que se está ejecutando ahora, y ve nuestra placa de desarrollo y, lo que es más importante, está escuchando en el puerto 4242 (el puerto predeterminado).

Ahora estamos listos para iniciar el cliente de GDB.

En Linux, abra otra terminal, ingrese esto:

brazo-ninguno-eabi-gdb -tui

Eso es lo mismo que ejecutar gdb estrictamente en la línea de comandos, sin embargo, en su lugar, produce una terminal basada en texto (supongo que usa curses).

Tenemos el cliente GDB y el servidor GDB en ejecución. Sin embargo, el cliente no está conectado al servidor. Por el momento no sabe nada sobre nuestro Nucleo (o placa de su elección). Tenemos que contarlo. En la terminal, su mensaje debería ser ahora "(gdb)". Ingresar:

ayudar a apuntar

Te dará una lista. Tenga en cuenta que el que queremos es el objetivo extendido-remoto: use una computadora remota a través de una línea serie.

Pero también tenemos que darle la ubicación. Entonces, en el indicador (gdb), ingrese:

(gdb) destino localhost remoto extendido: 4242

Debería obtener una respuesta similar a esta:

(gdb) destino localhost remoto extendido: 4242

Depuración remota usando localhost: 4242 0x080028e4 en ?? ()

Mientras tanto, en la terminal que ejecuta st-util gdbserver, obtuvimos esto:

2018-10-20T18: 42: 30 INFO gdb-server.c: Se encontraron 6 registros de puntos de interrupción de hw

2018-10-20T18: 42: 30 INFO gdb-server.c: GDB conectado.

Paso 12: Repitamos, con Windows y flasheamos nuestro programa

Repitamos, con Windows y Flash nuestro programa
Repitamos, con Windows y Flash nuestro programa
Repitamos, con Windows y Flash nuestro programa
Repitamos, con Windows y Flash nuestro programa
Repitamos, con Windows y Flash nuestro programa
Repitamos, con Windows y Flash nuestro programa

Los pasos para ejecutar st-util gdbserver y el cliente arm-none-eabi-gdb son esencialmente los mismos que hicimos durante el paso anterior. Abres dos terminales (cygwin, DOS cmd o Windows Powershell), buscas la ubicación del st-util y lo ejecutas. En la otra terminal, ejecute el cliente arm-none-eabi-gdb. La única diferencia es que el modo -tui (vista de texto basada en terminal) probablemente no sea compatible.

Si lo anterior funcionó en Windows, probablemente tendrá que detenerse (solo el cliente). En este punto, de alguna manera necesitará ejecutar el cliente GDB donde está su archivo de compilación ("core.out"), o agregar la ruta completa a ese archivo como un argumento para el cliente GDB.

Simplifiqué mi vida usando cygwin y creando enlaces desde mi directorio local $ HOME // bin al lugar donde residen ambas herramientas.

Ok, lo hemos compilado y vinculado como antes, y tenemos el archivo main.elf listo para ser flasheado.

Tenemos st-util ejecutándose en una ventana. Reiniciamos el cliente de GDB, esta vez lo hacemos:

arm-none-eabi-gdb main.elf

Dejamos que se inicie, esperamos el indicador (gdb), hacemos nuestro mismo comando de conexión al servidor GDB (st-util) y estamos listos para actualizar el ejecutable. Es muy anti-climático:

(gdb) cargar

Al ejecutarse con terminales cygwin, hay un problema conocido con los comandos de la consola en algún momento que no se emiten. Entonces, en nuestro caso, la ventana que ejecuta el servidor estaba completamente en silencio. El que ejecuta el cliente, donde ejecutamos la carga, genera esto:

Sección de carga.texto, tamaño 0x1c lma 0x8000000 Dirección de inicio 0x8000000, tamaño de carga 28 Velocidad de transferencia: 1 KB / seg, 28 bytes / escritura.

Paso 13: flasheo con Linux - Más recompensa: D

Parpadeo con Linux - Más recompensa: D
Parpadeo con Linux - Más recompensa: D

Paso 14: Profundicemos un poco más

Si llegaste hasta aquí, excelente. Vamonos.

¿Por qué no mirar dentro del archivo main.elf, el ejecutable? Ejecute lo siguiente:

arm-none-eabi-objdump -d main.elf

Debería ver una salida similar a esta:

main.elf: formato de archivo elf32-littlearm

Desmontaje de la sección.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [pc, n.º 8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, # 8]; (8000018) 800000e: 2000 movs r0, # 0

08000010:

8000010: 3001 agrega r0, # 1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

¿Qué pequeñas pepitas podemos obtener de la salida anterior?

Si recuerda cuando discutimos y creamos el archivo linker.script.ld, dijimos que estos dispositivos ARM tienen RAM a partir de 0x20000000, y que la memoria FLASH comienza a 0x08000000.

Así, podemos ver que efectivamente el programa es tal que todo reside en la memoria FLASH.

Luego, arriba, pero un paso posterior, cuando estábamos discutiendo la parte "Hola mundo", había una declaración en la que cargamos un valor literal constante e inmediato ("0xDEADBEEF") en un registro central de MCU ("R7").

La declaración fue:

LDR R7, = 0xDEADBEEF

En nuestro código, ese es el único lugar donde incluso mencionamos DEADBEEF. En ningún otro lugar. Y, sin embargo, si observa las instrucciones anteriores desmontadas / reconstruidas, etc., hay más cosas relacionadas con DEADBEEF de lo que pensamos.

Entonces, el compilador / enlazador de alguna manera decidió mostrar permanentemente el valor de DEADBEEF en una dirección FLASH, en la ubicación 0x8000018. Y luego, el compilador cambió nuestra instrucción LDR anterior para que sea:

LDR R7, [PC, n.º 8]

Incluso generó un comentario para nosotros. Que agradable. Y nos dice que tomemos el valor actual del contador del programa (el registro de la PC), agreguemos 0x8 a ese valor, y ahí es donde se ha quemado DEADBEEF, y obtengamos ese valor y lo rellenemos en R7.

Eso también significa que el contador de programa (PC) apuntaba a la dirección 0x8000010, que es el inicio de main_loop, y que el valor DEADBEEF se encuentra en dos direcciones después del final de main_loop.

Paso 15: Finalmente, una breve mirada al programa en ejecución

Incluso si sale de GDB, simplemente vuelva a ingresar el comando. Ni siquiera tiene que darle ningún archivo; ya no parpadeamos, solo lo ejecutamos.

Una vez que haya vuelto a conectar el cliente GDB al servidor GDB, en el símbolo del sistema (gdb):

(gdb) registros de información

Debería ver algo como esto:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x20014000 lr 0xffffffffr02

Pero luego, en el indicador (gdb), ingrese:

(gdb) continuar

Y presiona CTRL-C muy rápidamente. Eso debería detener el programa. Vuelva a introducir el comando "registros de información".

Esta vez, se ve diferente:

(gdb) registros de información

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r122 0x0ps 0x200ff 0x200ff00 0x200ff 16777216

¿Qué sucedió? Exactamente lo que queríamos. DEADBEEF se cargó en R7, y R0 se ha incrementado (extremadamente rápido). Si repite, verá R0 nuevamente con otro valor.

Paso 16: Queríamos crear una matriz de solo lectura en Flash

Una forma de crear el equivalente de una matriz utilizando ensamblado y directivas es la siguiente:

.type myarray,% object // el nombre o etiqueta 'myarray' se define como un tipo de objeto.

myarray: // este es el comienzo de la declaración de 'myarray' // (en qué consistirá)..word 0x11111111 // el primer miembro o valor contenido en 'myarray'..word 0x22222222 // el segundo valor (direcciones contiguas)..word 0x33333333 // y así sucesivamente..size myarray,.-myarray // el compilador / ensamblador ahora sabe dónde está el final o // límite de 'myarray'.

Ahora que lo hemos configurado en la memoria FLASH, podemos usarlo en el programa. A continuación se muestra una porción:

LDR R1, myarray // esto carga los datos contenidos en la primera ubicación de 'myarray'. ' // esto no es lo que queremos.

LDR R1, = myarray // esto carga el valor de ubicación en sí (la primera dirección), // no los datos.. // esto ES lo que queremos.

MOV R2, # 0 // R2 llevará un conteo para asegurarse de que no nos vayamos

// fin de la matriz. LDR R3, = myarrsize // R3 será el equivalente de 'myarrsize'.

// R0 mantendrá nuestros datos

bucle principal:

LDR R0, [R1] // Carga los datos apuntados por R1 ('myarray') en R0. CMP R2, R3 // ¿Estamos en el límite de la matriz? BEQ main_loop // Si lo estamos, hemos terminado, así que lo haremos para siempre.

ADD R2, # 1 // De lo contrario, podemos seguir iterando a través de la matriz.

ADD R1, # 4 // Agregue 4 para registrar R1, para que apunte correctamente al siguiente

// Dirección..

B main_loop // Bucle hacia atrás.

El video pasa por todo esto y tiene un error. Es bueno; muestra que es un código de ejecución y depuración importante. Muestra un caso clásico de caminar al final de una matriz.

Recomendado: