Semihosting Con OpenOCD
Si has tenido la oportunidad de programar en C para la computadora, entonces de seguro conocerás la función printf
. Esta función no es ninguna instrucción de C pero si es parte de la libreria estandar de C.
Sin entrar en mucho detalles la función printf
nos permite por lo general mandar información por pantalla. En la computadora típicamente es el monitor.
Cualquier compilador decente de C para cualquier plataforma, trae esta librería estándar incluida. El compilador GNU ARM no es la excepcion y podremos, en nuestro programa utilizar la función printf
. ¿Pero como?, si nuestro micro no tiene una pantalla!!.
Bueno nuestro micro no, pero la computadora que usamos para programar y debuggear si. Podemos usar el debugger ( en el caso de la tarjeta Nucleo-f072rb es el ST-Link ) para mandar la informacion de la función printf
de nuestro programa a la pantalla de OpenOCD.
Crearemos un nuevo proyecto con CMSIS incluido, como en el post Primer Programa con CMSIS. Llamaremos a ese proyecto test_semihosting
, y en el archivo main.c
escribimos lo siguiente
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Observa bien el codigo que acabas de escribir y nota que referenciamos la función extern void initialise_monitor_handles(void)
esta funcion es la que habilitará al debugger para que despliegue la información por pantalla.
Es necesario mandar llamar esta función en tu programa antes de usar la función printf
. tal como se aprecia en el codigo de ejemplo.
Aparte de lo anterior necesitaremos compilar el programa con un par de opciones extra. En las opciones del linker debemos colocar --specs=rdimon.specs -lc -lrdimon
. En el archivo makefile escribe en LCDFLAGS
1
|
|
Compila y conectate a la tarjeta con OpenOCD. Al momento de usar GDB debemos agregar mon enable semihosting
a la lista de opciones que normalmente usamos cuando cargamos un programa. Aqui la lista de los comandos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Coloca un breakpoint en la linea printf("fin del bucle\n\n\r");
y corre el programa. Podrás notar en la pantalla de GDB que nada aparece, pero si revisas la terminal en la que tienes corriendo OpenOCD podras ver la informacion enviada por printf
.
1 2 3 4 5 6 7 8 9 10 11 |
|
Mola bastante verdad!!!, Pero antes de que te alegres deberías observar el tamaño de tu programa. Cuando usaste load
GDB te dio esta información.
1
|
|
33K de codigo!!!!. Oh si!. Usar la librería estándar agrega bastante código extra a tu programa y siendo honestos la libreria estandar de C que viene con GNU ARM no es la version completa. Se usa una version reducida, especial para embedded llamada newlib. Que, ¿creias que era gratis?.
Usando newlib-nano
Se puede usar una versión reducida de la aún reducida libreria estándar que acompaña a GNU ARM la version newlib-nano, solo necesitaras pasar al compilador las siguientes opciones -Os -flto -ffunction-sections -fdata-sections -fno-builtin
y en el linker las opciones --specs=nano.specs -lc -lnosys
.
Asi que en tu makefile en GCFLAGS quedaria asi
1
|
|
Y en LDFLAGS quedaría de este modo
1
|
|
Vuelve a repetir el proceso anterior de compilar, conectar OpenOCD y cargar con GDB tu programa. Fijate cuando usas load
la cantidad de codigo que en esta ocasion se carga a tu micro.
1
|
|
Wow!. Se redujo a tan solo 5K, una cantidad mas considerable. Pero existe un precio como la imposibilidad de manejar numeros flotantes en la funcion printf
Uso de Stack y Heap
Bueno no solo memoria de programa se consume por la funcion printf. Tambien se consume memoria RAM, stack y heap para ser mas especificos. Abre el archivo STM32F072RB_FLASH.ld con tu editor de texto y fijate en las líneas 37 y 38
1 2 |
|
En este archivo se le da al stack 2k de memoria y al heap 1k. El uso de stack es muy común pues aquí es donde se almacenan las variables locales, pero a menos que se maneje memoria dinámica el valor de heap sera 0.
En este caso el archivo linker de ejemplo que usamos por default ya trae estos valores pero cuando no los tenga y uses la librería estándar ya sabes que deberás darle un valor adecuado ( como entre 1k y 2k esta bien )
Conclusion
El uso de la función printf
es muy interesante, en especial en la etapa de desarrollo de tu proyectos, se vuelve tentadora la idea de usarla para depurar tu programa y poblar el software con cientos de printf
. Pero como ves su uso no es gratuito y solo será útil mientras tengas un debugger conectado a tu micro, una vez que lo retires no servira de nada.
Por cierto la librería estándar no solo es la función printf, hay mucho más. Por que no vas y se lo preguntas a tu buscador favorito.