Fundamentos de programaci´ on de Sistemas Embebidos Desarrollo de aplicaciones para la CIAA
Mg. Ing. E. Sergio Burgos
Universidad Nacional de Entre R´ıos Facultad de Ingenier´ıa
Especializaci´ on en Sistemas Embebidos
01/09/2018
Agenda
1 Entorno de desarrollo
C´omo desarrollamos aplicaciones
2 El hardware de la CIAA Caracter´ısticas de la CIAA
3 Desarrollo de software
Aplicaciones para sistemas embebidos
4 Un proyecto de software Estructura
Linker script
Rutina de inicializaci´on
5 Depuraci´on
Simulaci´on y depuraci´on jtag
OpenOCD
C´omo construimos aplicaciones?
El proceso de construir una nueva aplicaci´on suele ser simple:
En un PC las herramientas suelen estar pre configuradas para desarrollar aplicaciones de escritorio.
¿Pero en un sistema embebido?
Conocimiento del sistema embebido
El primer paso para desarrollar aplicaciones para un sistema embebido es tener conocimiento sobre su estructura de hardware. En nuestro caso, para la EDU-CIAA NXP (lpc4337):
N´ucleo ARM Cortex-M4 (y ARM Cortex- M0)
1 MB de Flash 136 KB de RAM 16 KB de EEPROM
Programaci´on a trav´es de JTAG USB OTG
RTC
FT2232 (JTAG y UART2) 3 Leds + 1 RGB
4 Teclas Clock 12 Mhz
http://www.proyecto-ciaa.com.ar/devwiki/doku.php?id=desarrollo:edu-ciaa:edu-ciaa-nxp
Software
En lo que a desarrollo de software respecta, las aplicaciones para sistemas embebidos requieren de utilizar cross compiling.
El cross compiling (o compilaci´on cruzada) es el proceso por el cual se construyen aplicaciones para una arquitectura de software o hardware desde una arquitectura diferente.
Esta es una caracter´ıstica particular y no todos los compiladores la soportan. En el caso particular de GCC, permite generar aplicaciones binarias para diversos n´ucleos ARM (entre otros Cortex M0, M3, M4, M7, A7, A12).
Si bien muchas opciones b´asicas de compilaci´on son v´alidas para todas las arquitecturas (-O2, -O0, -g, -c, etc.), aparecen opciones espec´ıficas para cada arquitectura.a.
GCC puede ser compilado desde su c´odigo fuente como un cross compilador, estableciendo las arquitecturas host y target, pero suele ser conveniente utilizar versiones empaquetadas para cada arquitectura.
ahttps://gcc.gnu.org/onlinedocs/gcc-7.3.0/gcc/ARM-Options.html#ARM-Options
La librer´ıa est´andard de C
El lenguaje C tiene un l´exico constituido por 32 palabras claves, que a partir de su sintaxis conforman el lenguaje.
Consideremos un programa simple:
# i n c l u d e < s t d i o . h >
int m a i n ( int argc , c h a r * a r g v []) {
p r i n t f ( " H o l a m u n d o \ n " ):
r e t u r n 0;
}
¿Qu´e palabras reservadas identifica?
La librer´ıa est´andard de C
Existen diferentes librer´ıas que pueden proveer las funcionalidades de la librer´ıas est´andar del len- guaje C. Entre ellas:
GNU libc : Versi´on incluida en GCC portada para variedad de sistemas.
dietlibc : Dise˜nada para ser una librer´ıa de reducido tama˜no para sistemas embebidos utili- zando enlazado est´atico.
µClibc: Dise˜nada para sistemas embebidos basados en linux utilizando enlazado din´amico.
newlib: mantenida por Red Hat, es una librer´ıa de enlazado est´atico f´acilmente adaptable a sistemas embebidos.
Nota: el compilador debe soportar la librer´ıa est´andar utilizada y, en general, la librer´ıa debe ser compilada durante el proceso de construcci´on del compilador.
Estructura de un proyecto
La estructura de un proyecto de software para la EDU-CIAA NXP para el desarrollo de una aplicaci´on baremetal requiere de un conjunto de archivos para realizar tareas espec´ıficas:
El c´odigo de la aplicaci´on: depender´a del problema que se desea abordar. Es una implementa- ci´on particular.
lpcOpen: drivers provistos por el fabricante para el control de los diferentes perif´ericos.
linker scripts: establecen el mapa de alojamiento de las diferentes secciones de la aplicaci´on en la memoria del microcontrolador.
startup.c: archivo de inicializaci´on del microcontrolador.
syscalls.c: rutinas de adaptaci´on de la librer´ıa est´andar de C a una plataforma de hardware.
Linker script
Por comodidad suelen utilizarse varios archivos como linker scripts. En nuestro caso, uno es utilizado para establecer los nombres de los segmentos y sus direcciones (mem.ld).
M E M O R Y {
f l a s h ( rx ) : O R I G I N = 0 x 1 a 0 0 0 0 0 0 , L E N G T H = 0 x 8 0 0 0 0 /* 5 1 2 K b y t e s */
s t a c k ( rw ) : O R I G I N = 0 x 1 0 0 0 0 0 0 0 , L E N G T H = 0 x 8 0 0 0 /* 32 K b y t e s */
}
_ _ t o p _ s t a c k = 0 x 1 0 0 0 0 0 0 0 + 0 x 8 0 0 0 ;
Linker script
En un segundo archivo se establece la correlaci´on entre segmentos y su ´area de alojamiento (areas.ld algunas l´ıneas han sido omitida por razones de espacio).
E N T R Y ( R e s e t I S R )
S E C T I O N S {
. t e x t : A L I G N (4) {
F I L L (0 xff )
P R O V I D E ( s t e x t = .);
_ _ v e c t o r s _ s t a r t _ _ = A B S O L U T E (.) ; K E E P ( * ( . i s r _ v e c t o r ))
. = A L I G N (4) ;
_ _ s e c t i o n _ t a b l e _ s t a r t _ = .;
_ _ d a t a _ s e c t i o n _ t a b l e _ = .;
L O N G ( L O A D A D D R (. d a t a ));
L O N G ( A D D R (. d a t a ));
L O N G ( S I Z E O F (. d a t a ));
_ _ d a t a _ s e c t i o n _ t a b l e _ e n d _ = .;
_ _ b s s _ s e c t i o n _ t a b l e _ = .;
L O N G ( A D D R (. bss ));
L O N G ( S I Z E O F (. bss ));
_ _ b s s _ s e c t i o n _ t a b l e _ e n d _ = .;
_ _ s e c t i o n _ t a b l e _ e n d = . ;
*(. a f t e r _ v e c t o r s *) } > f l a s h
. t e x t : A L I G N (4) {
*(. t e x t *)
*(. r o d a t a . r o d a t a .*)
*(. c o n s t d a t a . c o n s t d a t a .*) . = A L I G N ( 4 ) ;
P R O V I D E ( e t e x t = .);
P R O V I D E ( s t a r t F l a s h F s = .);
*(. f l a s h F s *)
P R O V I D E ( e n d F l a s h F s = .);
} > f l a s h
. n o i n i t ( N O L O A D ): A L I G N (4) {
_ n o i n i t = .;
*(. n o i n i t *) _ e n d _ n o i n i t = .;
_ v S t a c k B o t t o m = .;
} > s t a c k
_ v S t a c k T o p = _ _ t o p _ s t a c k ; P R O V I D E ( _ s S t a c k = _ v S t a c k T o p );
P R O V I D E ( _ e S t a c k = _ v S t a c k B o t t o m );
}
Archivo de inicializaci´on (startUp.c)
_ _ a t t r i b u t e _ _ (( used , s e c t i o n ( " . i s r _ v e c t o r " ))) v o i d (* c o n s t i s r V e c t o r [ ] ) ( v o i d ) = {
& _ v S t a c k T o p , // T h e i n i t i a l s t a c k p o i n t e r
R e s e t I S R , // T h e r e s e t h a n d l e r
N M I _ H a n d l e r , // T h e N M I h a n d l e r H a r d F a u l t _ H a n d l e r , // T h e h a r d f a u l t h a n d l e r M e m M a n a g e _ H a n d l e r , // T h e M P U f a u l t h a n d l e r B u s F a u l t _ H a n d l e r , // T h e b u s f a u l t h a n d l e r U s a g e F a u l t _ H a n d l e r , // T h e u s a g e f a u l t h a n d l e r _ _ v a l i d _ u s e r _ c o d e _ c h e c k s u m , // L P C M C U C h e c k s u m
0 , // R e s e r v e d
0 , // R e s e r v e d
0 , // R e s e r v e d
S V C _ H a n d l e r , // S V C a l l h a n d l e r D e b u g M o n _ H a n d l e r , // D e b u g m o n i t o r h a n d l e r
0 , // R e s e r v e d
P e n d S V _ H a n d l e r , // T h e P e n d S V h a n d l e r S y s T i c k _ H a n d l e r , // T h e S y s T i c k h a n d l e r /* - - - f i n c o r t e x M4 - - - */
D A C _ I R Q H a n d l e r , // 16
M 0 C O R E _ I R Q H a n d l e r , // 17
D M A _ I R Q H a n d l e r , // 18
0 , // 19
F L A S H _ E E P R O M _ I R Q H a n d l e r , // 20 /* c o n t i n ´u a . . . */
V´ease: DUI0553A Cortex - M4 Devices Generic User Guide
Construcci´on: Compilaci´on
El proceso de construcci´on de la aplicaci´on se llevar´a adelante compilando y posteriormente en- lazando la aplicaci´on. A modo informativo, las opciones de compilaci´on utilizadas para construir aplicaciones para Cortex-M4 son:
C F L A G S = - W a l l - fdata - s e c t i o n s - f f u n c t i o n - s e c t i o n s \
- m c p u = cortex - m4 - m t h u m b - m f p u = fpv4 - sp - d16 - mfloat - abi = s o f t f p \ - D C O R E _ M 4 - D c h i p _ l p c 4 3 x x - D N O _ B O A R D _ L I B - D _ _ U S E _ L P C O P E N \ - D _ _ L P C 4 3 X X _ _ - D _ _ C O D E _ R E D - D _ G N U _ S O U R C E - I$( BASEPATH )/ inc \ - I$( INCBASEDIR ) -I$( BASEPATH )/ cortex -m4/ inc \
- I$( BASEPATH )/ lpc / config_43xx -I$( BASEPATH )/ lpc / inc arm - none - eabi - gcc - c - w $( CFLAGS ) -Iinc main .c -o main .o
Nota: La opci´on -D permite definir una constante simb´olica desde la l´ınea de invocaci´on al compi- lador.
Compilaci´on: enlazado
El proceso de enlazado puede realizarse de dos maneras: invocando directamente al enlazador de GNU (arm-none-eabi-ld) o, invoc´andolo indirectamente a trav´es de GCC.
e x p o r t L D F L A G S = - s t a t i c - fno - b u i l t i n - m c p u = cortex - m4 \ - m t h u m b - m f p u = fpv4 - sp - d16 - mfloat - abi = s o f t f p \ - Wl , - gc - s e c t i o n s - X l i n k e r - Tld / l i b s . ld - Tld / mem . ld \ - Tld / a r e a s . ld - L$( OUTDIR )/ lib
arm - none - eabi - gcc $( LDFLAGS ) $( objLst ) -L$( OUTDIR ) \ - l l p c o p e n - lc - lm - o $( OUTDIR )/ firmware . elf
A partir de esto tendremos un archivo binario, ejecutable, ‘elf’. Seg´un las herramientas utilizadas puede ser necesario convertir a otros formatos, por ejemplo binario (imagen plana) o intel hex. Para esto es posible utilizar la herramienta objcopy:
arm - none - eabi - o b j c o p y - O b i n a r y $( OUTDIR )/ firmware . elf $( OUTDIR )/ firmware . bin arm - none - eabi - o b j c o p y - O i h e x $( OUTDIR )/ firmware . elf $( OUTDIR )/ firmware . hex
Simulaci´on y Depuraci´on
¿Cuando ejecutamos una aplicaci´on paso a paso? Estamos simulando la ejecuci´on de la aplicaci´on?
¿Es posible simular un sistema embebido?
Existe la posibilidad de simular un sistema embebido, pero requiere la construcci´on de la es- tructura del dispositivo de inter´es. Uno de los simuladores m´as utilizados para este fin es QEmu (https://www.qemu.org/).
Depuraci´on in circuit: la otra alternativa
Consiste en la ejecuci´on controlada de una aplicaci´on en un sistema embebido, tendiente a:
Lectura y escritura de variables y expresiones en tiempo de ejecuci´on.
Lectura y escritura de direcciones de memoria en el espacio de direccionamiento del dispositivo.
Asignaci´on de puntos interrupci´on en la ejecuci´on (break), ejecuci´on paso a paso (step) y ejecuci´on normal (resume).
Dependiendo del fabricante del dispositivo utilizado es la forma en la que se produce la interconexi´on electr´onica entre el software de depuraci´on y el dispositivo embebido.
M´as all´a de la tecnolog´ıa utilizada, el proceso de depuraci´on incluye la programaci´on del firmware en el microcontrolador y la ejecuci´on controlada del mismo desde una interfaz de desarrollo.
Depuraci´on: interfaz f´ısica
Una de las interfaces m´as utilizadas para la programaci´on y depuraci´on de sistemas embebidos es la interfaz conocida como JTAG.
Est´a interfaz est´a definida por el est´andar IEEE 1149.1 (2013), de donde se extraen los objetivos de la misma:
Testing the interconnections between integrated circuits once they have been assembled onto a printed circuit board or other substrate.
Testing the integrated circuit itself
Observing or modifying circuit activity during the component’s normal operation
Depuraci´on: interf´az f´ısica
Desde un punto de vista electr´onico, la interfaz jtag est´a constituida por un conjunto de se˜nales con direcciones de flujo de informaci´on pre fijada:
TCK [in]: Se˜nal de reloj utilizada para sincronizar las dem´as se˜nales.
TMS [in]: Selecci´on de modo de trabajo. A trav´es de una m´aquina de estado establece el modo de funcionamiento.
TDI [in]: Datos de entrada al sistema embebido. Los datos aqu´ı establecidos son analizados y cobran sentido en funci´on del modo de funcionamiento establecido.
TDO [out]: Datos de salida del sistema embebido, al igual que en el caso de TDI, los valores obtenidos depender´an del estado de funcionamiento seleccionado.
TRST [in]: Opcional, si se encuentra implementado, inicializa la m´aquina de estado que con- trola la interfaz.
En conclusi´on, puede observase, que es una interfase serie s´ıncrona.
M´aquina de estado JTAG
Extra´ıdo de: https://www.xjtag.com/about-jtag/jtag-a-technical-overview/
Jtag Software Interface
Si utilizamos una interfaz Jtag para depurar aplicaciones en un sistema embebido, es fundamental contar con un software que permita gestionar las operaciones a realizar.
Cuando se trabaja con interfaces de hardware comerciales, se dise˜nan para un dispositivo particular (microcontrolador, FPGA, etc.) y un software de desarrollo.
OpenOCD es una desarrollo realizado por Dominic Rath, como tesis de diplomatura y tiene como objetivo ser una interfase de software a diferentes tipos de adaptadores jtag para realizar tareas de programaci´on y depuraci´on de sistemas embebidos.
Originalmente tuvo por objetivo los n´ucleos ARM7 y ARM9 pero desde el 2005, ha incorporado otros dispositivos.
Sitio web: http://openocd.org
OpenOCD y las interfaces de hardware
OpenOCD ha sido dise˜nado para soportar diferentes tipos de adaptadores jtag. El tipo de adaptador a utilizar depender´a del tipo de sistema embebido y fundamentalmente de la tensi´on de trabajo de este.
Algunas de las familias de dispositivos soportados son:
Basados en FT2232 usbjtag jtagkey
Stellaris Eval Boards olimex-jtag stm32stick CIAA!
Basados en J-Link Segger J-Link Atmel SAM-ICE IAR J-Link
STLink y STLink2 Stellaris ICDI
Basados en Puerto paralelo Wiggler
DLC5
Amontec - JTAG Accelerator Wiggler2
arm-jtag
FT2232 en la EDU-CIAA
FT2232 en la EDU-CIAA
Utilizando OpenOCD
OpenOCD utiliza un archivo de configuraci´on donde se describen diferentes caracter´ısticas del sis- tema embebido. Entre ellas, la cadena de identificaci´on del dispositivo y la distribuci´on de memoria.
i n t e r f a c e f t d i
f t d i _ v i d _ p i d 0 x 0 4 0 3 0 x 6 0 1 0 f t d i _ c h a n n e l 0
f t d i _ l a y o u t _ i n i t 0 x 0 7 0 8 0 x F F F B a d a p t e r _ k h z 2 0 0 0
set _ C H I P N A M E l p c 4 3 3 7 set _ M 4 _ J T A G _ T A P I D 0 x 4 b a 0 0 4 7 7 set _ M 0 _ J T A G _ T A P I D 0 x 0 b a 0 1 4 7 7
j t a g n e w t a p $_CHIPNAME m4 -irlen 4 - ircapture 0x1 -irmask 0xf -expected -id $_M4_JTAG_TAPID j t a g n e w t a p $_CHIPNAME m0 -irlen 4 - ircapture 0x1 -irmask 0xf -expected -id $_M0_JTAG_TAPID t a r g e t c r e a t e $_CHIPNAME .m4 cortex_m -chain - position $_CHIPNAME .m4
t a r g e t c r e a t e $_CHIPNAME .m0 cortex_m -chain - position $_CHIPNAME .m0 set _ W O R K A R E A S I Z E 0 x 8 0 0 0
$_CHIPNAME .m4 configure -work -area - phys 0 x10000000 -work -area - size $_WORKAREASIZE set _ F L A S H N A M E $_CHIPNAME . flash
f l a s h b a n k $_FLASHNAME lpc2000 0 x1a000000 0 x80000 0 0 $_CHIPNAME .m4 \ l p c 4 3 0 0 9 6 0 0 0 c a l c _ c h e c k s u m
set _ F L A S H N A M E B $_CHIPNAME . flashb
f l a s h b a n k $_FLASHNAMEB lpc2000 0 x1b000000 0 x80000 0 0 $_CHIPNAME .m4 \ l p c 4 3 0 0 9 6 0 0 0 c a l c _ c h e c k s u m
r e s e t _ c o n f i g n o n e
c o r t e x _ m r e s e t _ c o n f i g v e c t r e s e t t a r g e t s $_CHIPNAME .m4
Extra´ıdo del proyecto CIAA, realizado por Juan Cecconi
Utilizando OpenOCD
Al invocar a OpenOCD debe indicarse el archivo de configuraci´on a utilizar y es posible ejecutar comandos que interact´uan directamente con el sistema embebido. A saber:
init: inicializa la interfaz jtag.
halt: detiene en procesador.
flash write image: escribe un firmware dado como argumento en la direcci´on de memoria indicada.
flash erase sector: borra los sectores de memoria indicados.
reset: reinicia el sistema embebido
shutdown: libera la interfaz jtag y el sistema embebido.
A partir de esto, es posible programar la CIAA utilizando un comando como:
o p e n o c d - f o p e n o c d / l p c 4 3 3 7 . cfg \ - c " i n i t " \
- c " h a l t 0 " \
- c " f l a s h w r i t e _ i m a g e e r a s e u n l o c k out / f i r m w a r e . bin 0 x 1 A 0 0 0 0 0 0 bin " \ - c " r e s e t run " - c " s h u t d o w n "
Utilizando OpenOCD
Otra alternativa de uso de OpenOCD es que se inicie como servicio. En este modo de funciona- miento, una vez iniciada la aplicaci´on queda a la espera de conexiones tcp a diferentes puertos:
Puerto 4444: comunicaci´on a trav´es de telnet. En este modo es posible interactuar con OpenOCD envi´andole directivas para controlar la ejecuci´on de la aplicaci´on en el sistema embebido o acceder a variables y direcciones de memoria.
Puerto 3333: la interacci´on en este caso se da a trav´es del depurador utilizado, en nuestro caso arm-none-eabi-gdb. Cuando se depuran aplicaciones desde Eclipse, este invoca a gdb y
´
este a OpenOCD.
Puerto 5555: interfaz de m´aquina a trav´es de un int´erprete TCL.
Y ahora...