Upload
others
View
9
Download
0
Embed Size (px)
Citation preview
Extension del Sistema Operativo FreeOSEK
para multiprocesadores asimetricos
Ing. Pablo O. Ridolfi
Directores del trabajo
Mg. Ing. Mariano Cerdeiro
Esp. Ing. Alejandro Furfaro
Jurado del trabajo
Ing. Juan Manuel Cruz
Dr. Ing. Pablo Martın Gomez
Esp. Ing. Pedro Ignacio Martos
Presentado para obtener el tıtulo de Especialista en Sistemas Embebidos.
Universidad de Buenos Aires,
Diciembre de 2015.
ii
Extension del Sistema Operativo FreeOSEK para multiprocesadores asimetricos por
Pablo O. Ridolfi se distribuye bajo una Licencia Creative Commons Atribucion-
CompartirIgual 4.0 Internacional.
iii
UNIVERSIDAD DE BUENOS AIRES
FACULTAD DE INGENIERIA
Pablo O. Ridolfi, Ingeniero en Electronica
Extension del Sistema Operativo FreeOSEK
para multiprocesadores asimetricos
Resumen
En este trabajo se presenta la implementacion de un Sistema Operativo de Tiempo Real (RTOS,por sus siglas en ingles) basado en el estandar OSEK-OS 2.2.3 que es extendido para soportarun sistema multiprocesador asimetrico (Asymmetric Multiprocessor System, AMP). El terminoasimetrico se refiere a que los microprocesadores que componen el sistema son de arquitecturasheterogeneas (pudiendo existir un subconjunto de procesadores identicos pero no la totalidadde los mismos) y cada uno de ellos ejecuta una instancia del RTOS especıficamente disenada yoptimizada. Se describe ademas el proceso de desarrollo llevado a cabo para comunicar las ins-tancias aprovechando caracterısticas de hardware para intercambiar informacion entre las tareasque se ejecutan en diferentes cores. Finalmente se expone una aplicacion de prueba funcional:el monitoreo mutuo entre CPUs (keep-alive) con un analisis de consumo medio de cada CPUen aplicaciones donde, por un lado, se requiere gran capacidad de computo para implementarprotocolos de comunicacion, y por otro lado se requiere un relevamiento continuo de las en-tradas/salidas. La plataforma utilizada para la evaluacion de dichos casos es la ComputadoraIndustrial Abierta Argentina (CIAA) cuyos modelos basados en el microcontrolador LPC4337(NXP Semiconductors) disponen de un multiprocesador asimetrico compuesto por un micro-procesador ARM Cortex-M4 (arquitectura ARMv7E-M) y un coprocesador ARM Cortex-M0(ARMv6-M).
iv
Agradecimientos
A Gessica, que lleva la carga de tener que aguantar mis despistes y distracciones, sacrificando
bastante del poco pero valiosısimo tiempo que pasamos juntos. Este trabajo es el resultado de
su inagotable paciencia e inmenso carino.
A mis padres, Marıa Isabel y Oscar, que desde el inicio supieron educarme para seguir
superandome dıa a dıa y esforzarme al maximo para alcanzar mis anhelos y objetivos.
A mis directores, Esp. Ing. Alejandro Furfaro y Mg. Ing. Mariano Cerdeiro, por confiar en
mı y acompanarme, dedicando mucho de su valioso tiempo para discutir ideas conmigo. Sin sus
ensenanzas este trabajo no hubiera sido posible.
Al Dr. Ing. Ariel Lutenberg, no solo por sus atinadas correcciones y sugerencias sino tambien
por su inagotable empuje para ver realizado el Proyecto de la Computadora Industrial Abierta
Argentina (CIAA), referencia indiscutida del presente trabajo.
Al Ing. Juan Cecconi e Ing. Gustavo Muro, pilares fundamentales del Proyecto CIAA, por el
aporte que dıa a dıa realizan brindando desinteresadamente su experiencia a los que trabajamos
en este Proyecto.
A mis colegas y companeros del Laboratorio de Procesamiento Digital de la UTN-FRBA, con
quienes comparto la voragine cotidiana en este apasionante campo de la ingenierıa electronica
A mis companeros de la primer cohorte de la Carrera de Especializacion en Sistemas Embebi-
dos, con quienes nos reunimos semanalmente en estos ultimos meses para compartir inquietudes
y recomendaciones.
v
Indice
1. Introduccion General 1
1.1. Contexto y Justificacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3. Alcances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4. Requerimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5. Planificacion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2. Casos de Estudio 7
2.1. El Sistema Operativo OSEK-OS . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1. Sistema Operativo Estatico . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2. Tareas en OSEK-OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.3. Esquema de trabajo con OSEK-OS . . . . . . . . . . . . . . . . . . . . . . 9
2.1.4. FreeOSEK y CIAA-Firmware . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2. El microcontrolador dual-core asimetrico LPC4337 . . . . . . . . . . . . . . . . . 13
2.2.1. Procesador maestro: Cortex-M4 . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2. Procesador esclavo: Cortex-M0 . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.3. Estructura de hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.4. Modelo de Comunicacion Interprocesador (IPC) . . . . . . . . . . . . . . 15
2.2.5. Pendable Service Call (PendSV) . . . . . . . . . . . . . . . . . . . . . . . 17
3. Implementacion 18
3.1. Implementacion de CIAA-Firmware para Cortex-M0 . . . . . . . . . . . . . . . . 18
3.1.1. LPCOpen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.2. Makefiles y linker scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.1.3. Device Drivers POSIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.1.4. FreeOSEK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.1.5. Asignador de memoria dinamica . . . . . . . . . . . . . . . . . . . . . . . 22
vi
3.2. Implementacion del modulo multicore . . . . . . . . . . . . . . . . . . . . . . . . 22
3.2.1. Estructura general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2.2. Estructura de mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2.3. Funciones de interfaz (API) . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3. Extension del Makefile principal de CIAA-Firmware . . . . . . . . . . . . . . . . 27
3.4. Extension del generador de OSEK-OS . . . . . . . . . . . . . . . . . . . . . . . . 27
3.5. Modificacion de la API de FreeOSEK . . . . . . . . . . . . . . . . . . . . . . . . 29
4. Pruebas funcionales 31
4.1. Aplicacion de monitoreo entre procesadores . . . . . . . . . . . . . . . . . . . . . 31
4.1.1. Tareas del procesador maestro Cortex-M4 . . . . . . . . . . . . . . . . . . 31
4.1.2. Tareas del procesador esclavo Cortex-M0 . . . . . . . . . . . . . . . . . . 33
4.2. Pruebas de consumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5. Resultados y conclusion 36
5.1. Analisis de resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2. Proximos pasos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Bibliografıa 41
A. Diagrama de Gantt 43
B. Rutina de cambio de contexto para Cortex-M0 44
C. Macros dependientes de la arquitectura de FreeOSEK 47
D. Archivo OIL de la aplicacion ((Monitor)) 50
1
Capıtulo 1
Introduccion General
La utilizacion de Sistemas Operativos de Tiempo Real (Real-Time Operating Systems, RTOS)
es cada vez mas frecuente en sistemas profundamente embebidos (deeply embedded systems[1]),
es decir, aquellos sistemas embebidos con capacidad de procesamiento limitada, orientados fuer-
temente a aplicaciones especıficas. El incremento en la cantidad de implementaciones que in-
cluyen un RTOS[2] se debe en gran medida a que los microcontroladores disponen de mas y
mejores recursos para soportar mayor variedad y complejidad del software que deberan ejecutar.
Hasta los primeros anos de la decada del 2000 era impensado disenar un sistema basico como
el control automatico del porton de una cochera con un MCU de 32-bits, por razones como la
disponibilidad en el mercado local y el costo. Hoy en dıa hablar de megabytes de memoria de
programa, cientos de kilobytes de memoria de datos, DMA y perifericos de alta velocidad como
CAN y Ethernet, no representan desafıo alguno para los microcontroladores que existen y cuyo
costo no supera los cinco o seis dolares.
Siguiendo con este avance tecnologico, a partir de 2011[3] comenzaron a aparecer los prime-
ros microcontroladores con mas de un microprocesador integrado. Tal es el caso de la familia
LPC4300 de NXP Semiconductors, la primera de la industria en componerse de un nucleo CPU
principal o master Cortex-M4 y uno o mas CPU esclavos Cortex-M0. Es interesante remarcar
que luego de cuatro anos en que se dispone de este tipo de sistemas aun no se han encontrado (o
al menos no es de publico conocimiento) implementaciones de un Sistemas Operativos de Tiem-
po Real como los utilizados hasta el momento, pero que ademas soporten microcontroladores
con mas de un CPU. Esto limita en primer instancia al usuario a implementar su propio RTOS
multicore o a disenar una aplicacion mixta con RTOS en el CPU principal y bare-metal en el
CPU secundario o viceversa, o bien con un RTOS por CPU para luego tener que implementar
algun mecanismo de comunicacion entre las tareas que se ejecutan en cada uno.
Este contexto constituyo una de las principales motivaciones para trabajar en un Sistema
2
Operativo de Tiempo Real que soporte microcontroladores multicore, y que ademas este RTOS
sea de codigo libre y abierto para que cualquier persona pueda utilizarlo, adaptarlo a otros
sistemas y mejorarlo, ası como sucede con cualquier proyecto open-source. Una vez tomada la
decision para trabajar en este proyecto surgieron dos cuestiones fundamentales que definirıan
la forma en que se implementarıa un RTOS multicore: ¿que plataforma de hardware utilizar? y
¿que RTOS adaptar?
Ambas cuestiones quedaron resueltas en el marco del proyecto Computadora Industrial Abier-
ta Argentina –CIAA–, una iniciativa de representantes tanto del sector academico (ACSE –
Asociacion Civil para la Investigacion, Promocion y Desarrollo de los Sistemas Electronicos
Embebidos) como del industrial (CADIEEL – Camara Argentina de Industrias Electronicas,
Electromecanicas y Luminotecnicas) de la Republica Argentina, cuyo objetivo principal es la
incorporacion de valor agregado y know-how a la industria nacional a partir del diseno de sis-
temas electronicos para aplicaciones industriales, definiendo esquemas de referencia tanto para
el hardware como para el software. En adelante se referira al hardware del Proyecto CIAA co-
mo ((CIAA-Hardware)), al firmware (software embebido que se ejecuta en el hardware) como
((CIAA-Firmware)) y al entorno de desarrollo integrado como ((CIAA-IDE)) o ((CIAA-Software)).
Tal y como se analizara en las secciones siguientes, el Proyecto CIAA contempla entre sus
modelos de computadora industrial la utilizacion de microcontroladores dual-core y un Sistema
Operativo de Tiempo Real basado en el estandar OSEK-VDX, ampliamente utilizado en la
industria automotriz europea. Es ası como se decidio utilizar el hardware de referencia de la
CIAA y extender su implementacion de OSEK para que soporte ambos procesadores disponibles
en el microcontrolador de dicho hardware.
3
1.1. Contexto y Justificacion
Los modelos mas utilizados de la Computadora Industrial Abierta Argentina, CIAA-NXP y
EDU-CIAA-NXP (Figura 1.1) estan basados en el microcontrolador LPC4337 de la firma NXP.
Este microcontrolador es considerado un sistema AMP1 ya que incluye ademas del Cortex-M4F
como procesador principal o ((master)), un Cortex-M0 como procesador secundario o ((slave))
funcionando tambien a 204MHz.
Figura 1.1: La Computadora Industrial Abierta Argentina: Modelos EDU-CIAA-NXP (al frente)
y CIAA-NXP (detras).
La idea de disponer de un sistema de multiprocesamiento asimetrico esta fuertemente rela-
cionada con las diferentes caracterısticas que cada procesador posee: el Cortex-M4 es un pro-
cesador de alta performance que permite implementar algoritmos extensos como stacks USB o
TCP/IP con bajo tiempo de ejecucion y ocupacion de memoria. El Cortex-M0, por su parte, es
un procesador de 32-bits sencillo cuya principal caracterıstica es su reducido consumo. Ambos
procesadores tienen acceso completo a los perifericos y memorias del sistema. En una aplicacion
1Asymmetric Multiprocessor.
4
donde es necesario disponer de ambas ventajas en simultaneo (bajo consumo y ejecucion de
algoritmos extensos y complejos) pueden dividirse las actividades a realizar entre dichos cores:
mientras el M4 funciona solamente al momento de ejecutar los algoritmos mencionados, el M0
se encarga del monitoreo general del sistema (entrada/salida y perifericos de baja velocidad)
y tambien de activar al M4 en caso de que sea necesario ejecutar un algoritmo complejo en el
menor tiempo posible. De esta forma sera posible reducir el consumo promedio del sistema.
Para que el usuario pueda disponer de esta versatilidad en el Firmware de la CIAA sera ne-
cesario implementar una extension del Sistema Operativo de Tiempo Real basado en el estandar
OSEK (FreeOSEK) que soporte un sistema multiprocesador asimetrico como el mencionado. Es
importante destacar que dicho estandar no contempla sistemas con mas de un procesador, con
lo cual la extension no podra encuadrarse en el mismo.
1.2. Objetivos
En el momento de definir que trabajo final a realizar consistirıa de una extension del RTOS de
CIAA-Firmware para que soporte el multiprocesador asimetrico de la CIAA-NXP, resulto opor-
tuno enumerar objetivos con el fin de sentar las bases para la planificacion de este trabajo
ası como se procede con cualquier proyecto de ingenierıa:
Implementar la primer version de CIAA-Firmware y su RTOS FreeOSEK con soporte para
multiprocesadores asimetricos.
Finalizar los entregables para el 30 de Noviembre de 2015, fecha considerada como deadline
para la validacion de la plataforma segun el criterio de aceptacion, para luego realizar la
defensa del trabajo alrededor del 15 de Diciembre de 2015.
1.3. Alcances
En complemento de los objetivos, los alcances permiten delimitar en forma precisa el trabajo
a realizar y lo que se espera puntualmente de esta implementacion. Los alcances de este trabajo
son:
Implementacion especıfica para el microcontrolador LPC4337, presente en la CIAA-NXP
y EDU-CIAA-NXP.
Instancias del RTOS independientes de FreeOSEK y stack POSIX en cada core del LPC4337.
5
Mecanismo basico de comunicacion entre instancias mediante el control de activacion de
Tareas y Eventos de FreeOSEK.
1.4. Requerimientos
El siguiente listado define los requerimientos del sistema:
1. Debera implementarse CIAA-Firmware para Cortex-M0 (LPC4337) con test de confor-
midad aceptados, que funcionara en forma independiente de la implementacion existente
para Cortex-M4.
2. La implementacion del Cortex-M4 dispondra de una nueva funcionalidad que habilite al
Cortex-M0 a ejecutar su instancia.
3. Ambas instancias de Firmware se compilaran en forma automatica.
4. La API ActivateTask de ambas implementaciones sera ampliada para permitir la acti-
vacion de tareas entre cores.
5. La API SetEvent de ambas implementaciones sera ampliada para permitir la activacion
de eventos entre cores.
6. La instancia en Cortex-M4 podra detener su ejecucion con el objetivo de disminuir el
consumo del sistema, dejando a la instancia de Cortex-M0 las tareas basicas de control y
monitoreo de I/O. Esta ultima realizara un requerimiento a la primera para actividades
de mayor complejidad, como el envıo de datos a traves de alguna de las interfaces de
comunicacion.
7. Se debera mantener absoluta compatibilidad entre los modelos CIAA-NXP y EDU-CIAA-
NXP.
6
1.5. Planificacion
Una vez definidos los objetivos, alcances y requerimientos de la implementacion se procedio a
planificar cada una de las etapas con el fin de optimizar al maximo el tiempo disponible para la
realizacion del trabajo. En el Apendice A puede apreciarse el diagrama de Gantt resultante de
la lista de tareas que se enumera a continuacion:
1. Implementacion del port de FreeOSEK a Cortex-M0.
a) Definicion de arquitectura.
b) Implementacion de las rutinas de cambio de contexto.
c) Adaptacion de los tests de conformidad.
2. Adaptacion de CIAA-Firmware a Cortex-M0.
a) Definicion de bibliotecas y tipos de datos estaticos.
b) Implementacion del driver Dio.
3. Implementacion del modulo ciaaMulticore, que provea una API interna de IPC (Inter-
Processor Communication) para el kernel de FreeOSEK.
a) Implementacion de comandos para activacion inter-procesador de Tareas.
b) Implementacion de comandos para activacion inter-procesador de Eventos.
4. Extension del programa generador de FreeOSEK con el objetivo de generar imagenes
separadas del RTOS para cada procesador.
5. Extension de la API ActivateTask.
6. Extension de la API SetEvent.
7. Implementacion de los tests funcionales.
8. Documentacion general de la extension (memoria del trabajo final).
7
Capıtulo 2
Casos de Estudio
En este capıtulo se presentan los diferentes componentes a ser analizados para la implemen-
tacion del RTOS multicore. Se describe el sistema operativo OSEK-OS y luego el hardware a
utilizar para la implementacion (hardware que fue disenado en el marco del Proyecto CIAA): el
microcontrolador dual-core asimetrico LPC4337. Tambien se describen las caracterısticas prin-
cipales de la arquitectura de sus dos procesadores: Cortex-M4 y Cortex-M0.
2.1. El Sistema Operativo OSEK-OS
OSEK (Offene Systeme und deren Schnittstellen fur die Elektronik in Kraftfahrzeugen, ((sistemas
abiertos y sus interfaces para la electronica en automoviles))) es un comite de estandarizacion
formado por empresas europeas dedicadas a la industria automotriz en 1994 e integrado junto
al estandar VDX en 2005 formando OSEK-VDX. Este estandar fue pensado para unificar la
arquitectura de software utilizada en las diferentes Unidades de Control Electronico (ECU, por
sus siglas en ingles) presentes en los automoviles. Toda la especificacion de OSEK-VDX se dis-
tribuye desde 2009 mediante una licencia de uso libre[4]. Dentro de los estandares emitidos por
dicho comite, los utilizados en este trabajo (y en CIAA-Firmware) son:
OSEK-OS: Especificacion de la estructura y API de un sistema operativo estatico basado
en prioridades.
OSEK Implementation Language (OIL): Especifica el lenguaje para la configuracion re-
querida por los demas estandares, entre ellos OSEK-OS.
2.1.1. Sistema Operativo Estatico
OSEK-OS es un sistema operativo estatico. Esto significa que los recursos requeridos por la
aplicacion del usuario y por el kernel no se crean dinamicamente en tiempo de ejecucion, sino
8
que se definen en un proceso previo a la compilacion denominado generacion. Concretamente un
sistema operativo que cumpla con el estandar OSEK-OS nunca utilizara funciones de manejo de
memoria dinamica como malloc y free[5].
Esta forma de definir los recursos en forma estatica se justifica en el hecho de que el sistema
embebido que utiliza OSEK-OS tiene un proposito especıfico: se sabe de antemano que proce-
sos sera necesario ejecutar1 y que recursos necesita cada uno de ellos; es decir, no se crearan
nuevos procesos en tiempo de ejecucion2. Si se requiere modificar la funcionalidad del sistema
sera necesario compilar el firmware (aplicacion y sistema operativo) en su totalidad. Una gran
ventaja de un sistema estatico es su determinismo, caracterıstica fuertemente relacionada con su
respuesta en tiempo real. Por otra parte, el sistema estatico nunca sufrira de falta de memoria
o fragmentacion de heap. Ademas, todas las tareas tienen asegurado su espacio de pila, por lo
que no existe la posibilidad de que no se pueda activar un hilo de ejecucion por falta de memo-
ria. Si los recursos de hardware no son suficientes, el desarrollador se encontrara con errores en
tiempo de compilacion, nunca durante la ejecucion. Por otra parte, las prioridades de las tareas
tambien son estaticas: No puede cambiarse la prioridad de una tarea de OSEK-OS en tiempo
de ejecucion.
2.1.2. Tareas en OSEK-OS
Las tareas de la aplicacion de usuario pueden tener cuatro estados posibles (Figura 2.1).
Todas las tareas comienzan en estado Suspended : Se encuentran esperando a ser activadas. La
activacion de una tarea puede realizarse mediante la API ActivateTask, o bien a traves de una
Alarma (contador de software al que se le puede definir una accion en la configuracion OIL, entre
ellas la Activacion de una tarea), o bien con el parametro AUTOSTART = TRUE, que se define
en la configuracion OIL de la tarea y le permite estar activada al momento de iniciar el Sistema
Operativo. Las tareas que estan activadas se encuentran en estado Ready, esperando a que el
scheduler las seleccione para ser ejecutadas en funcion de su prioridad. Cuando esto sucede la
tarea pasa a estado Running. Normalmente una sola tarea se encuentra en estado Running ya
que el estandar contempla solamente un CPU, pero en el caso de una implementacion multicore
debe considerarse que puede existir mas de una tarea en estado Running. En la Tabla 2.1 se
describen las transiciones posibles.
1En el ambito de los sistemas embebidos que utilizan RTOS, el termino ((tarea)), ((proceso)) e ((hilo)) pueden
considerarse sinonimos: se refieren a cada uno de los contextos de ejecucion definidos en la aplicacion.2No confundir ((creacion)) con ((activacion)). En OSEK-OS no pueden crearse nuevas tareas pero pueden estar
definidas en el sistema encontrandose suspendidas hasta que la aplicacion requiera que se ejecuten.
9
WAITING(esperando)
SUSPENDED(suspendida)
RUNNING(corriendo)
READY(lista)
wait
(esperar)
terminate(terminar)
activate
(activa
r)release(liberar)
start
(com
enzar)
preempt
(detener)
Figura 2.1: Estados posibles para las tareas de OSEK-OS
2.1.3. Esquema de trabajo con OSEK-OS
En la Figura 2.2 se presenta el proceso de desarrollo de una aplicacion basada en el estandar
OSEK-OS: Los archivos de codigo fuente del sistema operativo se agrupan en dos tipos: los
que deben ser generados y los que no deben ser generados (son archivos fuente fijos) sino que
se utilizan directamente en la compilacion. Para la generacion de los archivos necesarios el
usuario debe definir al menos un archivo de configuracion OIL3 donde se listaran las tareas y
recursos necesarios. Una vez que el programa generador, a partir de los archivos OIL del sistema,
genera los archivos de codigo fuente adicionales de OSEK-OS, estos se compilan junto con los
archivos fuente fijos del RTOS y los archivos fuente de la aplicacion del usuario. Luego se linkea
normalmente para generar el binario que se grabara en la memoria del microcontrolador.
2.1.4. FreeOSEK y CIAA-Firmware
CIAA-Firmware es el software embebido que ejecuta el CPU de la CIAA. Esta formado por
diferentes modulos de software que pueden clasificarse en cuatro grandes grupos (ver Figura
2.3):
RTOS basado en FreeOSEK, implementacion de codigo abierto del estandar OSEK-OS.
Software de manejadores o drivers de perifericos basados en el estandar POSIX[6].
Aplicacion del usuario; contiene los archivos de configuracion OIL y el codigo fuente donde
se definen las tareas que implementan la funcionalidad requerida.
3Puede consultarse el Apendice D donde se lista un archivo de configuracion OIL como ejemplo.
10
Transicion Previo Siguiente Descripcion
Activate SUSPENDED READY
Una nueva tarea se pone en estado
Ready por una llamada del sistema,
normalmente ActivateTask. OSEK-
OS asegura que la ejecucion de esta
tarea comenzara por su primer ins-
truccion o entry-point.
Start READY RUNNING
Una tarea en estado Ready es se-
leccionada por el scheduler para ser
ejecutada.
Wait RUNNING WAITING
La tarea entra en estado Waiting
(en espera) por una llamada al siste-
ma, normalmente WaitEvent. Para
retomar su ejecucion sera necesaria
la activacion de un evento.
Release WAITING READYAl menos uno de los eventos espera-
dos por la tarea ocurrio.
Preempt RUNNING READY
El scheduler decide ejecutar otra ta-
rea. La tarea actual se coloca en es-
tado Ready ; y eventualmente reto-
mara su ejecucion en el punto donde
fue detenida.
Terminate RUNNING SUSPENDED
La tarea ejecuta una llamada al sis-
tema que la ubica en estado Sus-
pended. Para ejecutarse otra vez de-
bera ser activada.
Tabla 2.1: Estados y transiciones de las tareas en OSEK-OS
Drivers del fabricante (third-party software); codigo fuente cuya licencia, si bien permite
su libre uso, no necesariamente es la misma que se utiliza en el Proyecto CIAA y por eso se
incluyen en un directorio aparte denominado externals. Consiste en drivers de perifericos
especıficos para cada microcontrolador que facilitan el diseno de los drivers POSIX de
CIAA-Firmware.
11
Archivo(s) de configuración
.oil
Programa de Usuario
.c .h
Generador
Compilador
Código de OSEK-OS
(fijo).c .h
Código de OSEK-OS
(generado).c .h
Enlazador (linker)
Ejecutable
Bibliotecas estáticas
(p. ej. CIAA-Firmware)
Linker scripts.ld
Código de OSEK-OS
(generable).c.php .h.php
Figura 2.2: Esquema de generacion y compilacion de firmware de OSEK-OS
Hardware
RTOS tipo OSEK Drivers tipo POSIX
Programa del usuario Aplicación
CIAA-Hardware
CIAA-Firmware
Drivers del Fabricante Drivers de 3ros
Figura 2.3: Estructura de CIAA-Firmware
Existen dos motivos principales por los cuales se eligio un RTOS tipo OSEK: Al ser un sis-
tema estatico su determinismo es mucho mayor que el de un sistema dinamico, haciendolo ideal
para aplicaciones destinadas a utilizarse en ambientes industriales. Por otro lado, al tratarse de
un estandar abierto, el usuario puede optar por otras implementaciones de OSEK-OS (abier-
tas o cerradas, incluso con certificacion4) que se ajusten a los requerimientos de su aplicacion,
4Ejemplos de implementaciones comerciales de OSEK-OS: RTA-OSEK, osCAN.
12
minimizando el costo de adaptar el codigo de la aplicacion ya que la API del RTOS esta es-
tandarizada. Otros Sistemas Operativos de Tiempo Real abiertos disponibles limitan al usuario
a depender de un unico proveedor o grupo de desarrolladores. Para profundizar conocimientos
sobres OSEK-OS y FreeOSEK, puede consultarse [7].
La eleccion del estandar POSIX para el acceso a perifericos se fundamenta en la unificacion
de la API de inicializacion y utilizacion del hardware5. El programador de aplicaciones para
microcontroladores suele encontrarse con una variedad importante de funciones para controlar
el hardware con el que trabaja. Existe un cierto numero de funciones para acceder a un periferico
como la UART, otro juego de rutinas para los GPIO, etcetera. Incluso, si en algun momento se
cambia de microcontrolador por el de otro fabricante, debera interiorizarse nuevamente con una
API diferente. Usando el estandar POSIX, el usuario solamente debera conocer el formato de
cinco funciones:
open para inicializar el periferico y obtener un identificador (file descriptor) que le per-
mitira referirse a dicho periferico con las funciones restantes.
read para operaciones de lectura del periferico, como por ejemplo leer una cadena de
caracteres de un puerto serie.
write para operaciones de escritura del periferico, como por ejemplo escribir todas las
salidas digitales de un puerto GPIO.
ioctl para realizar operaciones especıficas sobre el periferico, como por ejemplo habilitar
sus interrupciones, cambiar el baud-rate, etcetera.
close para cerrar el acceso al periferico, desactivarlo para disminuir el consumo y liberar
cualquier recurso utilizado por el driver.
De esta manera los drivers POSIX independizan al programador de la CIAA del hardware que
se utilice. Es importante destacar que gracias a esta API unificada es posible contemplar mas de
un fabricante de microcontroladores o incluso mas modelos de un mismo fabricante, asegurando
de esta manera la independencia de un unico proveedor o un microcontrolador determinado6.
5En [8] puede consultarse otra implementacion basada en POSIX para microcontroladores que tambien incluye
un RTOS dinamico.6De hecho existen modelos de la CIAA basados en sistemas de diversas companıas: CIAA-Freescale, CIAA-
Safety (Texas Instruments), CIAA-PIC (Microchip), CIAA-Intel y CIAA-ACC (Xilinx).
13
2.2. El microcontrolador dual-core asimetrico LPC4337
El LPC4337JBD144 de NXP Semiconductors, que se utiliza en la CIAA-NXP y EDU-CIAA-
NXP a la fecha, es un microcontrolador que dispone de un procesador ARM Cortex-M4F y un
coprocesador ARM Cortex-M0. Ambos procesadores pueden correr a una frecuencia maxima de
204MHz. El procesador Cortex-M4 incluye instrucciones SIMD y unidad de punto flotante. El
Cortex-M0, por su parte, tiene un set de instrucciones reducido pero compatible hacia arriba
con Cortex-M4. Esta orientado a reemplazar aplicaciones que normalmente emplean microcon-
troladores de 8/16-bits. En esta seccion se describiran las caracterısticas principales de ambos
procesadores y la estructura general del hardware del microcontrolador junto con los recursos
disponibles para implementar la Comunicacion Interprocesador (InterProcessor Communication,
IPC).
2.2.1. Procesador maestro: Cortex-M4
Cortex-M4 es un microprocesador disenado por ARM, perteneciente a la familia de procesa-
dores con arquitectura ARMv7E-M y lanzado al mercado en 2010. Es el sucesor de Cortex-M3,
el primer procesador de esta familia lanzado al mercado en 2006[9]. Entre sus principales carac-
terısticas podemos mencionar:
Arquitectura RISC de 32-bits con pipeline de tres etapas (fetch, decode y execute).
Buses de tipo Harvard: D-Bus, I-Bus y S-Bus; mapa de memoria de 32-bits unificado con
capacidad de direccionamiento de 4GB.
Arquitectura de BUS tipo AMBA (Advanced Microcontroller Bus Architecture).
Controlador de Interrupciones Vectorizado y Anidado (NVIC) integrado al microprocesa-
dor.
Caracterısticas de hardware de soporte para Sistemas Operativos: Niveles de Privilegio
(Privileged y User), unidad de proteccion de memoria opcional, timer de interrupciones
periodicas SysTick, doble stack-pointer para espacios de usuario y kernel.
ISA Thumb-2 (mixto de 16- y 32-bits) extendido con instrucciones SIMD, multiplicacion-
acumulacion y aritmetica saturada.
Unidad de Punto Flotante de 32-bits opcional (presente en el LPC4337).
Temporizador generador de interrupciones periodicas SysTick incluido.
En la Figura 2.4 puede apreciarse su diagrama en bloques.
14
Matriz de Buses
ICode(instrucciones)
DCode(datos)
System(periféricos/sistema)
Puerto de Acceso AHB
(AHB-AP)
Instrumentation Trace Macrocell
(ITM)
Data Watchpoint and Trace (DWT)
Unidad de Protección de
Memoria
Flash Patch Breakpoint
Controlador de Interrupciones
(NVIC)
Núcleo Cortex-M4F
Procesador Cortex-M4F
Puerto de Debug JTAG
o SWD
Controlador de Interrupciones Wake-up (WIC)
interrupciones
Interfaz JTAG/SWD
Embedded Trace Macrocell (ETM)
Interfaz de Puerto de Trace (TPIU)
Interfaz Trace
Interfaz PPB APB
Figura 2.4: Diagrama en bloques del procesador Cortex-M4[10]
2.2.2. Procesador esclavo: Cortex-M0
Por otro lado, el microprocesador Cortex-M0 esta basado en la arquitectura ARMv6-M, con
un set de instrucciones mas reducido respecto a ARMv7-M (modo Thumb completo mas algunas
instrucciones de modo Thumb-2). Una de sus principales caracterısticas es su bajo gate count :
tiene aproximadamente 12000 compuertas equivalentes en area a NAND de dos entradas[11].
Esto implica no solo un area reducida en el die del microcontrolador y menor costo, sino tambien
un menor consumo de energıa. Su bus es de tipo Von-Neumann con arquitectura AHB-Lite. Aun
ası, ARMv6-M incorpora caracterısticas de ARMv7-M, como ser el modelo de excepciones e
interrupciones (se dispone de NVIC al igual que en Cortex-M4), el modelo de mapa de memoria
unificado y algunas instrucciones Thumb-2. En lıneas mas generales se trata tambien de un
procesador RISC de 32-bits con pipeline de tres etapas. En la Figura 2.5 puede apreciarse su
diagrama en bloques.
2.2.3. Estructura de hardware
El procesador Cortex-M4 incluido en el LPC4337 dispone de tres buses tipo AHB-Lite:
System-Bus, I-CODE bus y D-CODE bus. I-CODE y D-CODE admiten accesos concurrentes
tanto de memoria de codigo como de datos, siempre que provengan de esclavos diferentes de la
matriz AHB descripta mas adelante.
Por su parte el coprocesador Cortex-M0 se incluye con el objetivo de reducir la carga de
software que debe ejecutar el procesador principal Cortex-M4. Este coprocesador tiene acceso y
15
Matriz de Buses
Bus AHB-Lite
Interfaz de Debug
Unidad de Breakpoint y Watchpoint
Controlador de Interrupciones
(NVIC)
Núcleo Cortex-M0
Procesador Cortex-M0
Puerto de Acceso
Debuf (DAP)
Controlador de Interrupciones Wake-up (WIC)
interrupciones
Interfaz JTAG/SWD
Figura 2.5: Diagrama en bloques del procesador Cortex-M0[12]
es capaz de recibir interrupciones de la mayorıa de los perifericos del sistema. Al mismo tiempo
el Cortex-M0, dada su simplicidad respecto al Cortex-M4, puede aprovecharse para reducir el
consumo medio del sistema cuando no es necesario ejecutar software mas complejo que puede
ser resuelto en menor tiempo por el Cortex-M4.
La conexion entre perifericos, procesadores y memorias esta implementada con una matriz
multicapa AHB. Esta arquitectura admite que diferentes maestros (masters) puedan comuni-
carse simultaneamente con diferentes esclavos (slaves). En la Figura 2.6 puede apreciarse un
diagrama en bloques del microcontrolador donde estan identificados los maestros y los esclavos
de la matriz AHB.
2.2.4. Modelo de Comunicacion Interprocesador (IPC)
En el microcontrolador LPC4337 ambos procesadores (el maestro Cortex-M4 y el esclavo
Cortex-M0) tienen acceso completo7 al mapa de memoria. Luego de un reset del sistema, o al
salir del modo de ahorro de energıa deep power-down, unicamente el procesador maestro comienza
la ejecucion de codigo, mientras que el procesador esclavo se mantiene en estado de reset hasta
que el software ejecutado por el maestro escriba un registro de control para configurar al esclavo,
indicando en que posicion de memoria se encuentra su vector de interrupciones y luego liberando
su senal de reset. Una vez que ambos procesadores se encuentran ejecutando sus respectivos
programas, es posible intercambiar informacion entre ellos mediante alguna estructura de datos
definida en una zona de memoria (normalmente RAM) a la que ambos CPU tengan acceso. En el
7Salvo que la Unidad de Proteccion de Memoria (MPU) del Cortex-M4 se haya configurado para limitarle el
acceso a alguna region. El Cortex-M0 no dispone de MPU, por lo tanto no existe forma de limitar su acceso al
mapa de memoria del sistema.
16
Figura 2.6: Diagrama en bloques del microcontrolador LPC433x[13]
caso particular del microcontrolador LPC4337 no existe un modelo predefinido para la estructura
de datos; se deja a criterio del usuario implementarla8. Luego cada procesador podra trabajar
por encuesta (polling) de esa zona de memoria para descubrir si el otro dejo algun mensaje, o
bien es posible utilizar las interrupciones cruzadas que cada procesador posee. En la Figura 2.7
se ilustra el esquema de interrupciones cruzadas entre ambos CPU: Existe una entrada en la
posicion IRQ#1 del vector de interrupciones del Cortex-M4 que corresponde a la solicitud de
interrupcion del Cortex-M0, y una entrada en la posicion IRQ#1 del vector de interrupciones del
Cortex-M0 que corresponde a la solicitud de interrupcion del Cortex-M4. En ambos procesadores
la solicitud de interrupcion se genera usando la instruccion SEV (Send EVent : Enviar Evento)
8El microcontrolador dual-core TMS320F2837xD de Texas Instruments dispone de un modelo definido en la
arquitectura para intercambiar mensajes entre procesadores. Puede consultarse la seccion 6.9 de la hoja de datos.
17
que genera un pulso de un ciclo de clock en la lınea TXEV (Transmit EVent : Transmitir Evento)
disponible en cada CPU. De esta manera es posible evitar la encuesta permanente de la region
de memoria destinada al intercambio de informacion: El procesador que desea enviar un dato al
otro se encarga de colocar dicho dato en la memoria compartida y generar la interrupcion; luego
el otro en su rutina de atencion de interrupcion puede acceder a la misma zona de memoria y
retirar el dato en cuestion.
Cortex-M4 Cortex-M0APP
CREGM4TXEVENT
CREGM0APPTXEVENT
TXEV
TXEV
IRQ#1
IRQ#1
Figura 2.7: Modelo de interrupciones entre procesadores del microcontrolador LPC4337[14].
2.2.5. Pendable Service Call (PendSV)
PendSV es una de las excepciones del sistema disponibles tanto en Cortex-M4 como en
Cortex-M0. Vale la pena dedicarle tiempo de estudio ya que es de suma importancia para
la implementacion de un Sistema Operativo para cualquiera de estos procesadores. Se trata
en principio de una Interrupcion por Software, ya que la unica forma de dispararla es que el
programa escriba un ‘1’ en el bit 28 (PENDSVSET) del registro ICSR (Interrupt Control and
Status Register) del controlador de interrupciones NVIC. La rutina que se encarga de realizar
el cambio de contexto de un Sistema Operativo debe llevarse a cabo en el handler de PendSV,
al que se le asignara la prioridad mas baja posible. De esta manera el sistema operativo puede
((programar)) el cambio de contexto ya sea desde una tarea o desde otra interrupcion (siempre
de mayor prioridad). De esta forma se asegura que no existen otras interrupciones pendientes de
ser atendidas al momento de realizar el cambio de contexto, y por lo tanto no podran ocurrir
latencias indeseadas en la atencion a interrupciones de hardware que pueden afectar la respuesta
en tiempo real del sistema[15].
18
Capıtulo 3
Implementacion
Una vez analizados los componentes de hardware y software que forman parte del contexto
que enmarca el presente trabajo, debio definirse una secuencia de tareas (vease seccion 1.5) que
al finalizar permita el cumplimiento de los requerimientos descriptos en la seccion 1.4 y con ello
los objetivos definidos en la seccion 1.2.
En este capıtulo se describira cada uno de los pasos que se fueron realizando y los hitos que
se fueron alcanzando segun la planificacion prevista. A lo largo del texto se incluiran enlaces
a los commits realizados al repositorio de CIAA-Firmware donde se podra apreciar el trabajo
realizado.
3.1. Implementacion de CIAA-Firmware para Cortex-M0
Al momento de comenzar con el desarrollo de este proyecto, el Firmware utilizado en la
CIAA unicamente era compatible con microcontroladores basados en Cortex-M4, por lo que fue
necesario implementar toda la capa o layer de compatibilidad con el procesador Cortex-M0. Esto
incluye la adicion de las bibliotecas de terceros que sean necesarias, la adaptacion de los drivers
POSIX y del kernel de FreeOSEK. Esto normalmente se conoce como porting del Firmware a
una arquitectura nueva no portada previamente.
3.1.1. LPCOpen
LPCOpen es una plataforma abierta desarrollada para los microcontroladores de NXP, entre
los cuales se encuentra el utilizado en la CIAA, LPC4337. Desde el punto de vista de CIAA-
Firmware, LPCOpen es una biblioteca de terceros que incluye los manejadores de dispositivo
(device drivers) de todos los perifericos incluidos en el microcontrolador y la biblioteca de ARM
denominada CMSIS (Cortex Microcontroller Software Interface Standard) que incluye funciones
19
basicas para el manejo del procesador, controlador de interrupciones (NVIC) y temporizador
SysTick. Hasta ahora, dentro de la estructura de CIAA-Firmware solamente se utilizaba la
version de LPCOpen para Cortex-M4. Entonces, el primer paso consistio en incluir LPCOpen
para Cortex-M0 (ver commit 408f8c1) dentro de la carpeta externals de CIAA-Firmware.
3.1.2. Makefiles y linker scripts
CIAA-Firmware utiliza una estructura basada en Makefiles para definir las reglas de compi-
lacion que generan los archivos objeto, las bibliotecas estaticas y el binario que se descarga en
el microcontrolador. Para que se compile CIAA-Firmware para Cortex-M0 se agregaron nuevos
Makefiles, indicando cuales son los flags que el compilador debe utilizar para generar codigo
de maquina compatible con esta arquitectura (ver commit 60378ec con detalle en los flags de
compilacion).
Por otro lado los linker scripts son archivos que se utilizan durante el proceso de enlace
o linkeo. Contienen informacion sobre la estructura de memoria del microcontrolador objetivo
(tambien denominado target), en que parte del mapa de memoria se ubican los diferentes tipos
de memorias, y que secciones del programa (dato, codigo, pila) deben ir en cada una. Ver commit
60378ec con detalle en los linker scripts. Particularmente el linker script de la instancia de CIAA-
Firmware que ejecutara el Cortex-M0 define el banco B de memoria Flash del microcontrolador
(512kB a partir de la posicion 0x1B000000) para alojar vector de interrupciones, programa,
datos constantes e inicializadores de variables; y el banco de RAM AHB perteneciente al bloque
ETB (16kB a partir de la posicion 0x2000C000 no utilizado en esta implementacion por el ETB
y el ETM1) para las pilas y variables globales.
3.1.3. Device Drivers POSIX
Para las aplicaciones de prueba que hacen uso de CIAA-Firmware multicore y que se des-
criben en la Seccion 4 se utilizo el driver Dio (Digital Inputs/Outputs) portado a Cortex-M0.
Dado que el periferico GPIO es igualmente visto por el Cortex-M0 y el Cortex-M4, este driver
no requirio ser reescrito, pero sı debe compilarse con los flags de Cortex-M0. Esto se realiza en
forma transparente al usuario gracias a los Makefiles definidos en la seccion anterior. El commit
c879471 corresponde a este agregado. Si bien este no fue el primer commit donde se incluyo el
driver Dio para Cortex-M0, en este caso se realizo una mejora significativa en el diseno de este
driver que a su vez fue replicada en el correspondiente driver Dio de Cortex-M4: se modularizo el
1Enhanced Trace Buffer y Enhanced Trace Module se encuentran por defecto desactivados en el LPC4337, por
lo que el bloque de RAM queda conectado a la matriz AHB.
20
manejo de GPIO del microcontrolador por parte del driver haciendo mas sencillo el agregado de
nuevos pines disponibles para el usuario y se optimizaron las funciones de lectura y escritura de
los pines.
3.1.4. FreeOSEK
El desarrollo del port de FreeOSEK para Cortex-M0 comenzo tomando como base el de
Cortex-M4, ya que ambos procesadores comparten un esquema similar de registros e interrup-
ciones. Las diferencias principales a resolver fueron las siguientes:
1. El vector de interrupciones es significativamente diferente al de Cortex-M4 en cuanto al
orden de las entradas correspondientes a los perifericos. Ademas algunas excepciones de
sistema no existen en Cortex-M0.
2. El timer de interrupciones periodicas SysTick no esta disponible en el Cortex-M0 del
LPC4337. Es necesario utilizar un timer del microcontrolador para generar las interrup-
ciones periodicas que requiere el kernel de OSEK. En el caso particular del LPC4337 se
dispone del Repetitive Interrupt Timer (RIT) cuyo esquema es practicamente identico al
del SysTick.
3. El set de instrucciones de Cortex-M0 es mucho mas limitado que el de Cortex-M4. La rutina
de cambio de contexto y algunas macros dependientes de la arquitectura se resuelven en
lenguaje Assembler, con lo cual debio adaptarse esta rutina reemplazando las instrucciones
que Cortex-M0 no soporta por una o mas instrucciones compatibles. Ademas, dado que
el Cortex-M4 del LPC4337 incluye Unidad de Punto Flotante (FPU), se removieron las
instrucciones que se encargaban del guardado y recuperacion del contexto particular de
esta unidad2.
El punto 1 se resolvio en el archivo Os Internal Arch Cfg.c.php3. En este archivo se define
el vector de interrupciones del Cortex-M0 que se encuentra en el LPC4337. Cada una de las
rutinas de atencion a interrupcion que el usuario configure en su archivo OIL seran incluidas en
el archivo generado a partir de este.
2Cortex-M4 implementa un mecanismo de lazy stacking que requiere un tratamiento especial al momento de
guardar y recuperar el contexto de la FPU. Puede consultarse la nota de aplicacion DAI0298A de ARM y la
rutina de cambio de contexto de FreeOSEK para Cortex-M4.3Los archivos de extension .c.php y .h.php son los archivos de codigo generado de FreeOSEK, es decir aquellos
archivos de codigo que pasan a traves del generador y cuyo contenido se define a partir de la configuracion OIL
del sistema. De aquı se deduce que el programa Generador de FreeOSEK esta escrito en lenguaje PHP.
21
El punto 2 puede observarse en la lınea 218 del mismo archivo donde se establece el handler4
del temporizador RIT. Dicho handler no podra ser modificado por la configuracion OIL del
sistema, a diferencia de los handlers restantes. La inicializacion del RIT se puede observar en el
archivo StartOs Arch SysTick.c donde ademas puede apreciarse la utilizacion de funciones de
LPCOpen para el manejo de este periferico.
Respecto al punto 3 se puede observar en el Apendice B la rutina de cambio de contexto
escrita con instrucciones Thumb compatibles con Cortex-M05. Ademas en el Apendice C se
lista una porcion del archivo Os Internal Arch.h donde se definen las macros dependientes
de la arquitectura requeridas por FreeOSEK: osekpause, CallTask, JmpTask y SaveContext,
entre otras (se mencionan las mas relevantes, puede consultarse el enlace al archivo para ver las
restantes).
Una vez resueltas estas diferencias se llego a una version de FreeOSEK totalmente funcional
para Cortex-M0. Se realizo una aplicacion de prueba en la cual se genero el RTOS y se com-
pilo junto al ejemplo blinking de CIAA-Firmware, en el cual simplemente se destella un LED con
un perıodo fijo de 500ms. Luego se programo el banco de memoria Flash destinado al Cortex-M0
del LPC4337 (Banco B de 512kB a partir de la posicion 0x1B000000) con el binario resultante
y se programo el banco de memoria Flash configurado para el Cortex-M4 (Banco A de 512kB
en la posicion 0x1A000000) con un programa bare-metal que solamente se encarga de activar
al procesador esclavo. Con este esquema tambien fueron ejecutados los Tests de Conformidad
descriptos en la seccion siguiente. Una vez concluidos (y verificado que todos resultan ejecutados
satisfactoriamente), se procedio a trabajar en el modulo multicore descripto en la seccion 3.2. Es
importante destacar que los archivos de codigo mencionados en esta seccion no fueron los unicos
que se desarrollaron, sino los que mas tiempo de desarrollo requirieron. La totalidad de archivos
de codigo fuente, tanto fijo como generado, de FreeOSEK para Cortex-M0 pueden consultarse
en las carpetas src/cortexM0 e inc/cortexM0 para los archivos constantes; gen/src/cortexM0
y gen/inc/cortexM0 para los archivos generados.
Adaptacion de los Tests de Conformidad
Los tests de conformidad de FreeOSEK[16] se llevan a cabo mediante un script en lengua-
je Perl y un listado de comandos para GDB que debieron ser modificados para soportar la
arquitectura Cortex-M0 (commit 6bd509d). Estos tests en algunos casos requieren simular una
interrupcion de hardware definiendo rutinas de atencion a interrupcion de dos perifericos del mi-
crocontrolador que luego son activadas por software mediante las funciones TriggerISR1 Arch
4Por handler se refiere a Rutina de Atencion a Interrupcion o ISR.5La rutina de cambio de contexto correspondiente a Cortex-M4 puede consultarse en este enlace.
22
y TriggerISR2 Arch. En el caso de Cortex-M4 y Cortex-M0 se aprovecha una funcion en lınea
definida por la biblioteca CMSIS denominada NVIC SetPendingIRQ, que permite disparar por
software cualquier interrupcion del sistema. Debio definirse que periferico utilizar para ISR1 e
ISR2 ya que Cortex-M4 y Cortex-M0 no poseen el mismo vector de interrupciones. Una vez
definidas, los tests de conformidad pudieron ejecutarse sin inconvenientes.
3.1.5. Asignador de memoria dinamica
A diferencia de Cortex-M4, Cortex-M0 no soporta accesos no alineados a memoria. Esto
significa que las direcciones de dichos accesos deberan ser multiplos de cuatro bytes (32-bits).
La implementacion de las funciones malloc y free de CIAA-Firmware no tenıan en cuenta esta
restriccion, por lo que fue necesario modificar dicha implementacion para que siempre realice ac-
cesos alineados a memoria siempre que se este compilando para Cortex-M0. El codigo agregado
que soluciona este inconveniente puede verse en el listado 3.1, o en el commit d75abf5. Con-
cretamente se redondea el puntero del proximo bloque libre o chunk de memoria a la direccion
multiplo de cuatro bytes mas proxima.
Listado 3.1: Correccion de la funcion utilizada por malloc
1 #if (cortexM0 == ARCH)
2 /* Cortex -M0 doesn ’t support unaligned memory access */
3 /* Align chunk to 32-bits address */
4 next_chunk_header =( ciaaPOSIX_chunk_header *)(((int)next_chunk_header +3) &~3);
5 #endif
Es importante mencionar que las funciones malloc y free no son utilizadas por FreeOSEK tal
y como lo indica el estandar con el fin de mantener estatico al RTOS, sino que son requeridas
por las rutinas de inicializacion de los drivers POSIX con el fin de mantener compatibilidad con
este estandar. En la seccion 5.2 se deja documentada la necesidad de modificar las mencionadas
rutinas de inicializacion para asegurar el determinismo tanto del RTOS como de los manejadores
de dispositivo.
3.2. Implementacion del modulo multicore
Una vez disponibles ambas instancias de FreeOSEK ejecutandose independientemente en
cada uno de los procesadores del LPC4337, debieron definirse los recursos a utilizar para co-
municar dichas instancias. Por un lado, tal como se describio en la seccion 2.2.4, se dispone de
interrupciones cruzadas entre ambos procesadores y el mapa de memoria totalmente visible por
ellos.
23
El primer paso consistio en definir una zona de memoria RAM no utilizada previamente por
CIAA-Firmware. Existe un bloque de 16kB en el bus AHB que no forma parte de los bloques de
memoria RAM ((local)), y por eso es de mayor tiempo de acceso. Se opto por dejar los bloques
locales de SRAM para el Cortex-M4 y el bloque de RAM AHB/ETB para el Cortex-M0, como
se definio en el linker script (seccion 3.1.2).
Luego se definio la estructura de una cola circular en dicha seccion de memoria. Para ello se
aprovecho la estructura ciaaLibs CircBufType (ver Listado 3.2) utilizada en otros modulos de
CIAA-Firmware. Para ver la API completa de manejo de bufers circulares se recomienda con-
sultar los archivos ciaaLibs CircBuf.c y ciaaLibs CircBuf.h. Ası queda definido el conjunto
de recursos utilizados por el modulo multicore para la comunicacion entre ambos procesadores
(Figura 3.1).
Listado 3.2: Estructura de bufer circular utilizada en CIAA-Firmware
1 /** \brief circular buffer type
2 ** if buffer is empty head and tail are the same , if the buffer is full
3 ** (tail +1) %size=head. A buffer of size 64 will can handle maximal 63 bytes.
4 **/
5 typedef struct {
6 size_t head; /** <= index of the head element of the buffer */
7 size_t tail; /** <= index of the position to write the next byte */
8 size_t size; /** <= size -1 of the buffer (>=8-1 and power of 2-1) */
9 uint8_t * buf; /** <= pointer to the buffer */
10 } ciaaLibs_CircBufType;
CPU MaestroCortex-M4
CPU EsclavoCortex-M0
ciaaLibsCircBufType@0x20008000
(RAM AHB 16kB)
IRQ1
IRQ1
TXEV
TXEV
Figura 3.1: Esquema de los recursos de hardware utilizados por el modulo multicore.
24
3.2.1. Estructura general
El codigo fuente modulo multicore fue pensado con una estructura independiente del hard-
ware en el que se utilizara. Este es un requisito que deben cumplir todos los modulos de CIAA-
Firmware, aunque en principio, debido al alcance de este trabajo, solo esta disponible para el
port de CIAA-Firmware correspondiente al LPC4337. En la seccion 5 se describiran las tareas
futuras para realizar mejoras que admitan nuevos perfiles de hardware con multiprocesadores.
Al mismo tiempo las funciones publicas definidas en este modulo seran unicamente utilizadas
por el RTOS. En versiones posteriores de la implementacion se permitira al usuario hacer uso
de la cola de mensajes compartida entre procesadores para enviar informacion personalizada.
3.2.2. Estructura de mensajes
La estructura de mensajes del modulo multicore puede observarse en el Listado 3.3. La misma
ha sido pensada tambien para su extension futura a arquitecturas con mas de dos procesadores
y con la posibilidad de identificar diferentes tareas. Puede observarse dentro de su contexto en
el archivo ciaaMulticore.h.
Listado 3.3: Estructura de mensaje utilizada por el modulo multicore
1 /** \brief multicore module message struct */
2 typedef struct {
3 struct {
4 uint32_t cpuid; /**< CPU core number */
5 uint32_t pid; /**< thread (Task) number or ID */
6 }id;
7 uint32_t data0; /**< first data field */
8 uint32_t data1; /**< second data field */
9 }ciaaMulticore_ipcMsg_t;
En la implementacion actual del modulo multicore los mensajes pueden corresponder a dos
((comandos)) definidos en ciaaMulticore.h:92 (Listado 3.4):
Mensaje para activacion de una tarea remota: En el campo data0 del mensaje se coloca
el codigo del comando y en el campo data1 el ID (8-bits) de la tarea remota que se desea
activar.
Mensaje para activacion de un evento remoto: En el campo data0 se realiza una operacion
OR entre el codigo del comando (que deja libre el byte menos significativo) y el ID (8-bits)
de la tarea remota a la cual activar el evento, cuyo identificador se envıa en el campo data1
(ya que se trata de un valor de 32-bits).
25
Listado 3.4: Comandos disponibles para el control de Tareas y Eventos remotos
1 /** \brief available inter -core commands */
2 typedef enum {
3 CIAA_MULTICORE_CMD_ACTIVATETASK = 0x100 ,
4 CIAA_MULTICORE_CMD_SETEVENT = 0x200
5 }ciaaMulticore_ipcCmd_t;
3.2.3. Funciones de interfaz (API)
En esta seccion se describiran las funciones publicas del modulo multicore, tambien cono-
cidas como Interfaz de Programa de Aplicacion (API). Es importante hacer notar nuevamente
que dado el alcance de este trabajo, la API del modulo multicore esta solamente disponible
para ser utilizada por FreeOSEK y no por el programa del usuario. Pueden encontrarse mas
detalles sobre la API en el archivo ciaaMulticore.c (funciones externas o publicas indepen-
dientes de la arquitectura), ciaaMulticore Arch.c (implementacion interna para Cortex-M4)
y ciaaMulticore Arch.c (implementacion interna para Cortex-M0).
Funciones externas
ciaaMulticore init inicializa los recursos necesarios por el modulo multicore. Actualmen-
te dicha inicializacion no se realiza a nivel publico sino que se llama a ciaaMulticore init Arch
para hacerla a nivel dependiente de la arquitectura.
ciaaMulticore sendMessage agrega el mensaje pasado como parametro a la cola de
mensajes y luego envıa una senal avisando al/los procesador/es restante/s (se utiliza
ciaaMulticore sendSignal Arch, dependiente de la arquitectura).
ciaaMulticore recvMessage retira el proximo mensaje disponible en la cola de mensajes
y lo devuelve a traves del parametro pasado por referencia.
ciaaMulticore dispatch OSEK API se encarga de llamar a la API de OSEK correspon-
diente en funcion del mensaje recibido. Examina los campos data0 y data1, identifica
uno de los dos comandos posibles descriptos en el listado 3.4, determina el ID de la Tarea
destino y/o el Evento a activar y finalmente invoca a la instancia local del RTOS mediante
las API ActivateTask o SetEvent segun corresponda. El codigo fuente completo de esta
funcion puede observarse en el listado 3.5.
26
Funciones internas
ciaaMulticore init Arch (Cortex-M4) inicializa la cola de mensajes para comunicacion
entre procesadores, habilita la interrupcion proveniente del Cortex-M0 y configura a dicho
procesador para que proceda a ejecutar su instancia de CIAA-Firmware.
ciaaMulticore init Arch (Cortex-M0) unicamente requiere habilitar la interrupcion pro-
veniente del Cortex-M4. El resto de los recursos ya fueron inicializados por el procesador
maestro.
ciaaMulticore sendSignal Arch es equivalente para ambos procesadores. Se ejecuta la
instruccion DSB (Data Synchronization Barrier) para forzar la finalizacion de todos los
accesos a memoria y luego ejecuta la instruccion SEV (Send Event) para generar una
interrupcion en el procesador remoto, tal como se describio en la seccion 2.2.4.
ISR(M0 IRQHandler) (Cortex-M4) es el handler de interrupcion del Cortex-M0 en el pro-
cesador maestro. Se encarga de limpiar el registro M0APPTXEVENT indicando el recono-
cimiento de la interrupcion para luego recibir el mensaje del procesador remoto, proceder
a la interpretacion del mismo y posteriormente invocar al RTOS local para activar la tarea
o evento solicitado por el RTOS remoto.
ISR(M4 IRQHandler) (Cortex-M0) es el handler de interrupcion del Cortex-M4 en el proce-
sador esclavo. Se encarga de limpiar el registro M4TXEVENT indicando el reconocimiento
de la interrupcion para luego recibir el mensaje del procesador remoto, proceder a la inter-
pretacion del mismo y posteriormente invocar al RTOS local para activar la tarea o evento
solicitado por el RTOS remoto.
27
Listado 3.5: Funcion ciaaMulticore dispatch OSEK API
1 extern int32_t ciaaMulticore_dispatch_OSEK_API(ciaaMulticore_ipcMsg_t m)
2 {
3 int32_t rv = -1;
4 switch(m.data0 & ~0xFF) {
5 case CIAA_MULTICORE_CMD_ACTIVATETASK:
6 ActivateTask(m.data1);
7 rv = 0;
8 break;
9 case CIAA_MULTICORE_CMD_SETEVENT:
10 SetEvent(m.data0 & 0xFF , m.data1);
11 rv = 0;
12 break;
13 default:
14 rv = -1;
15 break;
16 }
17 return rv;
18 }
3.3. Extension del Makefile principal de CIAA-Firmware
Se agregaron nuevas reglas en el Makefile principal de CIAA-Firmware que permiten compilar
especıficamente aplicaciones multicore:
make mcore generate genera el sistema operativo para cada instancia de CIAA-Firmware
que se ejecutara en cada procesador.
make mcore compila, linkea y genera ambas imagenes de Firmware.
make mcore download se conecta al microcontrolador a traves de OpenOCD y descarga
las imagenes de memoria a los respectivos bancos de Flash que utilizara cada procesador.
make mcore clean borra todos los archivos generados del RTOS, archivos objeto, biblio-
tecas estaticas y binarios correspondientes a ambas instancias.
3.4. Extension del generador de OSEK-OS
El generador de FreeOSEK debio ser modificado para reconocer nuevos parametros de con-
figuracion que el usuario definira en su archivo OIL cuando desea implementar una aplicacion
multicore. Dichos parametros son:
28
MULTICORE = TRUE debe definirse en los parametros del sistema operativo (nodo OS, ver
lınea 11 del archivo OIL en el Apendice D).
En cada Tarea (TASK), Alarma (ALARM), Contador (COUNTER) e ISR definidas en el OIL
debera agregarse el parametro CORE = 0 para que ese recurso este definido en el procesador
maestro, o bien CORE = 1 para definirlo en el procesador esclavo. Pueden verse ejemplos
en las lıneas 31, 125, 161 y 181 del archivo OIL en el Apendice D.
Luego se definieron nuevas funciones de busqueda dentro del arbol de configuracion OIL:
getLocalList se utiliza para obtener el listado de recursos pertenecientes al procesador
para el cual se esta generando el RTOS.
getRemoteList se utiliza para obtener el listado de recursos pertenecientes al/los proce-
sador/es diferentes al cual se esta generando el RTOS.
En el Listado 3.6 puede observarse un caso de uso de estas dos funciones para definir las tareas
locales a un procesador y las que son remotas, es decir que se ejecutan en el otro procesador.
En el Listado 3.7 puede observarse el codigo resultante generado. Puede consultarse el archivo
Os Cfg.h.php:90 para verlas en su contexto.
Listado 3.6: Uso de las funciones para acceder a recursos locales y remotos
1 /* Definitions of Tasks */
2 $tasks = getLocalList("/OSEK", "TASK");
3 $remote_tasks = getRemoteList("/OSEK", "TASK");
4 $count = 0;
5 foreach ($tasks as $task) {
6 print "/** \brief Task Definition */\n";
7 print "#define $task $count\n";
8 $count ++;
9 }
10 print "\n";
11 if (count($remote_tasks) > 0) {
12 foreach ($remote_tasks as $task) {
13 print "/** \brief Remote Task Definition */\n";
14 print "#define $task $count\n";
15 $count ++;
16 }
17 print "\n";
18 }
29
Listado 3.7: Resultado de la generacion donde pueden apreciarse tareas locales y remotas
1 /** \brief Task Definition */
2 #define InitTaskMaster 0
3 #define CommTaskMaster 1
4 #define TaskCheckSlave 2
5 /** \brief Remote Task Definition */
6 #define InitTaskSlave 3
7 #define TaskCheckMaster 4
8 #define PeriodicTaskSlave 5
9 #define LEDOffSlave 6
Finalmente en el Listado 3.8 se observa un vector que es generado para indicar en que proce-
sador corren las tareas remotas. Se considera numero 0 (cero) el procesador maestro (Cortex-M4
en este caso) y numeros 1 en adelante los procesadores esclavos. Este vector es necesario para
confeccionar el mensaje que sera enviado a la cola del modulo multicore.
Listado 3.8: Resultado de la generacion donde pueden apreciarse tareas locales y remotas
1 /** \brief RemoteTaskCore Array */
2 const TaskCoreType RemoteTasksCore[REMOTE_TASKS_COUNT] = {1, 1, 1, 1};
3.5. Modificacion de la API de FreeOSEK
Las funciones de FreeOSEK que debieron modificarse se describen a continuacion. En todos
los casos la funcionalidad agregada solo es ejecutada si se define la opcion MULTICORE = TRUE
en la definicion del OS dentro del archivo OIL.
StartOS ademas de la inicializacion normal del sistema operativo, llama a ciaaMulticore init
(ver seccion 3.2.3).
ActivateTask detecta si el ID de la tarea pasada como parametro es remota (su va-
lor numerico es mayor que la cantidad de tareas locales definidas) entonces confecciona el
mensaje ciaaMulticore ipcMsg t correspondiente y lo envıa a traves del modulo multico-
re con ciaaMulticore sendMessage (ver seccion 3.2.3). En el Listado 3.9 puede observarse
el bloque de codigo correspondiente a esta modificacion.
SetEvent funciona en forma similar a ActivateTask detectando si el ID de la tarea a la
que se debe activar el evento es remota. En ese caso confecciona el mensaje correspondiente
y lo envıa (ver Listado 3.10).
30
Listado 3.9: Modificacion a la API ActivateTask
1 if (( TaskID - TASKS_COUNT) < REMOTE_TASKS_COUNT) {
2 ciaaMulticore_ipcMsg_t m = {
3 .id = {
4 /* TODO: this should be replaced by TasksConst[remote_id ]. TaskCore */
5 .cpuid = RemoteTasksCore[TaskID - TASKS_COUNT],
6 .pid = 0
7 },
8 .data0 = CIAA_MULTICORE_CMD_ACTIVATETASK ,
9 .data1 = TaskID - TASKS_COUNT
10 };
11 ciaaMulticore_sendMessage(m);
12 /* TODO: we should wait for an acknowledge from the remote core */
13 ret = E_OK;
14 }
Listado 3.10: Modificacion a la API SetEvent
1 if (( TaskID - TASKS_COUNT) < REMOTE_TASKS_COUNT) {
2 ciaaMulticore_ipcMsg_t m = {
3 .id = {
4 /* TODO: this should be replaced by TasksConst[remote_id ]. TaskCore */
5 .cpuid = RemoteTasksCore[TaskID - TASKS_COUNT],
6 .pid = 0
7 },
8 .data0 = CIAA_MULTICORE_CMD_SETEVENT | (TaskID - TASKS_COUNT),
9 .data1 = Mask
10 };
11 ciaaMulticore_sendMessage(m);
12 /* TODO: we should wait for an acknowledge from the remote core */
13 ret = E_OK;
14 }
31
Capıtulo 4
Pruebas funcionales
Una vez terminado el trabajo sobre el modulo multicore descripto en el capıtulo anterior,
se procedio a disenar las pruebas funcionales del mismo. En este capıtulo se describiran las
aplicaciones de prueba que cumplen la funcion de analisis funcional de la nueva implementacion.
4.1. Aplicacion de monitoreo entre procesadores
El programa ((monitor)) hace un uso extensivo del modulo multicore, tanto para la division de
tareas entre procesadores como para el monitoreo mutuo. Como indica la Figura 4.1, el procesa-
dor esclavo se encargara de monitorear permanentemente el estado de las entradas digitales de
la CIAA. Ante cualquier cambio en las mismas utilizara la API multicore para activar una tarea
remota en el procesador maestro que se encargara de transmitir dicho cambio de estado con un
formato predeterminado a traves de una UART. Por otro lado, ambos procesadores activaran
periodicamente eventos hacia el procesador remoto: la idea es que estos eventos funcionen como
keep-alive, indicando que estan ((vivos)) es decir, ejecutando su programa normalmente. En caso
de no recibir el evento keep-alive, y transcurrido un tiempo de timeout, el procesador remoto
generara una condicion de alarma representada por el encendido de un LED particular en la
CIAA, indicando que uno de los procesadores dejo de funcionar. En las secciones siguientes se
describiran las tareas de OSEK-OS que ejecuta cada procesador.
4.1.1. Tareas del procesador maestro Cortex-M4
main (punto de entrada de aplicacion): El procesador maestro Cortex-M4 inicia su ejecu-
cion de CIAA-Firmware y activa al procesador esclavo con la funcion StartOS (ademas de
la inicializacion tradicional del RTOS).
32
Sistema MaestroCortex-M4
Reporte
Sistema EsclavoCortex-M0
Monitoreo I/O
Ent
rada
s
DIOUART
Reporte
ciaaMulticore
Figura 4.1: Esquema de la aplicacion de prueba ((monitor))
InitTaskMaster: Tarea que se ejecuta una unica vez, inicializa los drivers POSIX de
CIAA-Firmware y mediante la funcion ciaaPOSIX open obtiene acceso a los perifericos
Dio (entradas), Dio (salidas) y la UART que se utilizara para la transmision de una cadena
de caracteres que reflejara los cambios en las entradas detectados por el esclavo.
CommTaskMaster: Tarea de comunicacion con comportamiento aperiodico. Esta es la tarea
que el procesador esclavo despierta remotamente. Se leen las entradas Dio, luego se arma
la cadena de caracteres y finalmente se transmite vıa UART.
TaskCheckSlave: Esta tarea comienza esperando dos eventos: El que activa el procesador
remoto indicando que ((esta vivo)) y un evento de timeout local que se activara a los cinco
segundos de haber comenzado la espera. Si llega primero el evento remoto, se lo da por
reconocido, se reinicia el timeout y la tarea vuelve al comienzo a esperar nuevamente
los eventos mediante la API ChainTask. Si llega el evento timeout se considera que el
procesador remoto no esta respondiendo, lo que implica una falla en el sistema. Por este
motivo se enciende un LED indicando el error y llama a la funcion ShutdownOS que detiene
el sistema.
Se observa que no existe ninguna tarea encargada de la activacion periodica del evento keep-
alive hacia el procesador remoto. Esto es ası ya que se utiliza una Alarma de FreeOSEK para este
fin, que unicamente debe definirse en el archivo OIL y comienza a funcionar automaticamente con
el inicio del sistema. La definicion de dicha alarma se encuentra en la lınea 106 del archivo OIL.
En ese mismo bloque se puede observar el evento que se envıa al procesador esclavo denominado
evMasterAlive y la tarea remota TaskCheckMaster. Tambien esta definido el tiempo de ciclo
de esta alarma, que es de un segundo. Este tiempo define la frecuencia de envıo del evento
evMasterAlive: uno por segundo.
33
4.1.2. Tareas del procesador esclavo Cortex-M0
main (punto de entrada de aplicacion): Similar a la del procesador maestro, se llama a la
API StartOS que arranca el RTOS y modulo multicore locales.
InitTaskSlave: Tarea que se ejecuta por unica vez, obtiene el acceso desde el esclavo a las
entradas y salidas de la CIAA, para luego activar la tarea periodica PeriodicTaskSlave
que se encargara del monitoreo.
PeriodicTaskSlave: Esta tarea monitorea las entradas y ante un cambio en las mismas lla-
mara a la API ActivateTask solicitando la activacion de la tarea remota CommTaskMaster.
La Figura 4.2 describe la secuencia completa de activacion remota de una tarea. Un es-
quema similar se aplica para la activacion de Eventos.
LEDOffSlave: Tarea con un proposito estetico. Cuando la tarea PeriodicTaskSlave detec-
ta un cambio en las entradas enciende un LED de la CIAA que esta tarea se encargara de
apagar luego de 100 milisegundos, la idea es tener un efecto ((destello)) que indique visual-
mente la deteccion del cambio.
TaskCheckMaster: Tarea equivalente a su homologa TaskCheckSlave en el procesador
maestro. Se define el timeout de cinco segundos mediante un evento local y se aguarda
por el evento keep-alive desde el procesador remoto. Ante la falta de este ultimo y la
aparicion del timeout se llamara a ShutdownOS encendiendo un LED diferente al de la
tarea homologa.
En el caso del procesador esclavo, la Alarma que envıa el evento evSlaveAlive a la tarea
TaskCheckSlave del procesador maestro esta definida en la lınea 127 del archivo OIL. Su ciclo
tambien es de un segundo, al igual que la definida en el procesador maestro.
Para probar el funcionamiento de los eventos de timeout tanto en el maestro como en el
esclavo se definieron bloques de codigo que generan una excepcion del sistema1: Se define un
puntero a la posicion de memoria 0x00000000 y se trata de escribir en dicha posicion. Dado que
corresponde a memoria de solo lectura se generara una excepcion BusFault (falla de bus) que
forzara al procesador a ejecutar un salto incondicional infinito en el handler de la excepcion,
y con ello deteniendo la instancia ejecutandose en el procesador donde se genero la falla. Otro
procedimiento para detener al procesador y forzar la generacion del timeout en el remoto es
iniciar una sesion de debug y colocar un breakpoint en alguna seccion ejecutable del codigo.
1Ver monitor slave.c:93 y monitor master.c:97.
34
PROGRAMA DE USUARIOESCLAVO
KERNEL OSEK ESCLAVO
MÓDULO MULTICORE ESCLAVO
ActivateTask()
MÓDULO MULTICORE MAESTRO
KERNEL OSEK MAESTRO
PROGRAMA DE USUARIOMAESTRO
ChainTask()
Init
Task
Per
iod
icTa
sk
Activación deTarea Local
ActivateTask()
Activación de Tarea Remota Enviar
Mensaje
Interrupción
RecibirMensaje
Co
mm
Task
ActivateTask()Activación deTarea Local
Cola deMensajes
Figura 4.2: Diagrama de secuencia para la activacion de tareas remotas.
4.2. Pruebas de consumo
Se realizaron cambios en el programa ((monitor)) para realizar mediciones de consumo, en
todos los casos se midio la corriente media que consume el microcontrolador LPC4337. La des-
cripcion de los diferentes casos de prueba ası como los resultados de las mediciones pueden
observarse en la Tabla 5.1. El hardware utilizado que puede observarse en la Figura 4.3 com-
prende la placa Core4337 que unicamente contiene el microcontrolador LPC4337 y un debugger
JTAG externo de fabricacion propia2. El amperımetro se coloco entre el debugger y la placa con
el microcontrolador, segun se puede apreciar en el esquema de la Figura 4.4. No se utilizo la
EDU-CIAA en este caso debido a que contiene varios perifericos externos y el JTAG incorpo-
rado, que agregan elementos activos cuyo consumo es irrelevante para este analisis. Durante las
pruebas se mantuvo un voltaje de alimentacion Vdd=3.3V.
2Para mas informacion sobre el debugger puede consultarse este repositorio.
35
Figura 4.3: Hardware utilizado para la medicion de consumo
Debugger JTAG Core4337
A3.3V
JTAG
Figura 4.4: Esquema de conexion de los elementos
36
Capıtulo 5
Resultados y conclusion
5.1. Analisis de resultados
Tomando como referencia los Objetivos definidos en la seccion 1.2, los Alcances en la seccion
1.3 y los Requerimientos del proyecto en la seccion 1.4, se puede concluir en principio que
la implementacion de la Extension del Sistema Operativo FreeOSEK para el multiprocesador
asimetrico LPC4337 ha resultado satisfactoria.
Por un lado los Objetivos del proyecto son relativamente generales: se habla de lograr la
implementacion en general de la extension y el cumplimiento de los deadlines para la defensa
del Trabajo Final de la Carrera de Especializacion. En cambio los Alcances son mas especıficos,
con lo cual se puede analizar en detalle el cumplimiento de cada uno:
El primer alcance se refiere a la implementacion especıfica para el microcontrolador LPC4337,
esto ha sido cumplido satisfactoriamente.
El segundo alcance se refiere a los entregables, que han sido finalizados en tiempo y forma.
Restan correcciones que puedan surgir de revisiones posteriores por parte de los Directores
del Trabajo Final.
Respecto a los requerimientos, se realizara un analisis puntual de cada uno en funcion del
trabajo realizado:
1. El port de CIAA-Firmware para Cortex-M0 se ha implementado, disponiendose en princi-
pio del driver Dio (GPIO) para ser utilizado por esta instancia. Si no se requiere comuni-
cacion con la instancia ejecutandose en el Cortex-M4, dicho port es capaz de coexistir en
forma independiente, siempre que no se intente acceder a recursos de hardware en forma
concurrente.
37
2. Para lograr que la instancia de CIAA-Firmware que se ejecuta en Cortex-M4 de inicio a
la correspondiente en Cortex-M0, fue necesario modificar la API StartOS de FreeOSEK
(ver seccion 3.5).
3. La generacion de FreeOSEK y la compilacion de ambas imagenes de CIAA-Firmware se
realizan en forma automatica gracias a las nuevas reglas incluidas en el Makefile principal
(ver seccion 3.3).
4. La API de FreeOSEK ActivateTask se modifico satisfactoriamente, tal y como se descri-
bio en la seccion 3.5.
5. La API de FreeOSEK SetEvent tambien se modifico satisfactoriamente (seccion 3.5).
Ambas API sufren de una limitacion: dada la forma en que se calcula el ID del recurso
remoto a ser activado, la extension actual funciona para sistemas con dos procesadores.
En caso de existir tres o mas, debera revisarse la implementacion.
6. Se han realizado pruebas de consumo que desde un punto de vista funcional resultaron
adecuadas y logicamente consistentes (el procesador Cortex-M0 tiene un consumo medio
menor que el Cortex-M4), aunque no se observaron diferencias importantes en la corriente
media consumida por el microcontrolador (ver Tabla 5.1).
7. Gracias a la arquitectura de CIAA-Firmware se logro mantener absoluta compatibilidad
entre los modelos de CIAA que utilicen el LPC4337. Incluso podrıa extenderse este reque-
rimiento a otro hardware que este basado en el mismo microcontrolador, aunque sera ne-
cesario revisar los device drivers que accedan a perifericos externos.
Ademas de estos requerimientos cumplidos el usuario dispone de dos ejemplos de utilizacion
de FreeOSEK multicore: El programa blinking multicore que ilustra la comunicacion entre
los procesadores mediante la activacion mutua de tareas y eventos; y por otro lado el ejemplo
monitor que fue ampliamente descripto en la seccion 4.1, que es utilizado como plataforma de
prueba funcional de la extension multicore de FreeOSEK.
5.2. Proximos pasos
Existen algunas cuestiones en el marco de este trabajo que pueden ser abordadas a corto
plazo:
El issue #354 de CIAA-Firmware se abrio con el objetivo de definir mas zonas de me-
moria RAM compartidas entre procesadores ademas de la utilizada para el intercambio
38
Caso Descripcion Clock CPU [MHz] Consumo [mA]
A0Programa ((monitor)) sin cambios, tal co-
mo se describio en la seccion 4.1.204 228.4
A1 Idem A0. 102 127.6
A2 Idem A0. 51 69.8
B0
Todas las tareas se ejecutan en el proce-
sador maestro. El procesador esclavo se
mantiene en estado de reset.
204 214.1
B1 Idem B0. 102 118.7
B2 Idem B0. 51 68.7
C0
Todas las tareas se ejecutan en el proce-
sador esclavo. El procesador maestro se
mantiene en estado deep-sleep.
204 208.4
C1 Idem C0. 102 114.3
C2 Idem C0. 51 66.5
Tabla 5.1: Casos de prueba para medicion del consumo del microcontrolador y valores obtenidos
durante la experimentacion.
de mensajes. Particularmente en este caso serıa conveniente que todos los procesadores
tuvieran acceso a las estructuras unificadas de Tareas y Alarmas de FreeOSEK, evitando
la existencia de definiciones duplicadas en la memoria utilizada por cada procesador.
El issue #369 sugiere una mejora para la implementacion de malloc en sistemas que no
soportan acceso desalineado mas generica respecto a la definida en la seccion 3.1.5.
Actualmente existe una unica cola de mensajes intercambiados entre procesadores. Una
mejora significativa de esta caracterıstica consiste en implementar una cola de mensajes
para cada procesador. De esta manera se simplifica el tratamiento de los mensajes, dado
que si la cola es unica y un procesador quita un mensaje que no es para el, deberıa volverlo
a colocar, lo que implica una perdida de tiempo que puede optimizarse con la mejora
mencionada.
La caracterıstica multicore de CIAA-Firmware aun no se ha integrado oficialmente a la ra-
ma master (donde aparecen todas las caracterısticas oficialmente soportadas). Debera tra-
bajarse para lograr el merge (union) de la rama master con la rama feature/multicore que
39
es donde se ha realizado este trabajo.
Tambien pueden implementarse mas drivers POSIX para el procesador Cortex-M0, ademas
de GPIO (Dio).
Expandir la caracterıstica multicore al port de CIAA-Firmware para x86 y x86 64. Estos
ports particulares tienen por objetivo generar un ejecutable para Windows o Linux donde
se puede simular el comportamiento general de la aplicacion (Tareas, Alarmas, Eventos)
pero no se dispone de emulacion de los drivers de hardware (GPIO, ADC, Timers, etc.).
Un sistema multicore podrıa simularse en este contexto creando diferentes procesos (que
simularıan las instancias) donde el modulo multicore puede aprovechar algun mecanismo
de comunicacion entre procesos de Linux o Windows para simular la cola de mensajes
necesaria, que debera ser visible desde todos los procesos que emulan las instancias.
Analizar los valores devueltos por ActivateTask y SetEvent: Actualmente ambas API
devuelven E OK cuando activan recursos remotos. Esto no es correcto ya que el estandar
especifica ademas otros valores a ser retornados en caso de error, por ejemplo si el ID de
la tarea es invalido[17].
A largo plazo el objetivo es continuar los estudios para la Maestrıa en Sistemas Embebi-
dos siguiendo la lınea de investigacion actual sobre Sistemas Operativos de Tiempo Real para
microcontroladores con mas de un procesador:
Definir en tiempo de ejecucion en que procesador se ejecutara una determinada tarea
(actualmente eso se define en la configuracion OIL). Dado que un programa compilado
para Cortex-M0 es tambien ejecutable por el Cortex-M4 (la inversa no es posible), y si
por ejemplo este ultimo tiene menos carga de trabajo que el Cortex-M0, puede ejecutar
tareas del procesador esclavo con el fin de reducir su carga y equilibrar el uso de ambos
procesadores.
Unificar el kernel de FreeOSEK. Actualmente la instancia del kernel que se ejecuta en
el procesador esclavo podrıa optimizarse dejando que el kernel del procesador maestro
seleccione la tarea que el/los esclavo/s debera/n ejecutar.
Agregar envıo de mensajes definidos por el usuario ademas de los utilizados por la API de
FreeOSEK.
Implementar la utilizacion de los Resources (Recursos) de OSEK-OS para sincronizar el
acceso a recursos compartidos en sistemas multicore.
40
Asegurar la escalabilidad para el modulo multicore en microcontroladores con N procesa-
dores, donde N es un numero configurable en el OIL del sistema.
Mejorar el consumo del sistema multicore a partir de la variacion en la frecuencia de reloj
de cada procesador. Puntualmente en el LPC4337 no es posible independizar la frecuen-
cia de trabajo de Cortex-M4 y la de Cortex-M0, pero puede trabajarse para modificar
dinamicamente este parametro, ya que segun se observo en la Tabla 5.1 existe una reduc-
cion drastica de consumo si se trabaja a menores frecuencias de reloj.
El issue #370 sugiere separar la interpretacion de los mensajes recibidos que actualmente
realiza la API ciaaMulticore dispatch OSEK API, integrandola al kernel de FreeOSEK,
dejando exclusivamente al modulo multicore la tarea de manejo de mensajes. Esto se
relaciona tambien con el punto descripto anteriormente respecto a los mensajes definidos
por el usuario.
Ademas de los Conformance Tests especificados en el estandar de OSEK-OS, se definen
tambien los Implementation Tests o Pruebas de Implementacion, que se suman a los del
estandar pero no son requeridos por el mismo, sino que son especıficos a la version de
OSEK-OS utilizada. El issue #371 fue abierto con el objetivo de definir Pruebas de Im-
plementacion especıficas para la extension multicore.
Si bien el RTOS OSEK-OS es estatico por los motivos expuestos en la seccion 2.1.1,
los manejadores de dispositivo o device drivers de CIAA-Firmware, al estar basados en
el estandar POSIX, requieren la inicializacion de ciertas estructuras de datos en forma
dinamica, hecho que atenta contra el determinismo de la aplicacion a ser ejecutada por la
CIAA. Debera mejorarse esta implementacion para que los drivers POSIX tambien sean
definidos en forma estatica, al igual que FreeOSEK, con el fin de asegurar los recursos
del sistema necesarios para su utilizacion en tiempo de compilacion y no en tiempo de
ejecucion.
41
Bibliografıa
[1] Beuche, D.; Guerrouat, A.; Papajewski, H.; Schroder-Preikschat, W.; Spinczyk, O.; Spin-
czyk, O., “The PURE family of object-oriented operating systems for deeply embedded
systems, in Object-Oriented Real-Time Distributed Computing”, 1999. (ISORC ‘99) Pro-
ceedings. 2nd IEEE International Symposium on , vol., no., pp.45-53, 1999. doi: 10.1109/I-
SORC.1999.776349. 1
[2] UBM Tech, “Embedded Market Study”, 2014. 1
[3] NXP LPC4300 family press release, 2011. 1
[4] Carta de Licencia Libre de OSEK/VDX. 7
[5] Especificacion ISO/IEC 9899:1999, pp. 313, sec. 7.20.3 “Funciones de Manejo de Memoria”.
8
[6] Estandar POSIX.1-2008. 9
[7] Mariano Cerdeiro, “Introduccion a OSEK-OS – El Sistema Operativo del CIAA-Firmware”
(en prensa), ACSE, 2015. 12
[8] Pablo Ridolfi, µPOSIX: Una biblioteca POSIX para microcontroladores, ACSE, 2015. 12
[9] Joseph Yiu, “The Definitive Guide to ARM R© Cortex R©-M3 and Cortex R©-M4 Processors”,
Newnes, 2013. 13
[10] Cortex-M4 Technical Reference Manual, sec. 2.1. 14
[11] Joseph Yiu, “The Definitive Guide to ARM R© Cortex R©-M0 and Cortex R©-M0+ Proces-
sors”, Newnes, 2015, pp. 89, sec. 4.1.2. 14
[12] Cortex-M0 Technical Reference Manual, sec. 2.1. 15
[13] LPC43xx User Manual, pp. 24, sec. 1.6. 16
[14] LPC43xx User Manual, pp. 28, sec. 2.2. 17
42
[15] Joseph Yiu, “The Definitive Guide to ARM R© Cortex R©-M3 and Cortex R©-M4 Processors”,
Newnes, 2013. Sec. 10.4. 17
[16] Especificacion del Sistema Operativo OSEK/VDX 2.2.3, pp. 13, sec. 3.2. 21
[17] Especificacion del Sistema Operativo OSEK/VDX 2.2.3 pp. 50, sec. 13.2.3.1 y 13.5.3.1. 39
43
Apendice A
Diagrama de Gantt
44
Apendice B
Rutina de cambio de contexto para
Cortex-M0
1 /* Pendable Service Call: utilizada para cambio de contexto en los procesadores
Cortex -M */
2 PendSV_Handler:
3 cpsid f /* deshabilitar IRQs */
4 /* Reiniciar la pila de la tarea
5 que termino */
6 mov r0 ,lr
7 push {r0}
8 bl CheckTerminatingTask_Arch
9 pop {r0}
10 mov lr ,r0
11 mrs r0 ,msp /*Se usa MSP para
12 guardar el contexto */
13 /* guardado de registros
14 incluyendo lr */
15 subs r0 ,4
16 mov r1 ,lr
17 str r1 ,[r0]
18 subs r0 ,4
19 str r4 ,[r0]
20 subs r0 ,4
21 str r5 ,[r0]
22 subs r0 ,4
23 str r6 ,[r0]
24 subs r0 ,4
25 str r7 ,[r0]
26 /* guardado de los registros r8-r11 (high -registers) */
45
27 mov r4 ,r8
28 mov r5 ,r9
29 mov r6 ,r10
30 mov r7 ,r11
31 subs r0 ,4
32 str r4 ,[r0]
33 subs r0 ,4
34 str r5 ,[r0]
35 subs r0 ,4
36 str r6 ,[r0]
37 subs r0 ,4
38 str r7 ,[r0]
39 /* verificar si el contexto actual requiere ser guardado */
40 ldr r1 ,= Osek_OldTaskPtr_Arch
41 ldr r1 ,[r1]
42 cmp r1 ,0
43 beq no_guardo
44 str r0 ,[r1]
45 no_guardo:
46 /* cargar nuevo contexto */
47 ldr r1 ,= Osek_NewTaskPtr_Arch
48 ldr r1 ,[r1]
49 ldr r0 ,[r1]
50 /* recuperar registros del nuevo contexto */
51 ldr r7 ,[r0]
52 adds r0 ,4
53 ldr r6 ,[r0]
54 adds r0 ,4
55 ldr r5 ,[r0]
56 adds r0 ,4
57 ldr r4 ,[r0]
58 adds r0 ,4
59 mov r11 ,r7
60 mov r10 ,r6
61 mov r9 ,r5
62 mov r8 ,r4
63 ldr r7 ,[r0]
64 adds r0 ,4
65 ldr r6 ,[r0]
66 adds r0 ,4
67 ldr r5 ,[r0]
68 adds r0 ,4
46
69 ldr r4 ,[r0]
70 adds r0 ,4
71 ldr r1 ,[r0]
72 mov lr ,r1
73 adds r0 ,4
74 msr msp ,r0 /* recuperar MSP */
75 cpsie f /* habilitar IRQs */
76 bx lr /* fin de la ISR */
77 .end
47
Apendice C
Macros dependientes de la
arquitectura de FreeOSEK
1 /** \brief osekpause
2 ** This macro is called by the scheduler when not task has to be executed.
3 ** If a background task is configured by the user (a full preemptive task
4 ** with lower priority and which never ends) this macro will never be called.
5 ** In other case the macro will be called any time that the OS has nothing
6 ** else to execute. The macro may sleep the cpu for a short time to avoid
7 ** overheating and full power consumption or may halt the processor always
8 ** that all wakeup reasons are right configured. If nothing is running
9 ** nothing my activate any task so we will keep sleeping until anything
10 ** occurs , like for example an interrupt.
11 **/
12 #define osekpause () __asm volatile ("wfi")
13 /** \brief Call to an other Task
14 ** This function jmps to the indicated task.
15 **/
16 #define CallTask(actualtask , nexttask) \
17 { \
18 Osek_OldTaskPtr_Arch = (void*) TasksConst [( actualtask)]. TaskContext; \
19 Osek_NewTaskPtr_Arch = (void*) TasksConst [( nexttask)]. TaskContext; \
20 __asm__ __volatile__ ( \
21 /* Call PendSV */ \
22 "push {r0 -r2} \n\t" \
23 /* Activate bit PENDSVSET in Interrupt Control State Register (ICSR) */ \
24 "ldr r0 ,=0 xE000ED04 \n\t" \
25 "ldr r1 ,[r0] \n\t" \
26 "ldr r2 ,=(1 <<28) \n\t" \
27 "orr r1 ,r2 \n\t" \
48
28 "str r1 ,[r0] \n\t" \
29 "pop {r0 -r2} \n\t" \
30 ); \
31 }
32 /** \brief Jmp to an other Task
33 ** This function jmps to the indicated task.
34 **/
35 #define JmpTask(task) \
36 { \
37 extern TaskType WaitingTask; \
38 if(WaitingTask != INVALID_TASK) \
39 { \
40 Osek_OldTaskPtr_Arch = (void*) TasksConst[WaitingTask ]. TaskContext; \
41 WaitingTask = INVALID_TASK; \
42 } \
43 else \
44 { \
45 Osek_OldTaskPtr_Arch = (void*)0; \
46 } \
47 Osek_NewTaskPtr_Arch = (void*) TasksConst [(task)]. TaskContext; \
48 __asm__ __volatile__ ( \
49 /* Call PendSV */ \
50 "push {r0 -r2} \n\t" \
51 /* Activate bit PENDSVSET in Interrupt Control State Register (ICSR) */ \
52 "ldr r0 ,=0 xE000ED04 \n\t" \
53 "ldr r1 ,[r0] \n\t" \
54 "ldr r2 ,=(1 <<28) \n\t" \
55 "orr r1 ,r2 \n\t" \
56 "str r1 ,[r0] \n\t" \
57 "pop {r0 -r2} \n\t" \
58 ); \
59 }
60 /** \brief Save context */
61 #define SaveContext(task) \
62 { \
63 extern TaskType WaitingTask; \
64 if(TasksVar[GetRunningTask ()].Flags.State == TASK_ST_WAITING) \
65 { \
66 WaitingTask = GetRunningTask (); \
67 } \
68 flag = 0; \
69 /* remove of the Ready List */ \
49
70 RemoveTask(GetRunningTask ()); \
71 /* set system context */ \
72 SetActualContext(CONTEXT_SYS); \
73 /* set running task to invalid */ \
74 SetRunningTask(INVALID_TASK); \
75 /* finish cirtical code */ \
76 IntSecure_End (); \
77 /* call scheduler */ \
78 Schedule (); \
79 /* add this call in order to maintain counter balance when returning */ \
80 IntSecure_Start (); \
81 }
82 /** \brief */
83 #define ResetStack(task) \
84 { \
85 TerminatingTask = (task); \
86 }
87 /** \brief Set the entry point for a task */
88 #define SetEntryPoint(task) \
89 { \
90 TerminatingTask = (task); \
91 }
92 /** \brief Enable OS Interruptions
93 ** Enable OS configured interrupts (ISR1 and ISR2). This macro
94 ** is called only ones in StartUp.c function.
95 **/
96 #define EnableOSInterrupts () __asm volatile (" cpsie i")
97 /** \brief Enable Interruptions
98 ** Enable not OS configured interrupts (ISR1 and ISR2). This macro
99 ** is called only ones in StartUp.c function.
100 ** This macro may be empty. Maybe will be removed on the future ,
101 ** please use it only if necessary , in other case use EnableOSInterrupts.
102 **/
103 #define EnableInterrupts () EnableOSInterrupts ()
104 /** \brief Disable OS Interruptions
105 ** Disable OS configured interrupts (ISR1 and ISR2).
106 **/
107 #define DisableOSInterrupts () __asm volatile (" cpsid i")
50
Apendice D
Archivo OIL de la aplicacion
((Monitor))
1 OSEK OSEK {
2 OS MulticoreOS {
3 STATUS = EXTENDED;
4 ERRORHOOK = TRUE;
5 PRETASKHOOK = FALSE;
6 POSTTASKHOOK = FALSE;
7 STARTUPHOOK = FALSE;
8 SHUTDOWNHOOK = FALSE;
9 USERESSCHEDULER = FALSE;
10 MEMMAP = FALSE;
11 MULTICORE = TRUE;
12 };
13 RESOURCE = POSIXR;
14 EVENT = POSIXE;
15 APPMODE = AppMode1;
16 EVENT = evMasterAlive;
17 EVENT = evSlaveAlive;
18 EVENT = evMasterTimeout;
19 EVENT = evSlaveTimeout;
20 TASK InitTaskMaster {
21 PRIORITY = 1;
22 ACTIVATION = 1;
23 AUTOSTART = TRUE {
24 APPMODE = AppMode1;
25 }
26 STACK = 512;
27 TYPE = EXTENDED;
51
28 SCHEDULE = NON;
29 RESOURCE = POSIXR;
30 EVENT = POSIXE;
31 CORE = 0;
32 }
33 TASK InitTaskSlave {
34 PRIORITY = 1;
35 ACTIVATION = 1;
36 AUTOSTART = TRUE {
37 APPMODE = AppMode1;
38 }
39 STACK = 512;
40 TYPE = EXTENDED;
41 SCHEDULE = NON;
42 RESOURCE = POSIXR;
43 EVENT = POSIXE;
44 CORE = 1;
45 }
46 TASK CommTaskMaster {
47 PRIORITY = 2;
48 ACTIVATION = 1;
49 STACK = 512;
50 TYPE = EXTENDED;
51 SCHEDULE = NON;
52 RESOURCE = POSIXR;
53 EVENT = POSIXE;
54 CORE = 0;
55 }
56 TASK TaskCheckSlave {
57 PRIORITY = 1;
58 ACTIVATION = 1;
59 STACK = 512;
60 TYPE = EXTENDED;
61 SCHEDULE = FULL;
62 RESOURCE = POSIXR;
63 EVENT = POSIXE;
64 EVENT = evSlaveAlive;
65 EVENT = evSlaveTimeout;
66 CORE = 0;
67 AUTOSTART = TRUE {
68 APPMODE = AppMode1;
69 }
52
70 }
71 TASK TaskCheckMaster {
72 PRIORITY = 1;
73 ACTIVATION = 1;
74 STACK = 512;
75 TYPE = EXTENDED;
76 SCHEDULE = FULL;
77 RESOURCE = POSIXR;
78 EVENT = POSIXE;
79 EVENT = evMasterAlive;
80 EVENT = evMasterTimeout;
81 CORE = 1;
82 AUTOSTART = TRUE {
83 APPMODE = AppMode1;
84 }
85 }
86 TASK PeriodicTaskSlave {
87 PRIORITY = 1;
88 ACTIVATION = 1;
89 STACK = 512;
90 TYPE = EXTENDED;
91 SCHEDULE = FULL;
92 RESOURCE = POSIXR;
93 EVENT = POSIXE;
94 CORE = 1;
95 }
96 TASK LEDOffSlave {
97 PRIORITY = 1;
98 ACTIVATION = 1;
99 STACK = 512;
100 TYPE = EXTENDED;
101 SCHEDULE = NON;
102 RESOURCE = POSIXR;
103 EVENT = POSIXE;
104 CORE = 1;
105 }
106 ALARM KeepAliveMaster {
107 COUNTER = HardwareCounterMaster;
108 ACTION = SETEVENT {
109 EVENT = evMasterAlive;
110 TASK = TaskCheckMaster;
111 }
53
112 AUTOSTART = TRUE {
113 APPMODE = AppMode1;
114 ALARMTIME = 0;
115 CYCLETIME = 1000;
116 }
117 CORE = 0;
118 }
119 ALARM TimeoutMaster {
120 COUNTER = HardwareCounterSlave;
121 ACTION = SETEVENT {
122 EVENT = evMasterTimeout;
123 TASK = TaskCheckMaster;
124 }
125 CORE = 1;
126 }
127 ALARM KeepAliveSlave {
128 COUNTER = HardwareCounterSlave;
129 ACTION = SETEVENT {
130 EVENT = evSlaveAlive;
131 TASK = TaskCheckSlave;
132 }
133 AUTOSTART = TRUE {
134 APPMODE = AppMode1;
135 ALARMTIME = 0;
136 CYCLETIME = 1000;
137 }
138 CORE = 1;
139 }
140 ALARM TimeoutSlave {
141 COUNTER = HardwareCounterMaster;
142 ACTION = SETEVENT {
143 EVENT = evSlaveTimeout;
144 TASK = TaskCheckSlave;
145 }
146 CORE = 0;
147 }
148 ALARM ActivateLEDOffSlave {
149 COUNTER = HardwareCounterSlave;
150 ACTION = ACTIVATETASK {
151 TASK = LEDOffSlave;
152 }
153 CORE = 1;
54
154 }
155 COUNTER HardwareCounterSlave {
156 MAXALLOWEDVALUE = 10000;
157 TICKSPERBASE = 1;
158 MINCYCLE = 1;
159 TYPE = HARDWARE;
160 COUNTER = HWCOUNTER0;
161 CORE = 1;
162 };
163 COUNTER HardwareCounterMaster {
164 MAXALLOWEDVALUE = 10000;
165 TICKSPERBASE = 1;
166 MINCYCLE = 1;
167 TYPE = HARDWARE;
168 COUNTER = HWCOUNTER0;
169 CORE = 0;
170 };
171 ISR M0_IRQHandler {
172 CATEGORY = 2;
173 PRIORITY = 0;
174 INTERRUPT = M0APP;
175 CORE = 0;
176 }
177 ISR UART2_IRQHandler {
178 INTERRUPT = UART2;
179 CATEGORY = 2;
180 PRIORITY = 0;
181 CORE = 0;
182 };
183 ISR M4_IRQHandler {
184 CATEGORY = 2;
185 PRIORITY = 0;
186 INTERRUPT = M4CORE;
187 CORE = 1;
188 }
189 };