Diseñar una arquitectura de aplicación integrada



Buenas tardes Me gustaría hablar sobre la arquitectura de las aplicaciones integradas. Desafortunadamente, hay muy pocos libros sobre este tema, y ​​debido al hecho de que, recientemente, el interés en embebido e IoT está creciendo, quiero prestar atención a este tema. En este artículo, me gustaría describir una de las posibles opciones sobre cómo se pueden diseñar dichas aplicaciones.

Esta es una pregunta discutible! ¡Por lo tanto, ofrecen compartir su visión en los comentarios!
Para comenzar, determinaremos el área: en el marco de este artículo, por desarrollo integrado nos referimos al desarrollo de software para microcontroladores (en adelante MK, por ejemplo STM32) en C / Asm.
Los proyectos para sistemas basados ​​en MK se pueden dividir condicionalmente en aquellos que no requieren y requieren multitarea. En cuanto a las soluciones del primer tipo, generalmente no son muy complejas (desde un punto de vista estructural). Por ejemplo, un proyecto simple, en el que es necesario leer datos del sensor y mostrarlos en la pantalla, no requiere multitarea, es suficiente para implementar la ejecución secuencial de las operaciones anteriores.



Si la aplicación es más compleja: dentro del marco del cual es necesario leer datos de sensores digitales y analógicos, guarde los valores obtenidos en la memoria (por ejemplo, en una tarjeta SD), mantenga la interfaz de usuario (pantalla + teclado) y proporcione acceso a los datos a través de una interfaz digital (por ejemplo, RS-485 / Modbus o Ethernet / TCP / IP) y reacciona lo más rápido posible a ciertos eventos en el sistema (presionar botones de emergencia, etc.), entonces en este caso será difícil hacerlo sin multitarea. Hay dos formas de resolver el problema de la multitarea: implementarlo usted mismo o utilizar algún tipo de sistema operativo (en lo sucesivo, el SO). Hoy, uno de los sistemas operativos en tiempo real más populares para sistemas embebidos es FreeRTOS.

Tratemos de imaginar cómo debería ser la arquitectura de una aplicación integrada "compleja" que realiza una cantidad bastante grande de operaciones heterogéneas. Admito que es posible proponer una opción aún más complicada, que implica resolver problemas de procesamiento de sonido, criptografía, etc., pero nos detendremos en la opción que se describió anteriormente.

Establecemos la tarea más claramente, incluso si dentro del marco de nuestra aplicación es necesario:

  • Lea los datos de los sensores en el RS-485 / Modbus.
  • Lea los datos de los sensores en el bus I2C.
  • Leer datos de entradas digitales.
  • Salida de relé de control.
  • Mantener la interfaz de usuario (pantalla + teclado).
  • Proporcione acceso a los datos a través de RS-485 / Modbus.
  • Guardar datos en medios externos.

Porque necesitamos implementar un número suficientemente grande de subtareas diferentes, usaremos el sistema operativo en tiempo real (por ejemplo, el FreeRTOS ya mencionado) como base. Los hilos en el sistema operativo a veces se denominarán tareas, similar a FreeRTOS. Quiero advertirle de inmediato: no habrá código fuente en el artículo, lo que interesa es el aspecto arquitectónico de este tema.

Si analizamos la tarea, podemos ver que diferentes componentes del sistema usan los mismos datos. Por ejemplo: los datos de los sensores deben obtenerse, mostrarse en una pantalla, escribirse en un medio y proporcionarse a sistemas externos para su lectura. Esto sugiere que se necesita algún tipo de base de datos en tiempo real (RTDB) para almacenar y proporcionar los datos más relevantes a varios subsistemas.

Las tareas realizadas en el sistema (lectura de datos, escritura, visualización, etc.) pueden tener diferentes requisitos para la frecuencia de su llamada. No tiene sentido actualizar los datos en la pantalla con una frecuencia de 1 vez por 100 ms, porque Esto no es crítico para una persona, pero a menudo es necesario leer los datos de los sensores (especialmente si es necesario dar acciones de control sobre ellos) (aunque puede no ser posible dependiendo de los conocimientos tradicionales). Otro punto importante está relacionado con la resolución del problema de acceso a los mismos datos para leer y escribir. Por ejemplo: un flujo que interroga a los sensores escribe los valores recibidos en RTDB, y en este momento el flujo responsable de actualizar la información en la pantalla los lee. Aquí, los mecanismos de sincronización que proporciona el sistema operativo nos ayudarán.

¡Comencemos a diseñar la arquitectura de nuestra aplicación!

Base de datos en tiempo real




Una estructura ordinaria que contiene el conjunto necesario de campos o una matriz puede servir como tal base. Para acceder a "RTDB" utilizaremos la API, que nos permitirá escribir y leer datos de la base de datos. La sincronización del acceso a datos dentro de las funciones de la API se puede construir en los mutexes proporcionados por el sistema operativo (o utilizar algún otro mecanismo).



Trabajando con sensores en los neumáticos


Trabajar con sensores implica lo siguiente:

  • lectura de datos;
  • procesamiento de datos (si es necesario), que incluye:
    • verificación de validación;
    • escalado
    • filtrado
    • validación de valores válidos;

  • grabación de datos recibidos en RTDB.

Todo este trabajo se puede hacer en una sola tarea.



"Puerto" - el puerto real de MK;
"Controlador de protocolo": controlador de protocolo (por ejemplo, Modbus). Para tal controlador, es aconsejable hacer su interfaz y trabajar a través de ella. Dentro del marco de dicha interfaz, es posible implementar el control de acceso al recurso a través de mutexes, como se hizo para "RTDB". Algunos desarrolladores proponen hacer esto a nivel de puerto, para asegurarse de que nadie más escriba nada en este puerto mientras transmitimos nuestros paquetes Modbus a través de él.
"Lector de sensores": una tarea (tarea) que sondea los sensores, ordena la información recibida y la escribe en "RTDB".

"RTDB" es la base de datos en tiempo real descrita anteriormente en la sección correspondiente.
La inscripción "Pr: 1" sobre la tarea significa prioridad, la conclusión es que cada tarea puede tener prioridad si dos tareas que esperan el tiempo del procesador tienen prioridades diferentes, el recurso recibirá el que tenga la prioridad más alta. Si las tareas tienen la misma prioridad, se iniciará la que tenga el mayor tiempo de espera.

Trabaja con entradas discretas


En general, el trabajo con entradas digitales se puede organizar de la misma manera que con los sensores digitales. Pero puede ser necesario responder rápidamente a los cambios en el estado de las entradas. Por ejemplo, con solo tocar un botón, cierre la salida del relé lo más rápido posible. En este caso, es mejor usar el siguiente enfoque: para procesar la salida del relé, creamos una tarea especial por separado con una prioridad más alta que el resto. Dentro de esta tarea hay un semáforo que intenta capturar. Se activa una interrupción para activar una entrada digital particular, en la que se restablece el semáforo mencionado anteriormente. Porque la prioridad de interrupción es máxima, entonces la función asociada con ella se ejecutará casi instantáneamente, en nuestro caso, restablecerá el semáforo y, después de eso, la siguiente tarea en la cola de ejecución será aquella dentro de la cual se controla el relé (porque tiene la prioridad es mayor que otras tareas y se elimina el bloqueo al esperar el semáforo).
Así es como puede verse el esquema de este subsistema.



Además de la respuesta rápida para cambiar el estado de una entrada específica, también puede configurar la tarea "Lector DI" para leer el estado de las entradas discretas. Esta tarea puede ser independiente o llamada por temporizador.

A continuación se presenta el trabajo del "controlador de interrupciones" y el "controlador de relé" en forma de diagramas.



Escribir datos en medios externos


Escribir datos en un medio externo es ideológicamente muy similar a leer datos de sensores digitales, solo el movimiento de datos se lleva a cabo en la dirección opuesta.



Leemos desde "RTDB" y escribimos a través del "controlador de la tienda" en un medio externo; puede ser una tarjeta SD, una unidad flash USB u otra cosa. De nuevo, ¡no olvide poner envoltorios de mutex (o cualquier otra herramienta para organizar el acceso al recurso) en las funciones de la interfaz!

Proporcionar acceso a datos en tiempo real.


Un punto importante es la provisión de datos de "RTDB" a sistemas externos. Puede ser casi cualquier interfaz y protocolo. A diferencia de una serie de subsistemas considerados, la diferencia clave de esto es que algunos de los protocolos ampliamente utilizados en los sistemas de automatización tienen requisitos especiales para el tiempo de respuesta a la solicitud, si la respuesta no llega dentro de un cierto tiempo, entonces se considera que no hay comunicación, incluso si él (la respuesta) vendrá después de un tiempo. Y desde El acceso a "RTDB" en nuestro ejemplo puede estar bloqueado temporalmente (por mutex), es necesario proporcionar protección para el dispositivo maestro externo (el maestro es un dispositivo que intenta leer datos nuestros) de dicho bloqueo. También vale la pena considerar la protección del dispositivo del hecho de que el maestro lo interrogará con alta frecuencia, inhibiendo así la operación del sistema mediante la lectura constante de "RTDB". Una solución es usar un tampón intermedio.



El "Actualizador de datos" lee los datos de "RTDB" a una frecuencia dada y suma lo que lee en el "Caché de protocolo", del cual el "controlador de protocolo" recogerá los datos. En este caso, existe un problema de bloqueo en el nivel de caché de protocolo, para resolverlo, puede crear otro caché en el que el "controlador de protocolo" almacenará datos en caso de que no pueda leer desde el "caché de protocolo" bloqueado, además puede:
- hacer del "controlador de protocolo" una prioridad más alta;
- aumente el período de lectura de "RTDB" para "Actualizador de datos" (que es una solución regular).

Trabaja con interfaz de usuario


Trabajar con la interfaz de usuario implica actualizar los datos en la pantalla y trabajar con el teclado. La arquitectura de este subsistema puede verse así.



El trabajador de UI es responsable de leer las pulsaciones de teclas, tomar datos de "RTDB" y actualizar la pantalla que ve el usuario.

Estructura general del sistema


Ahora eche un vistazo a lo que sucedió al final.



Para equilibrar la carga, puede configurar cachés adicionales, como lo hicimos en el subsistema responsable de proporcionar acceso a estos sistemas externos. Algunas tareas de transferencia de datos se pueden resolver mediante colas, ya que generalmente son compatibles con sistemas operativos en tiempo real (por supuesto, en FreeRTOS).
Eso es todo, espero que haya sido interesante.

PS
Como literatura, recomendaría "Hacer sistemas embebidos: Patrones de diseño para un gran software" Elecia White y artículos de Andrey Kournits "FreeRTOS: un sistema operativo para microcontroladores"

Source: https://habr.com/ru/post/es419717/


All Articles