¿Necesita un código de autocomprobación dentro de los módulos de firmware integrados?

Tengo una pregunta sobre el código de autocomprobación dentro de un módulo de firmware. Desarrollé el código, y estaba en ruinas, y tampoco tenía idea de la arquitectura del firmware. Más tarde encontré excelentes artículos sobre la arquitectura de firmware, por ejemplo, Desarrollando una arquitectura de firmware flexible , y pusieron énfasis en modularizar su firmware en módulos.

Tengo el firmware con los módulos asociados:

  1. módulo_adc
  2. Módulo EEPROM
  3. Módulo SPI
  4. Módulo Algorithm1
  5. Módulo de algoritmo

No tengo un RTOS aquí, y encontré la inclusión de un código de prueba dentro de cada firmware dentro de esos artículos: D. Bueno, estoy trabajando en microcontroladores PIC de 8 bits y me gustaría saber si estoy disparando por encima de la cabeza o en el camino correcto.

Me gustaría recibir sus sugerencias para la 'inclusión del código de autocomprobación'. Y si lo necesito, ¿qué tipo de funciones realizan dentro de los módulos?

¿Por qué no tener un andamio de prueba para cada módulo y luego cargarlos en el dispositivo por separado y probar?
así que debería cargar el andamio solo para probar, ¿verdad?
Debe cargar el andamio solo cuando pruebe el módulo para el que está escrito. El producto final solo debe tener suficiente código para probar lo que no pudo probar en los módulos individuales, así como las comprobaciones básicas de cordura.
Escribí una respuesta en Stack Overflow sobre este tema. Incluye una estrategia de prueba muy simple: stackoverflow.com/questions/21215172/…

Respuestas (2)

Me gusta pensar que el firmware de prueba asume tres roles diferentes durante la vida útil de un producto.

Cuando se entrega por primera vez una PCB para un nuevo diseño, es necesario tener programas de firmware individuales para probar cada componente por separado del sistema. Cada uno de estos son programas independientes y se cargan en el microcontrolador individualmente según sea necesario. Siempre empiezo probando uno de los UART, ya que esta será la forma en que se entregarán los resultados de todas las demás pruebas. (Incluso si hay una pantalla LCD en el sistema, es mucho más complicada de activar que un UART, que es parte integral del microcontrolador y lo único que puede salir mal es un error en el diseño de la PCB).

Si es posible, me gusta tener un UART dedicado en el sistema solo para depurar la salida. generalmente llevado a un encabezado que se puede marcar DNP (no colocar) en producción. Si uno tiene que compartir el puerto de depuración con otras funciones, se deben hacer algunos compromisos.

En un proyecto reciente, tuve un firmware de prueba para verificar los rieles de voltaje, un módulo de celda, un módulo Bluetooth, una interfaz de tarjeta SD, un circuito de audio (DAC + EEPOT), un teclado, una pantalla LCD, interrupciones externas y una expansión de puerto paralelo. En el camino, estos verificaron todos los buses SPI e I2C en el sistema.

Por lo general, una PCB pasará por varias revisiones. A veces, el circuito se cambiará, a veces no (solo problemas de diseño). Creo un directorio para cada revisión por separado, por ejemplo, RevA, RevB, etc. y hago una copia completa de todos los archivos a medida que avanzo en caso de que los pinouts hayan cambiado y tenga que hacer cambios menores en el firmware.

Una vez que la placa comienza a fabricarse, combino todo el firmware de prueba en un solo programa, junto con un controlador que luego se instala en el microcontrolador y el fabricante contratado lo usa para probar cada PCB después de ensamblarla. Una vez que la placa ha pasado todas las pruebas, el firmware de prueba se reemplaza por el firmware de producción.

El último lugar donde se puede incluir el firmware de prueba es parte del programa de producción. Tiendo a no hacer esto, ya que muchas pruebas, como el teclado, la pantalla LCD y el audio, requieren la participación del usuario, y otras pruebas, como el celular y el Bluetooth, requieren un entorno controlado. Todavía podría ser útil, por ejemplo, probar todos los rieles de voltaje en el arranque. En un proyecto, una placa bastante compleja tenía 12 rieles de voltaje diferentes (seis solo para la pantalla LCD).

Mi enfoque habitual para esto es incluir un procesador de comandos en el firmware que se comunica a través de un flujo bidireccional de bytes a un host, generalmente utilizando el UART. La mayoría de los proyectos incluyen comunicación con un host, por lo que a menudo necesitará este código de todos modos. En algunos casos, no hay conexión de host en el sistema final. En función de los recursos disponibles, puede incluir el código del procesador de comandos en el firmware solo cuando los conmutadores de depuración en tiempo de compilación lo habiliten.

Por ejemplo, estoy trabajando en un proyecto en este momento que funcionará con baterías y se comunicará con el resto del mundo a través de MiWi usando solo radios 802.15. Como tenía espacio en el tablero, incluí almohadillas para conectar a las líneas UART. En la producción final, este conector no se completará, por lo que no agrega ningún costo adicional. Dado que el consumo de energía es muy importante en el producto final, la interfaz UART solo se habilita si un interruptor de tiempo de compilación para ese propósito está configurado en modo de depuración. Sin ese interruptor configurado, el UART nunca se enciende y el código ni siquiera está vinculado.

Tener una forma simple de habilitar/deshabilitar la interfaz UART opcional es útil incluso después de que se haya depurado el firmware. En algún momento en el futuro, es posible que sea necesario agregar funciones o realizar otras modificaciones. La interfaz UART volverá a ser útil para el desarrollo y las pruebas. De esta manera, solo se necesita cambiar un solo "falso" a "verdadero" para habilitarlo, y no es necesario tener que averiguar de nuevo cómo vincular el código, agregar los ganchos en los lugares correctos, inicializar el UART. , etc.

Una vez que tengo un flujo bidireccional de bytes a un host, generalmente uso un protocolo de paquete simple. Cada paquete comienza con un byte de código de operación, seguido de cualquier byte de datos especificado para ese código de operación. Llamo "comandos" a los paquetes del host a la unidad, y "respuestas" a los de la unidad al host, pero las respuestas no se envían necesariamente como respuesta directa a los comandos.

Este tipo de protocolo de datos de código de operación es fácil de analizar en el microcontrolador (cuán fácil o no es en una PC es irrelevante, pero también es fácil allí). El byte del código de operación se indexa en una tabla de despacho, lo que hace que se ejecute una rutina específica para ese código de operación. Las rutinas de comando luego obtienen los bytes de datos del comando, ejecutan el comando y luego regresan al ciclo de despacho principal. Este ciclo generalmente se ejecuta en una tarea separada, por lo que parece ejecutarse de forma asincrónica e independiente de otras cosas en el sistema.

El conjunto de comandos, por supuesto, incluye comandos para hacer que el sistema realice las funciones previstas, pero también un montón de comandos de depuración que no se usan en el sistema final. Estos son utilizados por un programa de prueba en el host para permitir la prueba de partes de bajo nivel del firmware.

Por ejemplo, en el proyecto MiWi que mencioné anteriormente, el código MiWi enlatado necesita leer y escribir en la EEPROM interna a través de una interfaz definida que debo proporcionar. Para probar esa interfaz por separado, agregué comandos para leer y escribir ubicaciones de EEPROM. Usando esos comandos, probé y verifiqué la interfaz EEPROM de bajo nivel. Encontrar errores en eso más tarde a partir de síntomas extraños de MiWi habría sido mucho más difícil.

Hago esto con tanta frecuencia que tengo plantillas tanto para el procesador de comandos en el firmware como para el programa de prueba en el host. Normalmente reservo el código de operación 0 como NOP, 1 para PING y 2 para FWINFO. PING solo responde con PONG, que también es una respuesta de un solo byte. Eso puede ser útil para probar el enlace de comunicación. FWINFO hace que se envíe la respuesta FWINFO, que proporciona el tipo de firmware, la versión y los números de secuencia. Otros comandos se agregan desde allí.

A veces ha sido útil tener comandos para operaciones de bajo nivel disponibles en el sistema final, aunque esto no estaba en la especificación. Estas cosas pasan. Más de una vez, tener un nuevo software capaz de leer y escribir EEPROM directamente en las unidades de campo existentes, por ejemplo, ha ahorrado muchos problemas. La gente del software generalmente se burla de los comandos adicionales al principio, luego están realmente agradecidos un año después cuando les salva el trasero.