A menudo, desea una forma de cambiar los valores de los parámetros sin volver a compilar el código fuente.
Como resultado de nuestra escasez de mano de obra, recientemente decidimos subcontratar un diseño electrónico simple, que incluye hardware y software. Escribí una especificación y el diseñador no sabía lo que yo quería, así que lo que pensé que era conocimiento común resultó ser completamente ignorado. Él puede haber preguntado, pero esa es otra historia. Justo cuando pensaba “si un técnico joven no tiene ese conocimiento, puede haber otros”, sentí que el blog comenzaba (debería haberme acostado en su lugar).
Al escribir software, casi siempre usa constantes para determinar cuántas veces se ejecuta un ciclo, cuánto tiempo debe esperar antes de habilitar una salida, etc. En un programa C simple, estas constantes son #define
Una macro de la forma:
#define WAIT_TIME_BEFORE_ACTIVATING_SOLENOID 4000 //time in mS
Puede existir una lista completa de estas constantes. Si desea cambiar algo, simplemente vaya a la definición de macro, cambie el valor y vuelva a compilar. Eso es algo bueno, pero a menudo los usuarios quieren cambiar el rendimiento de su sistema, pero no tienen el conocimiento ni los recursos para hacerlo, y mucho menos liberar el código fuente al dominio público. . Lo que necesito es una forma de cambiar los valores de los parámetros sin volver a compilar el código fuente.
Piense en los parámetros que se pueden cambiar en un automóvil moderno. Puede programar cuánto tiempo permanecen encendidas las luces después de cerrar el automóvil. Puede habilitar/deshabilitar el sensor de proximidad. Y se pueden cambiar de docenas a cientos más dependiendo de la sofisticación del automóvil. Los sistemas modernos generalmente permiten cambiar estos parámetros mediante una interfaz de usuario o alguna descarga a través de un canal de comunicación. Obviamente, estos parámetros deben residir en la memoria reconfigurable. Puede ser RAM, pero la mayoría es EEPROM o flash configurado para comportarse como EEPROM.
Declarando una constante en C como esta:
const uint16_t iVariable1 = 45;
const uint16_t iVariable2[4]= {45,46,47,48};
La mayoría de los compiladores los agrupan y colocan los datos resultantes en algún lugar de la memoria flash. No creo que haya ninguna garantía de que sean adyacentes. En los micros que no tienen EEPROM dedicadas, no toda la memoria flash se puede tratar como EEPROM, por lo que generalmente hay una instrucción para el compilador para tratar algún espacio de memoria como EEPROM. Por ejemplo, en Cypress PSoC4 con el compilador Keil, la instrucción sería:
const uint8_t EmEEPROM_em_EepromStorage[EmEEPROM_PHYSICAL_SIZE] __ALIGNED(CY_FLASH_SIZEOF_ROW) = {0u};
Pero los procesadores y compiladores son diferentes.
Para asegurarse de que todos los elementos en la EEPROM sean contiguos (veremos por qué en un momento), cree una sola matriz (o quizás una estructura) como hicimos en la declaración de PSoC4.
uint8_t eepromArray[48];
y, enum
o establecer #defines
que identifica qué elemento de la matriz está asociado con un parámetro en particular.
Bueno, en los días en que construíamos microcontroladores en dispositivos de seguimiento de dinosaurios. En aquel entonces, no había EEPROM para empezar. Más tarde, la EEPROM estuvo disponible en forma de dispositivos externos. Aún así, el cliente quería cambiar los parámetros sin volver a compilar.
Los sistemas de desarrollo eran engorrosos y, a menudo, un equipo que requería un programador PROM independiente (ya menudo portátil). La técnica consistía en crear la tabla en una EPROM (ya sea externa o integrada en la microcomputadora) como parte del programa utilizando algunas de las técnicas anteriores. Los clientes pueden usar el programador de EPROM para leer el código binario del IC maestro o del dispositivo de destino, navegar a las ubicaciones de las tablas y cambiar los números presentes, y reprogramar todo el shebang en una EPROM vacía. Luego, vuelva a conectar la EPROM al zócalo de destino. No se requiere ensamblar, vincular, cargar o compilar programas.
Los enlaces y ubicaciones de varios módulos formaban parte de la línea de comandos (y se podían ingresar desde un archivo por lotes), y había una buena cantidad de documentación sobre cómo colocar diferentes partes de la memoria en diferentes ubicaciones. Si estuviera usando memoria externa o dispositivos de partición de memoria, estas asignaciones podrían ser bastante grandes. Para bien o para mal, esta característica se ha sublimado y los detalles no están fácilmente disponibles como parte de las interfaces de usuario modernas.
Para sistemas pequeños, esta antigua técnica aún puede ser la única forma de implementar la capacidad de configuración del cliente. En el proyecto que inspiró este blog, un cliente solicitó una reconfiguración tabular y un subcontratista interpretó la “mesa” como una serie. #defines
recompilando.
usando const
Declarar es fácil. El problema es la posición de la mesa. Es posible extraer la ubicación exacta en la memoria del informe de compilación (nuevamente, cada procesador/compilador puede ser diferente), pero la ubicación puede variar de una iteración de compilación a otra. La idea de usar una ubicación fija tiene muchas recomendaciones. Tengo una idea bastante buena de cómo abordar esto con un microcontrolador PSoC, pero el procesador en el proyecto mencionado anteriormente es un Microchip Atmega328. Eso significa que tienes un gran problema. No tengo ni idea.
hay varios discusión en línea Acerca de implementar esto en Atmega. Dado que el dispositivo en realidad tiene una EEPROM, podría ser igual de fácil colocar una tabla allí, pero solo es útil si sus herramientas de desarrollo le permiten cambiar los valores de la EEPROM o la memoria del programa. El tiempo dirá.
Algunos dispositivos de misión crítica tienen rutinas que verifican las sumas de verificación de la memoria para garantizar que la memoria del programa esté limpia. En este caso, el cálculo de la suma de comprobación debe excluir el ajuste fino de la tabla.
Los parámetros de ajuste que afectan el rendimiento del software pueden revelar u ocultar fallas en el programa. Pero el hecho de que pueda cambiar el rendimiento no garantiza que el software esté libre de errores. Una vez tuve un jefe que luchó con este delirio. Solo duré tres meses en el trabajo.
Posdata
Tras el rediseño, el subcontratista optó por colocar las tablas en EEPROM. Atmel Studio 7 parece poder acceder a la EEPROM, pero el contenido no se muestra como una tabla en la pantalla. El proceso empleado por el subcontratista fue usar Atmel Studio 7 (que se ejecuta en una PC) para leer el contenido de la EEPROM en un archivo hexadecimal, editar el contenido del archivo hexadecimal y crear una nueva suma de verificación para cada línea cambiada. , crear un archivo y vuelva a escribir el archivo en la EEPROM. También deberá cambiar algunos de los “interruptores” internos del micro para acceder a la EEPROM antes de volver a la operación estándar. Esto parece un poco complicado, espero encontrar una forma más elegante.
Posdata
Probé PSoC Programmer para ver si podía cambiar los bytes directamente desde la interfaz de usuario (UI). No tiene que cambiar la configuración de programación en el micro, pero desafortunadamente editar el archivo hexadecimal anterior requiere la misma técnica.
Este concepto completo de tabla probablemente no funcionará en el futuro ya que requiere una buena interfaz de programador. O puede que tenga que invertir en un programador de terceros con una interfaz de usuario decente (si tal bestia todavía existe).