60 votos

RTOS para sistemas empotrados

He visto muchos artículos que me dicen que debería usar RTOS para la gestión del tiempo y de los recursos. Mi tiempo no me permite investigar por mi cuenta, así que acudo a chiphacker en busca de consejo.

Utilizo microcontroladores de bajos recursos (MSP430, PIC) y estaba buscando RTOSs que pueda utilizar.

Al grano:

  1. Coste de los recursos del sistema
  2. Ventajas del sistema
  3. Desventajas del sistema
  4. Trucos de aplicación
  5. Situaciones en las que el RTOS debería/no debería utilizar.

No utilizo sistemas como el arduino, los proyectos con los que trabajo no pueden soportar el coste de un sistema de este tipo.

29voto

fearphage Puntos 250

No he tenido mucha experiencia personal con RTOSs aparte de QNX (que es genial en general, pero no es barato y he tenido una muy mala experiencia con un proveedor de placas en particular y la actitud de QNX de no preocuparse por los sistemas que no sean los más comunes) que es demasiado grande para PICs y MSP430.

Donde se beneficiará de un RTOS es en áreas como

  • gestión/programación de hilos
  • comunicaciones entre hilos + sincronización
  • E/S en sistemas con stdin/stdout/stderr o puertos serie o soporte ethernet o un sistema de archivos (no un MSP430 o PIC en su mayor parte, excepto los puertos serie)

Para los periféricos de un PIC o MSP430: para los puertos serie usaría un buffer de anillo + interrupciones... algo que escribo una vez por sistema y simplemente reutilizo; otros periféricos no creo que encuentres mucho soporte de un RTOS, ya que son tan específicos del vendedor.

Si necesitas una sincronización sólida como una roca al microsegundo, un RTOS probablemente no te ayudará -- los RTOS tienen una sincronización limitada, pero normalmente tienen una fluctuación de tiempo en su programación debido a los retrasos de la conmutación de contexto... QNX corriendo en un PXA270 tenía jitter en las decenas de microsegundos típicos, 100-200us máximo, así que yo no lo usaría para cosas que tengan que correr más rápido que unos 100Hz o que necesiten una sincronización mucho más precisa que unos 500us. Para ese tipo de cosas probablemente tendrás que implementar tu propio manejo de interrupciones. Algunos RTOS se adaptan bien a esto, y otros lo convierten en un verdadero dolor de cabeza: tu sincronización y la suya pueden no ser capaces de coexistir bien.

Si la temporización/programación no es demasiado compleja, puede ser mejor utilizar una máquina de estados bien diseñada. Recomiendo encarecidamente la lectura de Tablas de estado prácticas en C/C++ si aún no lo has hecho. Hemos utilizado este enfoque en algunos de nuestros proyectos donde trabajo, y tiene algunas ventajas reales sobre las máquinas de estado tradicionales para la gestión de la complejidad.... que es realmente la única razón por la que se necesita un RTOS.

26voto

Alex Puntos 1140

¿Has probado FreeRTOS ? Es gratis (sujeto a T&C), y ha sido portado tanto al MSP430, como a varios tipos de PIC.

Es pequeño en comparación con otros, pero esto también hace que sea fácil de aprender, especialmente si no has utilizado un RTOS antes.

Existe una licencia comercial (no gratuita), así como una versión IEC 61508/SIL 3.

12voto

intrepion Puntos 3973

Me acabo de enterar de NuttX RTOS, que incluso puede funcionar en un sistema 8052 (8 bits). No tiene muchos puertos, pero parece interesante. El POSIX puede ser una ventaja, porque puede hacer que parte de tu código sea un poco más portable si te mueves a un procesador más fuerte y quieres ejecutar linux en tiempo real o QNX.

Yo no tengo ninguna experiencia con RTOS comerciales, pero he utilizado los caseros durante años. Son geniales para ayudar a dividir el desarrollo del código entre muchos programadores, porque esencialmente cada uno puede tener una "tarea" o "hilo" para trabajar en su parte. Aún así hay que coordinar y alguien debe supervisar todo el proyecto para asegurarse de que cada tarea pueda cumplir con su plazo.

También le recomiendo que investigue Análisis monótono de la tasa o RMA cuando se utiliza un RTOS. Esto te ayudará a garantizar que tus tareas críticas cumplan sus plazos.

También me gustaría investigar la obra de Miro Samek QP-nano marco de programación basado en eventos que puede funcionar con o sin un RTOS y seguir ofreciéndole capacidad de tiempo real. Con él, estás dividiendo tu diseño en máquinas de estado jerárquicas en lugar de tareas tradicionales. Jason S mencionó el libro de Miro en su post. Una lectura excelente.

9voto

Alex Andronov Puntos 178

Una cosa que he encontrado útil en varias máquinas es un simple conmutador de pila. En realidad no he escrito uno para el PIC, pero supongo que el enfoque funcionaría bien en el PIC18 si ambos/todos los hilos utilizan un total de 31 o menos niveles de pila. En el 8051, la rutina principal es:

\_taskswitch:
  xch  a,SP
  xch  a,\_altSP
  xch  a,SP
  ret

En el PIC, olvido el nombre del puntero de la pila, pero la rutina sería algo así:

\_taskswitch:
  movlb \_altSP >> 8
  movf  \_altSP ,w,b
  movff \_STKPTR,altSP 
  movwf \_STKPTR,c
  return

Al comienzo de tu programa, llama a una rutina task2() que carga altSP con la dirección de la pila alternativa (16 probablemente funcionaría bien para un PIC18Fxx) y ejecuta el bucle task2; esta rutina no debe regresar nunca o de lo contrario las cosas morirán de forma dolorosa. En su lugar, debería llamar a _taskswitch cada vez que quiera ceder el control a la tarea primaria; la tarea primaria debería entonces llamar a _taskswitch cada vez que quiera ceder el control a la tarea secundaria. A menudo, uno tendrá pequeñas rutinas como:

void delay\_t1(unsigned short val)
{
  do
    taskswitch();
  while((unsigned short)(millisecond\_clock - val) > 0xFF00);  
}

Tenga en cuenta que el conmutador de tareas no tiene ningún medio para hacer ninguna "condición de espera"; todo lo que soporta es un spinwait. Por otro lado, el conmutador de tareas es tan rápido que un intento de taskswitch() mientras la otra tarea está esperando a que expire un temporizador cambiará a la otra tarea, comprobará el temporizador y volverá a cambiar más rápido de lo que un conmutador de tareas típico determinaría que no necesita cambiar de tarea.

Hay que tener en cuenta que la multitarea cooperativa tiene algunas limitaciones, pero evita la necesidad de un montón de bloqueos y otro código relacionado con los mutex en los casos en los que las invariantes que se alteran temporalmente pueden restablecerse rápidamente.

(Editar): Un par de advertencias respecto a las variables automáticas y demás:

  1. si una rutina que utiliza la conmutación de tareas es llamada desde ambos hilos, generalmente será necesario compilar dos copias de la rutina (posiblemente #incluyendo el mismo archivo fuente dos veces, con diferentes declaraciones #define). Cualquier archivo fuente contendrá código para un solo subproceso, o bien contendrá código que se compilará dos veces -una para cada subproceso- por lo que puedo utilizar macros como "#define delay(x) delay_t1(x)" o #define delay(x) delay_tx(x)" dependiendo del subproceso que esté utilizando.
  2. Creo que los compiladores de PIC que no pueden "ver" una función que está siendo llamada asumirán que dicha función puede destrozar todos y cada uno de los registros de la CPU, evitando así la necesidad de guardar cualquier registro en la rutina de cambio de tarea [un buen beneficio comparado con la multitarea preventiva]. Cualquiera que considere un conmutador de tareas similar para cualquier otra CPU necesita ser consciente de las convenciones de registro en uso. Empujar los registros antes de un cambio de tarea y abrirlos después es una manera fácil de ocuparse de las cosas, asumiendo que existe un espacio adecuado en la pila.

La multitarea cooperativa no permite escapar completamente de los problemas de bloqueo y demás, pero realmente simplifica mucho las cosas. En un RTOS preventivo con un recolector de basura compactado, por ejemplo, es necesario permitir que los objetos se fijen. Cuando se utiliza un conmutador cooperativo, esto no es necesario siempre que el código asuma que los objetos del GC pueden moverse en cualquier momento que se llame a taskswitch(). Un recolector de compactación que no tenga que preocuparse por los objetos anclados puede ser mucho más sencillo que uno que sí lo haga.

7voto

sq1020 Puntos 143

He utilizado Salvo en el MSP430. Este sistema es muy ligero en cuanto a recursos del procesador y, siempre que se respeten las reglas de implementación, muy fácil de usar y fiable. Se trata de un SO cooperativo y requiere que los cambios de tarea se realicen en el nivel de llamada a la función externa de las funciones de tarea. Esta restricción permite que el SO trabaje en dispositivos de memoria muy pequeños sin utilizar grandes cantidades de espacio en la pila para mantener los contextos de las tareas.

En el AVR32 estoy usando FreeRTOS. De nuevo muy fiable hasta ahora pero he tenido algunas discrepancias de configuración/versión entre la versión que publica FreeRTOS y la versión suministrada con el framework de Atmel. Sin embargo, esto tiene la ventaja de que es gratis.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X