Fundamentos de Sistemas Empotrados: Comunicación, Periféricos y RTOS

Comunicación en Sistemas Empotrados

1. Diferencia entre Comunicación Síncrona y Asíncrona

En la comunicación síncrona, se envía una señal de reloj en la transmisión que marca las pautas de la comunicación. Esta señal se puede proporcionar a través de una línea adicional entre los sistemas que se desean comunicar, o bien, se puede extraer de alguna forma específica de codificación. Por otro lado, en la comunicación asíncrona, tanto el transmisor como el receptor deben secuenciar la comunicación de acuerdo con una base de tiempos, ya que la transmisión o la recepción pueden ocurrir en cualquier momento.

2. Bits Transmitidos en un Sistema Asíncrono RS-232

En un sistema asíncrono RS-232, los bits que se transmiten y su finalidad son:

  • El primer bit de la transmisión es un bit de inicio (start), que es un cero lógico.
  • Luego le siguen los bits del dato, comenzando por el bit menos significativo.
  • Finalmente, se transmiten uno o dos bits de parada (stop).

3. El Generador de Baudios y su Relación con RS-232

La velocidad de comunicación de la USART del PIC (la tasa de baudios) se controla mediante el USART Baud Rate Generator (SPBRG). El SPBRG es un temporizador de 16 bits que está continuamente contando. Esencialmente, la tasa de baudios deseada se fija cargando el registro SPBRG con el valor correcto para proporcionar la velocidad deseada.

La tasa de baudios también se ve afectada por el valor del bit BRGH. BRGH determina si se desean comunicaciones de alta o de baja velocidad. Cuando sea posible, usar el modo de alta velocidad (BRGH=1) siempre ofrece valores de tasa de baudios más cercanos al valor deseado que el modo de baja velocidad. Por tanto, es preferible emplear el modo de alta velocidad. Se dispone además de un bit, el BRG16, que permite usar el registro SPBRG como si fuese de 8 bits, lo cual en la mayoría de los casos es suficiente.

4. Gestión del Puerto Serie por Interrupciones en PIC18

Para gestionar el puerto serie por interrupciones, se define un búfer circular (una cola de tipo FIFO, “primero en entrar, primero en salir”) para una o ambas direcciones de comunicación. El puerto serie actúa como productor y la CPU como consumidor de los datos en la dirección de recepción (RX). Se asume que la CPU puede leer los datos más rápidamente que el puerto serie puede proporcionarlos, minimizando la pérdida de datos por falta de espacio en el búfer.

En la dirección de transmisión (TX), el programa es el productor y la USART es el consumidor. Si no hay espacio en el búfer (debido a un búfer de transmisión demasiado pequeño o a una producción de datos demasiado rápida), la transmisión fallará y deberá ser reintentada más tarde.

Los sucesos que ocurren al llegar un carácter a la USART del PIC18 son:

  1. Configurar el puerto y preparar la interrupción USART RX.
  2. Cuando los datos llegan, se llama a la interrupción.
  3. Dentro de la interrupción: si hay espacio disponible en el búfer, se guardan los nuevos datos y se incrementa el índice “head”.
  4. En la aplicación, la función de lectura de datos sería la siguiente:
    • Si head != tail, hay datos disponibles en el búfer.
    • Se devuelven los datos a los que apunta el índice “tail”.
    • Se incrementa el índice “tail”.

5. Características del Bus I2C

Las características más importantes del bus I2C son:

  • Se necesitan solamente dos líneas: la de datos (SDA) y la de reloj (SCL).
  • Cada dispositivo conectado al bus tiene un código de dirección seleccionable mediante software.
  • Existe una relación permanente maestro/esclavo entre el microcontrolador y los dispositivos conectados.
  • El bus permite la conexión de varios maestros, ya que incluye un detector de colisiones.
  • El protocolo de transferencia de datos y direcciones posibilita diseñar sistemas completamente definidos por software.
  • Los datos y direcciones se transmiten con palabras de 8 bits.
  • Las líneas SDA y SCL transportan información entre los dispositivos conectados al bus.

Para establecer un intercambio de datos, el maestro debe informar el comienzo de la comunicación mediante una condición de Start: la línea SDA cae a cero mientras SCL permanece en nivel alto. A partir de este momento, comienza la transferencia de datos.

Una vez finalizada la comunicación, se debe informar de esta situación mediante una condición de Stop: la línea SDA pasa a nivel alto mientras SCL permanece en estado alto. Para efectuar la transferencia de datos, el maestro genera la condición de Start. Cada palabra puesta en el bus SDA debe tener 8 bits. La primera palabra transferida contiene la dirección del esclavo seleccionado. Luego, el maestro lee el estado de la línea SDA: si vale 0 (impuesto por el esclavo), el proceso de transferencia continúa. Si vale 1, indica que el circuito direccionado no valida la comunicación, entonces el maestro genera un bit de stop para liberar el bus I2C. Este acuse de recibo se denomina ACK (acknowledge o reconocimiento) y es una parte importante del protocolo I2C. Al final de la transmisión, el maestro genera la condición de Stop y libera el bus I2C, pasando las líneas SDA y SCL a estado alto.

6. Diferencia entre Gestión del Bus I2C por “Bitbang” y por Controladora SSP del PIC18

La gestión del bus I2C puede realizarse de dos maneras principales:

  • Método “Bitbang”: Implica el uso de los puertos de entrada/salida (E/S) para generar manualmente las señales del bus I2C. Esto significa que el software debe actualizar el puerto para sacar cada uno de los bits que forman toda la comunicación, incluyendo las condiciones de start y stop, el envío de la dirección del dispositivo, el envío de los datos y la verificación del reconocimiento (ACK) que envía el dispositivo esclavo. Este proceso es tedioso y lento desde el punto de vista del software.
  • Empleando la Controladora del Bus SSP del PIC18: Esta controladora dispone de un circuito secuencial que genera automáticamente los trenes de pulsos de comunicación con el bus. La condición de start se genera activando un bit en un registro de control, en lugar de tener que sacar todos los bits que forman la condición. El envío de la dirección se realiza también escribiendo la dirección en un registro de salida, en lugar de sacarla por el puerto de E/S bit a bit en formato serie. El controlador se encarga de la temporización de los pulsos que envían los datos en formato serie por el bus I2C. También se encarga de recoger el reconocimiento (ACK) del esclavo y copiarlo a un registro de estado para que el programa lo pueda leer y testear. Para realizar esta tarea, existen dos registros de configuración que deben programarse previamente.

7. Conexión de Dispositivos SPI en “Daisy Chain”

La conexión de dispositivos SPI en “daisy chain” es un método para conectar periféricos en paralelo con un sistema microprocesador. En este esquema, los periféricos se combinan agrupándolos en diversas ramas seriales, donde cada rama corresponde a un canal y requiere una sola interfaz con la unidad central.

Su principal ventaja reside en la facilidad de ampliación de las ramas en serie. Sin embargo, su principal desventaja es que si el primer elemento de un canal se avería, deja fuera de servicio a los demás dispositivos conectados en esa misma cadena.

8. Programación del Puerto I2C mediante un Controlador de Bus (Ejemplo PIC)

Para manejar el puerto I2C mediante un controlador integrado, como el SSP del PIC, se deben programar sus registros de control, estado y datos. El controlador SSP del PIC dispone de los siguientes registros:

  • SSPCON1 y SSPCON2: Registros de control.
  • SSPSTAT: Registro de estado.
  • SSPBUF: Registro de recepción/transmisión.
  • SSPADD: Registro de velocidad.

El registro SSPCON1 permite configurar el tipo de comunicación I2C, el tipo de señal de reloj y el control de errores en el bus para detectar colisiones y overflow. En el registro SSPCON2, se emplean los bits SEN, RSEN, PEN y ACKEN para generar condiciones particulares en el bus I2C de forma automatizada, sin tener que manipular directamente las señales del bus como sucedería con los métodos bit-bang. Además, el bit ACKSTAT en el controlador informa del estado del bit de reconocimiento que debe generar el esclavo, permitiendo validar los datos enviados.

El proceso para enviar un dato por el bus I2C sería:

  1. Enviar condición de Start: Poner a nivel lógico 1 el bit SEN y esperar a que el controlador esté listo.
  2. Enviar la dirección del dispositivo: Escribir en el registro de salida SSPBUF y esperar a que el controlador esté listo. Opcionalmente, leer el bit ACK y comprobar que el esclavo responde.
  3. Enviar datos al dispositivo: Escribir en el registro de salida SSPBUF y esperar a que el controlador esté listo. Opcionalmente, leer el bit ACK y enviar más datos.
  4. Finalmente, enviar condición de Stop: Poner a nivel lógico 1 el bit PEN y esperar a que el controlador esté listo.

9. Características y Cronograma del Bus SPI

Las principales características del bus SPI son:

  • Es una interfaz de comunicación serie síncrona maestro/esclavo.
  • Necesita de 4 hilos:
    • SCLK: Señal de reloj serie, siempre generada por el maestro.
    • MISO: Línea de datos del esclavo al maestro (Master In, Slave Out).
    • MOSI: Línea de datos del maestro al esclavo (Master Out, Slave In).
    • CS (Chip Select) o SS (Slave Select): Señal de selección de chip para activar el periférico.
  • El maestro genera la señal de reloj del bus.
  • Los datos se transmiten y se reciben simultáneamente por dos hilos distintos, lo que lo convierte en un protocolo full-duplex.
  • A diferencia del bus I2C, los datos no tienen por qué transmitirse en grupos de 8 bits; pueden tener cualquier longitud.

En una aplicación típica con un convertidor A/D, por ejemplo, la señal SCLK del microcontrolador se conectaría a la entrada SCLK del convertidor, la señal MISO a la patilla DOUT del convertidor y la MOSI a la entrada DIN del convertidor.

Los protocolos serie como el SPI necesitan una señal auxiliar de chip-select (CS) para activar el periférico. Empleando esta señal de selección de chip, es posible conectar varios periféricos al mismo bus SPI en paralelo. Si se debe emplear una señal CS, puede generarse por una patilla sobrante del microcontrolador. Cada periférico conectado al bus necesita su propia señal CS.

Conversión Analógica-Digital y Periféricos

1. Funcionamiento de los Potenciómetros Digitales y Aplicaciones

Los potenciómetros digitales son muy útiles para controlar una variable analógica, como la ganancia de un circuito o el nivel de tensión, con precisión y sencillez. Sin embargo, presentan varios inconvenientes:

  • Su ancho de banda es limitado, por lo que no se pueden emplear para señales de gran ancho de banda, como audio y, sobre todo, RF.
  • No admiten tensiones mayores que la de su alimentación ni tensiones negativas. Si se incumplen estas normas, se obtendrá una señal recortada por los diodos de protección de que disponen estos integrados CMOS.

A pesar de estas limitaciones, son ampliamente utilizados en aplicaciones donde se requiere control digital de señales analógicas de baja frecuencia y tensión.

2. Pasos para una Conversión A/D con el Convertidor Integrado del PIC

Para obtener una conversión A/D con el convertidor integrado del PIC, se deben seguir los siguientes pasos:

  1. Configuración del módulo A/D:
    • Configurar los pines analógicos y las referencias.
    • Seleccionar el canal de entrada en ADCON0.
    • Seleccionar el tiempo de adquisición en ADCON2.
    • Seleccionar la frecuencia de conversión en ADCON2.
    • Conectar el módulo A/D en ADCON0.
  2. Configurar la interrupción de conversión (si se desea):
    • Bajar la bandera ADIF.
    • Poner a 1 el bit de máscara ADIE.
    • Poner a 1 el bit de interrupción global GIE.
  3. Esperar el tiempo de adquisición programado (si es necesario).
  4. Comenzar la conversión:
    • Poner a 1 el bit GO de ADCON0.
    • Esperar a que acabe la conversión de dos formas:
      • Muestreando el bit GO/DONE hasta que valga cero.
      • Esperando el disparo de la interrupción.
  5. Leer el resultado de la conversión en los registros ADRESH:ADRESL.
  6. Bajar la bandera ADIF si se están usando las interrupciones.
  7. Para la siguiente conversión, activar de nuevo el bit GO y esperar.

3. Empleo de un Convertidor A/D Externo por Bus I2C

Para emplear un convertidor A/D externo por bus I2C, lo primero que hay que hacer es configurarlo. Todos estos dispositivos disponen de una palabra de control que debe programarse con el modo de funcionamiento y las opciones de conversión antes de comenzar a enviar o recibir datos.

Los dispositivos suelen tener dos modos de funcionamiento:

  • Conversión continua: Permite realizar conversiones de forma ininterrumpida.
  • Conversión por disparo: Solo realiza la conversión cuando se programa para ello y luego vuelve al estado de reposo.

Para realizar una adquisición, se efectúa una escritura con la dirección del dispositivo en el bus I2C (ej. 1101000). Esto provoca el comienzo de la conversión. A continuación, se debe realizar un polling sobre el bit RDY hasta que la conversión haya terminado. Entonces, se realiza una lectura de los registros que contienen el valor de la conversión.

En cuanto a si todos los dispositivos se emplean del mismo modo, la respuesta es no. Aunque el principio general de configuración y lectura a través de I2C es similar, los registros específicos, las direcciones de control y los bits de estado (como RDY) pueden variar entre diferentes fabricantes y modelos de convertidores A/D externos. Por lo tanto, siempre es necesario consultar la hoja de datos (datasheet) del dispositivo específico.

4. Multiplexores Analógicos

Los multiplexores analógicos son simples llaves de paso CMOS que permiten realizar todo tipo de circuitos analógicos bajo control digital, empleando estas llaves de paso como simples interruptores controlados. Al igual que sucede con los potenciómetros digitales, las llaves de paso, al ser integrados CMOS, disponen de las entradas protegidas con diodos. Esto impide el empleo de estas llaves de paso o multiplexores con señales superiores al voltaje de alimentación e inferiores a cero.

Sin embargo, la tensión de alimentación de estos dispositivos puede ser tan alta como 30 voltios. Además, los dispositivos de la serie 405X disponen de la posibilidad de usar alimentación simétrica y señales de control compatibles TTL. De esta forma, el margen dinámico puede ser tan amplio como ±15V.

Sistemas de Tiempo Real (STR) y Planificación de Tareas

1. Diferencias entre STR de Tipo “Hard” y “Soft”

Los Sistemas de Tiempo Real (STR) se clasifican en dos tipos principales:

  • Los STR de tipo “hard” (duros) son estrictos, es decir, todas las acciones deben terminar dentro del plazo especificado. El incumplimiento de un plazo puede llevar a un fallo catastrófico del sistema.
  • Los STR de tipo “soft” (blandos) son flexibles, es decir, se pueden perder plazos de vez en cuando y el valor de la respuesta decrece con el tiempo. El incumplimiento de un plazo puede degradar el rendimiento, pero no necesariamente causar un fallo total.

2. Definición de STR

Un Sistema de Tiempo Real (STR) es un sistema operativo que debe ser capaz de proporcionar resultados correctos en los plazos de tiempo señalados. No implica necesariamente que sea rápido, sino que debe realizar sus tareas de manera predecible y dentro de los límites temporales establecidos para garantizar la funcionalidad y estabilidad del sistema.

3. Organización de Tareas mediante la Técnica de Primer Plano/Trasfondo

Para solucionar el problema de la falta de prioridades entre las tareas en un programa, es posible convertir las tareas de alta prioridad en interrupciones. Estas interrupciones tomarán el control de la CPU tan pronto como sea necesario, especialmente si solo se utiliza una interrupción.

Es muy probable que las tareas en el bucle principal (trasfondo) vengan disparadas por tiempo, utilizando la tasa de repetición del bucle como base de tiempo. Las tareas dirigidas por interrupciones (primer plano) es probable que vengan disparadas por eventos. Con esta estructura simple del programa, se logra una tasa de repetición fiable para las tareas del bucle, y además se priorizan las tareas que lo necesitan. Las tareas con mayor prioridad se ejecutan en el primer plano (cuando tienen que ejecutarse), mientras que las tareas de menor prioridad se ejecutan en el bucle de forma casi continua en segundo plano.

4. Estructura de un Programa Basado en un RTOS

Para satisfacer las necesidades de tiempo real, se utiliza un tipo particular de sistema operativo: el Sistema Operativo en Tiempo Real (RTOS). Un programa escrito para un RTOS está estructurado mediante tareas, generalmente (pero no siempre) por orden de prioridad, que son controladas por el sistema operativo.

El RTOS realiza tres funciones principales:

  • Decide qué tarea debe realizar y durante cuánto tiempo.
  • Proporciona comunicación y sincronización entre tareas.
  • Controla la utilización de los recursos compartidos entre las tareas, por ejemplo, la memoria y los periféricos de hardware.

Un RTOS en sí mismo es un programa de propósito general. Se adapta para una aplicación particular mediante la escritura de las tareas específicas y la personalización de la aplicación de varias maneras. Si bien es posible escribir un RTOS propio, es una actividad especializada y, en general, realizada por expertos.

5. Planificación Round-Robin y sus Carencias

En la planificación Round-Robin, el sistema operativo se ejecuta mediante una interrupción periódica, conocida como el tick de reloj. Las tareas son seleccionadas en un orden fijo para su ejecución. En cada tick de reloj, la tarea actual se suspende y se permite que la siguiente comience la ejecución. Todas las tareas se consideran de igual importancia y esperan en secuencia su “trozo de tiempo” de CPU.

A las tareas no se les permite ejecutarse hasta el final, sino que son interrumpidas (preempted), es decir, su ejecución se detiene en medio del proceso. Este es un ejemplo de un planificador pre-emptivo. Las implicaciones de esta conmutación de tareas pre-emptivas, y sus necesidades de recursos, no son despreciables y deben ser tenidas en cuenta. Cuando se permite a la tarea ejecutarse de nuevo, debe ser capaz de continuar el funcionamiento sin problemas, sin ningún efecto secundario debido a la planificación. Por lo tanto, se debe guardar el contexto completo (todas las banderas, registros y otras direcciones de memoria) cuando se realiza la conmutación de la tarea. Sin embargo, los elementos del programa que resultan críticos en cuanto a su temporización no deben ser interrumpidos, y este requisito tendrá que ser implementado en el programa.

6. Planificación Pre-emptiva con Prioridades y sus Ventajas

En el planificador pre-emptivo con prioridad, a las tareas se les asignan prioridades. Las tareas de alta prioridad están autorizadas a terminar antes que cualquier otra tarea de menor prioridad. El planificador sigue funcionando mediante un tick de reloj. En cada tick de reloj, comprueba qué tareas listas tienen la más alta prioridad, y estas son las que consiguen el acceso a la CPU.

Una tarea que se encuentre en ejecución y que todavía necesite tiempo de CPU, y sea de alta prioridad, mantiene la CPU. Una tarea de baja prioridad que se está ejecutando es sustituida por una de mayor prioridad en caso de que esta última haya pasado al estado de “lista”. La tarea de alta prioridad se convierte en la tarea que “se lleva el gato al agua” y, en casi todos los casos, prosigue su camino.

El texto describe un ejemplo con tres tareas de diferentes prioridades y tiempos de ejecución. La tarea de mayor prioridad (Tarea 1) se ejecuta primero hasta su finalización. Luego, la siguiente tarea de mayor prioridad (Tarea 3) se ejecuta hasta completarse. Finalmente, la tarea de menor prioridad (Tarea 2) tiene la oportunidad de ejecutarse, pero puede ser interrumpida si una tarea de mayor prioridad vuelve a estar lista. Esto asegura que las tareas críticas se completen a tiempo, incluso si otras tareas de menor prioridad se retrasan.

7. Programación de Tareas en un RTOS y Proceso de Estructuración

Las tareas en un RTOS deben escribirse como si se ejecutaran continuamente, como programas semiautónomos y autocontenidos, a pesar de que pueden ser interrumpidas por el planificador. No pueden llamar directamente a una sección de código de otra tarea, pero pueden tener acceso a código común, por ejemplo, a las librerías de C. Las tareas pueden depender de los servicios prestados por otras tareas y puede ser necesario sincronizarlas con otras tareas.

En casi todos los casos, el RTOS permite al programador establecer prioridades. Existen dos tipos principales de prioridades:

  • Prioridad estática: Las prioridades son fijas y no cambian durante la ejecución del programa.
  • Prioridades dinámicas: Las prioridades se pueden cambiar a medida que el programa se ejecuta.

Una forma de asignar prioridades es considerar la importancia de una tarea para el funcionamiento y buen comportamiento del sistema, su usuario y el entorno. Las prioridades pueden entonces asignarse de la siguiente manera:

  • Máxima prioridad: Tareas esenciales para la supervivencia del sistema.
  • Media prioridad: Tareas esenciales para la correcta operación del sistema.
  • Baja prioridad: Tareas necesarias para la adecuada operación del sistema. Estas tareas pueden ser ocasionalmente descartadas o un retraso en su conclusión podría ser aceptable.

8. Concepto de Inversión de Prioridades en un RTOS

La inversión de prioridades es una condición peligrosa que puede ocurrir en un RTOS. Se produce cuando una tarea de baja prioridad bloquea indirectamente a una tarea de alta prioridad. Esto sucede, por ejemplo, si una tarea de baja prioridad adquiere un recurso compartido (mediante un semáforo) que luego es requerido por una tarea de alta prioridad. La tarea de alta prioridad queda bloqueada esperando que la tarea de baja prioridad libere el recurso, invirtiendo así el orden de ejecución basado en prioridades.

9. El “Tick de Reloj” en un STR y su Empleo

El tick de reloj en un STR es básicamente una interrupción periódica en un sistema empotrado que ejecuta el planificador de tareas del sistema de tiempo real. De esta forma, se puede periódicamente cambiar de tarea. Esto lo realiza el planificador que, en cada “cuanto de tiempo” marcado por el tick de reloj, evalúa la tarea que está lista para ejecutar en función de su prioridad y de la evolución de las demás tareas en el sistema.

10. Uso de Semáforos en los STR

En un STR, varias tareas pueden necesitar acceder al mismo recurso compartido, ya sea hardware (memoria o periféricos) o un módulo de software común. Para gestionar este acceso y evitar conflictos, se utilizan los semáforos.

Se asigna un semáforo a cada recurso compartido, el cual se utiliza para indicar si está en uso. Existen dos tipos principales de semáforos:

  • Semáforo binario: Se utiliza para un único recurso. La primera tarea que necesita usar el recurso lo encuentra en un estado “VERDE” (disponible) y cambia su estado a “ROJO” (en uso) antes de comenzar a utilizar el recurso. Cualquier otra tarea que necesite el mismo recurso pasará al estado de bloqueada. Cuando la primera tarea ha completado el acceso al recurso, cambia el semáforo de nuevo a “VERDE”. Esto lleva al concepto de exclusión mutua, donde cuando una tarea está accediendo al recurso, todas las demás están excluidas.
  • Semáforo contador: Se emplea para un conjunto de recursos idénticos (por ejemplo, un grupo de impresoras). El semáforo se inicializa con el número de unidades del recurso. A medida que cada tarea utiliza una de las unidades, el semáforo se decrementa en una unidad, incrementándose de nuevo al final de su uso. Por lo tanto, el semáforo contador contiene el número de unidades que están disponibles para su uso.

Además de la gestión de recursos, los semáforos pueden utilizarse como un medio de proporcionar sincronización en el tiempo y señalización entre las distintas tareas. Una tarea puede bloquear a otra mediante el establecimiento de un semáforo y liberarla en un momento de su elección al poner a cero el semáforo. Sin embargo, el uso inadecuado de semáforos puede llevar a la peligrosa condición conocida como inversión de prioridades, donde una tarea de baja prioridad bloquea a una de alta prioridad al mantener un recurso necesario.

11. Funcionamiento del Planificador en un STR y Tipos Usados

Una parte central del RTOS es el planificador. Este determina a qué tarea se le permite ejecutarse en un determinado momento. Entre otras cosas, el planificador debe ser consciente de qué tareas están listas para ejecutarse y sus prioridades (si las tuvieran).

Los tipos de planificadores más usados en STR son:

  • Planificación cíclica: Las tareas se ejecutan en un ciclo predefinido y repetitivo.
  • Planificación Round-Robin: Las tareas se ejecutan en un orden fijo, cada una recibiendo un “cuanto de tiempo” de CPU antes de ser suspendida para dar paso a la siguiente.
  • Planificación pre-emptiva con prioridades: Las tareas con mayor prioridad pueden interrumpir la ejecución de tareas de menor prioridad para asegurar su finalización a tiempo.
  • Planificación Cooperativa: Las tareas ceden voluntariamente el control de la CPU al planificador cuando han terminado su trabajo o llegan a un punto de espera.