Unidad Didáctica 3: Arquitectura de los C Interrupciones

Anuncio
Otros servicios de los RTOS
Sistemas embebidos para tiempo real
Índice
●
●
Introducción
Comunicación entre tareas:
–
●
●
●
●
●
mail box, queues, pipes.
Gestión del tiempo
Eventos
Gestión dinámica de memoria
Interrupciones en RTOS
Resumen
Introducción
●
Servicios básicos de RTOS
–
–
●
Planificador de tareas (multitarea)
Semáforos: comunicación y sincronización
entre tareas
Servicios adicionales para comunicación
entre tareas:
–
–
–
buzón de correo (mail boxes)
cola de mensajes (queue)
tuberías (pipes)
Cola de mensajes
●
Características:
–
–
●
Normalmente se usan cuando:
–
–
●
permite el envío de mensajes entre tareas.
mensajes organizados como un buffer circular.
Se necesita un almac. temporal para ráfagas de datos.
Existen varios generadores de datos y un sólo
consumidor y no queremos bloquear a los generadores.
Dos estrategias:
–
–
Se envía un puntero a los datos del mensaje (C/OS-II)
Se copian los datos directamente (otros)
Cola de mensajes: Preguntas
●
¿Qué pasa si leemos cuando la cola esta vacía?
–
–
Más común: se bloquea a la tarea que llama
Muchos RTOSs ofrecen dos funciones para leer:
●
●
●
Leer de la cola, se bloquea si está vacía
Leer de la cola, retorna (inmediatamente) un error si vacía
¿Qué pasa si escribimos y está llena?
–
Más común: se retorna un error
●
–
Menos común: se bloquea hasta que haya lugar.
●
–
Quien llama debe verificar el valor retornado. ¿Qué hacer?
Obviamente esta versión no puede llamarse desde ISR.
Ninguna solución se adapta a todas la necesidades.
Cola de mensajes: Ejemplo
●
Registro de errores (logs)
–
Task1 & Task2: tareas de alta prioridad
●
–
Si detectan errores necesitan registrarlos
●
–
almacenamiento no volátil o transmisión
Solución: ErrorTask (tarea baja prioridad)
●
–
requerimientos temporales exigentes
No afecta el tiempo de respuesta de Task1 & Task2
Comunicación de errores
●
Opción: cola de mensajes (se indica tipo error con
un entero)
/* RTOS queue function prototypes */
void AddToQueue (int iData);
void ReadFromQueue (int *p_iData);
/* Task1: high priority*/
void Task1 (void)
{
...
if (!! problem arises)
vLogError (ERROR_TYPE_X);
!! other things that need to be done
...
}
/* Task2: high priority */
void Task2 (void)
{
...
if (!! problem arises)
vLogError (ERROR_TYPE_Y);
!! other things that need to be done
...
}
void vLogError (int iErrorType)
{
AddToQueue (iErrorType);
}
static int cErrors;
/* ErrorTask: low priority*/
void ErrorsTask (void)
{
int iErrorType;
while (FOREVER)
{
ReadFromQueue (&iErrorType);
++cErrors;
!! Send cErrors, iErrorType
}
}
Cola de mensajes: funciones
●
Dos funciones reentrantes:
–
AddToQueue( )
●
–
ReadFromQueue( )
●
●
Obtiene un mensaje de la cola
Repaso
–
–
●
Agrega un mensaje a la cola
¿Qué significa que las funciones sean reentrantes?
¿Qué garantiza?
Atención: Ejemplo simplificado
Colas y punteros
●
Puntero a void (null pointer): void*
–
Uso como comodín:
●
●
●
cualquier puntero puede ser transformado a void*
nuevamente transformado al tipo original
Cola de punteros a void
–
Encolado de múltiples datos (ejemplo: arreglo de char)
●
●
–
Se guardan los datos en un buffer
Se pasa un puntero al buffer en la cola
Encolado de un dato: ejemplo int
●
●
encolar como: (void *) data
recuperar y “castear” a int
Colas en C/OS-II: resumen
• OS_EVENT *OSQCreate(void **start, INT8U size)
–
Crea la cola con el arreglo de punteros a
creado por la aplicación.
void
• INT8U OSQPost(OS_EVENT *pevent, void *msg)
–
Envía un mensaje a la cola.
• void *OSQPend(OS_EVENT *pevent, INT16U timeout,
INT8U *err)
–
Espera un mensaje.
Colas: C/OS-II
●
Estructura:
OS_EVENT
typedef struct{
INTU8 OSEventType; /* Tipo de evento */
INTU8 OSEventGrp;
/* Grupos de la lista de espera */
INT16U OSEventCnt; /* Contador (para semáforos) */
void *OSEventPtr;
/* Puntero al mensaje */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Lista de espera */
} OS_EVENT;
Actividad en grupo
●
Implementación: “registro de errores”
–
Objetivo:
●
–
Material:
●
●
–
3 a 4 participantes
Tiempo:
●
–
Código “genérico” de la implementación (no incluye
main).
Prototipos de las funciones de cola de C/OS-II.
Grupos:
●
–
Escribir el código para C/OS-II del ejemplo de uso de
colas para implementar el “registro de errores”.
10 minutos
Puesta en común.
Buzones
●
Características
–
Permite el pasaje de un mensaje entre tareas
–
Similar uso a la cola de mensaje
Buzones en C/OS-II: resumen
• OS_EVENT *OSMboxCreate(void *msg)
–
Crea el buzón con el mensaje inicial msg.
• void* OSMboxPend(OS_EVENT *pevent,
INT16U timeout, INT8U *err)
–
Espera a que llegue un mensaje y devuelve su
dirección.
• INT8U OSMboxPost(OS_EVENT *pevent, void *msg)
–
Envía un mensaje al buzón. Si ya hay un
mensaje devuelve un código de error.
Buzón: Ejemplo
●
Tarea de Impresión
–
–
●
Una tarea encargada de administrar la
impresión
Comunicación entre la tarea de impresión y el
resto de las tareas: vía un Buzón
Estudio de caso:
–
rutina de interrupción del timer manda
actualizar el tiempo mostrado en el display.
#include <stdio.h>
#include "display.h"
/* Cabeceras de uC/OS-II */
#include <includes.h>
void TimePrint (void)
{
char buf[10];
Time time_copy, *pTime;
int error;
typedef struct{
INTU8 hh;
INTU8 mm;
INTU8 ss;
} Time;
while(1){
pHora = (Time *) OSMboxPend(
pMbox_time, 0, &error);
if(error == OS_NO_ERR){
/* copia de dato compartido */
__disableInt();
time_copy = *pHora;
__enableInt();
sprintf(buf,
"\n%02d:%02d:%02d",
time_copy.hh,
time_copy.mm,
time_copy.ss);
DisplayPutString(buf);
}else{
/* Procesar el error */
}
}
OS_EVENT *pMbox_time;
void main(void)
{
/*bla bla bla*/
pMbox_time = OSMboxCreate(NULL);
/*bla bla bla*/
}
__interrupt void TimerISR (void)
{
static Time time_act;
time_act.ss++;
if(time_act.ss == 60){
...
}
OSMboxPost(pMbox_time, &time_act);
}
}
Pipes (tuberías,caño)
●
●
●
Las tuberías (pipes) son similares a las colas.
Las diferencias principales son:
–
Mensajes pueden ser de distinto tamaño.
–
Cada tarea puede escribir/leer núm arbitrario de
bytes.
–
Normalmente se usan para cadenas de caracteres
Es necesario establecer un protocolo:
–
–
●
terminadas por un carácter nulo
enviar el número de bytes total y luego el mensaje.
µC/OS-II no dispone de esta funcionalidad.
Gestión del tiempo
●
En los RTOS la gestión de tiempo es
fundamental:
–
Rutinas de control deben ejecutarse
periódicamente: TS.
–
Ahorro de energía: actividades no críticas han
de realizarse cada cierto tiempo (no
continuamente).
Diálogo con el hardware.
Gestión de timeouts.
–
–
Gestión del tiempo
●
Interrupción periódica
–
–
–
incrementa un contador: cuenta desde el
arranque.
cada incremento se denomina tick de reloj.
configurable al compilar el núcleo.
●
●
Para el µC/OS-II el tick es de 10 ms por defecto.
Función retardo (delay)
–
retarda la tarea por el periodo de tiempo
especificado, es decir: se bloquea hasta que el
tiempo expira
Gestion del tiempo: C/OS-II
• void OSTimeDly(INT16U ticks)
–
Suspende la tarea durante el número de ticks
especificado.
• void OSTimeDlyHMSM(INT8U horas, INT8U min,
INT8U seg, INT8U mili)
–
Suspende la tarea durante el tiempo
especificado en horas, minutos, segundos y
milisegundos.
Gestión del tiempo: Preguntas
●
¿Cuán preciso son los retardos?
●
¿Cómo se logran tiempos más precisos?
●
¿Son útiles los timeout de los semáforos, etc?
Ejemplo
●
Implementación: “gestión de tiempo”
–
–
Escribir seudo-código para muestrear cada 1
seg un dato del ADC.
Escribir código para C/OS-II.
Eventos
●
Es una bandera booleana que una tarea puede:
–
●
●
Generalmente manejados en grupos
Características:
–
–
–
●
Crear, Disparar(Set), Borrar (Reset), Esperar (Wait for)
Varias tareas se pueden desbloquear con un mismo
evento
Tarea se desbloquea por cualquier evento del grupo
Después ocurre el evento, todas las tareas son
desbloqueadas y el evento se borra.
Diferencias y similitudes con semáforos...
Comunic. entre tareas: comparación
●
Semáforos
–
–
●
Eventos:
–
–
–
●
Más rápido y simple, pero información si/no (ocupado)
Una tarea solo se bloquea en un semáforo por vez.
Poco más complicado pero...
Una tarea puede esperar por muchos eventos a la vez.
Múltiples tareas pueden desbloquearse por un evento.
Colas (buzones y tuberías)
–
–
Una tarea solo se puede bloquear en una cola pero...
Permiten enviar más información
Gestión dinámica de memoria
●
Funciones: malloc() y free() de la stdlib
–
no son apropiadas para sistemas de tiempo real
●
●
●
lentas
tiempos de ejecución no predecibles.
RTOS disponen de funciones alternativas
–
–
–
pools de memoria: buffers de tamaño fijo
comportamiento predecible
ciertas limitaciones
Gestión de memoria: µC/OS-II
–
–
La memoria se divide en particiones y cada
partición se divide en bloques del mismo tamaño.
La aplicación puede obtener bloques de una
partición.
• OS_MEM *OSMemCreate(void *addr, INT32U nblks,
INT32U blksize, INT8U *err).
– Crea una partición de memoria.
• void *OSMemGet(OS_MEM *pmem, INT8U *err)
– Obtiene un bloque de memoria.
• INT8U OSMemPut(OS_MEM *pmem, void *pblk)
– Devuelve un bloque de memoria.
OS_MEM *PartiMens; /* Estructura de control */
typedef struct{
INT8U id;
INT8U tiempo;
} Sensor;
/* Número del sensor */
/* Tiempo en ciclos del T7 de retardo del eco */
/* Se asigna memoria para la partición */
#define N_BLOQ_MENS 16
BYTE8 MemPartiMens[N_BLOQ_MENS][sizeof(Sensor)];
void main(void)
{
INT8U err;
OSInit();
...
PartiMens = OSMemCreate(MemPartiMens, N_BLOQ_MENS,
sizeof(INFO_SENSOR), &err);
if(err != OS_NO_ERR){
/* Abortamos porque no tenemos memoria */
}
...
OSStart();
}
Interrupciones en RTOS
●
Pregunta: ¿Qué sucede si se llama funciones que...
–
puedan bloquearse?
●
–
pueda hacer conmutar tareas?
●
●
Tomar semáforos, leer de colas, esperar por eventos
Liberar semáforos, escribir en colas, disparar eventos
Reglas
1) NO llamar funciones que puedan
bloquearse
2) NO llamar funciones que pueda hacer
conmutar tareas
Interrupciones: 2da regla
NO llamar funciones que pueda hacer conmutar tareas
ISR
RTOS
Tarea1 (espera buzon)
Entra a ISR
Envia mensaje
al buzón
Tarea2
ISR
RTOS
Tarea1 (espera buzon)
Tarea2
Envia mensaje
al buzón
Sale de ISR
Interrupciones en RTOS
●
2da Regla:
–
–
No llamar funciones del RTOS que pueda hacer
conmutar tareas
sin que RTOS sepa que se está en una
interrupción.
• Tres métodos diferentes:
1. Avisar al RTOS de la entrada y salida de la ISR.
2. RTOS intercepta todas las interrupciones y luego
llama a la ISR proporcionada por la aplicación.
3. Existen funciones especiales para su llamada
desde las ISR.
Interrupciones en RTOS: µC/OS-II
• void OSIntEnter(void)
– Indica al RTOS que se empieza a ejecutar una
ISR.
• void OSIntExit(void)
– Indica al RTOS que se termina de ejecutar la
ISR
ISR.
RTOS
Tarea1 (espera buzon)
Tarea2
OSIntEnter()
OSMboxPend( )
OSIntExit()
Actividad en grupo
•
Implementación: “RadiomodemControl”
–
Objetivo:
•
Escribir el código de la tarea que maneja un radio-modem:
Espera por un mensaje para transmitir.
Pasa la radio a modo Tx: llama la función PTT_On().
Espera 250 ms (necesario para que se estabilice el transmisor).
Manda el mensaje: llama la función UART_Send(...) que retorna
luego de mandar todos los caracteres. Explicar modificaciones a
realizar a la función original.
5. Pasa la radio a modo Rx: llama la función PTT_Off().
6. Vuelve al punto 1.
1.
2.
3.
4.
–
Grupos:
•
–
Tiempo:
•
–
2 a 4 participantes
5 minutos para implementar el módulo
Puesta en común.
Bibliografía
●
“An Embedded Software Primer”David E.
Simon
–
Chapter 7: More Operating System Services
Descargar