← Índice del curso

Sistemas Embebidos · Tema 51 · Bloque 11

Proyecto integrador

Cincuenta temas dieron las piezas; este las junta. Construimos de punta a punta el registrador de temperatura para la cadena de frío que viene acompañando al bloque de diseño: sus requisitos (tema 48), su arquitectura (tema 49) y ahora su firmware, con sensores, máquina de estados, tareas, bajo consumo, watchdog, registro en flash y actualización segura. Lo más valioso de un proyecto integrador no es escribir más código sino descubrir lo que solo aparece cuando todo trabaja junto: la energía que el presupuesto no contó, la zona de alerta que resulta demasiado angosta para una pendiente rápida, el watchdog cuya cuenta corre desde la última medida y no desde el cuelgue, la marca de actualización que debe grabarse al final. Para verlo, simulamos el equipo completo tres días, a un paso de un segundo, y comprobamos sus requisitos uno por uno.

01 · El punto de partida

El proyecto y sus requisitos

El producto es un registrador de temperatura que viaja dentro de un contenedor refrigerado. Mide la temperatura, guarda un historial, avisa por radio si se sale de rango y se actualiza por el aire. Los requisitos son los del tema 48, en una versión resumida y con identificador:

Requisitos del registrador y cómo se verificará cada uno.
IdRequisitoVerificación
R-1El registrador debe funcionar al menos 2 años con 2 pilas AA de 1875 mAh (objetivo de diseño: 3 años, margen de 1,5).Análisis con el consumo medido de cada modo (tema 36)
R-2Cuando la temperatura supere 8 °C, el registrador debe transmitir una alarma en menos de 5 s.Prueba en el banco con una rampa de temperatura (tema 47)
R-3El registrador debe reportar su estado al menos cada 15 minutos.Prueba en simulación y en el banco
R-4Si el programa se cuelga, el registrador debe recuperarse sin intervención y no pasar más de 300 s sin medir.Prueba con cuelgue provocado desde el modo de prueba
R-5Si el sensor no responde, el registrador debe informarlo en menos de 120 s.Inyección de falla del sensor
R-6El registrador debe poder actualizarse por radio sin quedar inutilizable aunque se corte la energía en cualquier instante.Corte de energía en cada paso de la actualización (tema 47)
R-7El registrador debe guardar 30 días de medidas, sobreviviendo a cortes de energía.Prueba del registro circular con cortes (tema 41)

El registrador tiene cuatro modos de operación (tema 48): activo (mide cada 60 s y reporta cada 15 min), alarma (mide cada 2 s y reporta cada minuto), falla (el sensor no responde) y los modos de almacenado y de descarga (antes de la activación y al llegar), que dejamos fuera de la simulación para centrarnos en el viaje. Las hipótesis de energía son las del tema 48: sueño de 2,0 µA, 3 mA durante 20 ms para medir, 4 mA durante 5 ms para calcular y 28 mA durante 400 ms para cada reporte de radio, sobre dos pilas de 1875 mAh con el 80 % utilizable y 5,70 µA de autodescarga.

02 · Todo junto

La arquitectura integrada

La arquitectura que sale de los temas 48 y 49 es dirigida por eventos: casi todo el tiempo el microcontrolador duerme; lo despiertan el reloj de tiempo real (para medir y reportar), la radio (al terminar de enviar o al recibir) y el botón. Cada fuente solo deposita un evento en una cola; un único bucle de aplicación los procesa de a uno, y cuando no queda ninguno, vuelve a dormir.

Flujo de eventos del registrador A la izquierda, tres fuentes de eventos: el reloj de tiempo real, la radio y el botón. Cada una deposita eventos en una cola de eventos. La cola alimenta el módulo de aplicación, que contiene la máquina de estados. La aplicación usa los módulos sensor, registro en flash, protocolo de radio y energía, y alimenta al watchdog después de cada medida. Cuando no hay eventos, la energía lleva al microcontrolador a dormir. Reloj (RTC)RadioBotón Cola deeventos Aplicaciónmáquina de estadosactivo · alarma · fallazona de alerta SensorRegistro (flash)Radio y protocoloEnergía Watchdogse alimenta tras cada medida Dormirsin eventos

Dos propiedades de este diseño importan para todo lo que sigue. Primera: la lógica del producto corre en un solo contexto (el bucle de aplicación), así que casi no hay condiciones de carrera sobre sus datos (tema 46); las interrupciones solo encolan. Segunda: el reposo es el estado por defecto y todo consumo extra se debe a eventos reales, sin un tick periódico (tema 49). El presupuesto de memoria (73 KB de flash y 10 KB de RAM con margen) y la elección del microcontrolador de 128 KB con la imagen de respaldo en la flash externa también vienen de aquel tema.

03 · El código

El esqueleto del firmware

El punto de entrada es corto a propósito: inicializa en un orden que importa, y entra en el bucle de eventos. Todo lo demás está en los módulos del tema 49.

/* main.c: inicialización y bucle de eventos del registrador */
int main(void) {
    hal_iniciar();                                  /* relojes, pines, RTC (capa 0) */
    causa_reinicio_registrar();                     /* ¿arranque normal, watchdog, caída de tensión? (tema 37) */
    wdt_iniciar(WDT_PLAZO_S);                       /* el watchdog se arma temprano, con un plazo de 120 s */
    registro_iniciar();                             /* recupera el registro circular tras un corte (tema 41) */
    sensor_iniciar();
    radio_iniciar();
    arranque_confirmar_si_corresponde();            /* si es la primera vez de una versión nueva, la confirma (sección 7) */
    app_iniciar();                                  /* estado inicial y primera medida */

    for (;;) {
        Evento e;
        if (evento_tomar(&e)) { app_procesar(&e); }
        else                  { energia_dormir(); }                 /* sin eventos: reposo profundo hasta la próxima interrupción (tema 35) */
    }
}

/* app.c: la máquina de estados reacciona a los eventos; las interrupciones solo los publicaron */
void app_procesar(const Evento *e) {
    switch (e->tipo) {
        case EV_MEDIDA:        app_medir();                break;     /* el RTC despierta cada 60 s (cada 2 s en la zona de alerta) */
        case EV_REPORTE:       app_reportar_periodico();   break;     /* cada 15 min (cada minuto en alarma) */
        case EV_RADIO_FIN:     radio_apagar();             break;
        case EV_BOTON:         app_atender_boton();        break;
        case EV_ACTUALIZACION: arranque_proceso_fragmento(e->dato); break;
        default:               contador_eventos_desconocidos++; break;  /* un evento imposible se cuenta, no se ignora (tema 39) */
    }
}

Algunas decisiones que el esqueleto hace visibles. El watchdog se arma antes que lo demás, para que cubra también las inicializaciones lentas. La causa del reinicio se registra apenas arranca, antes de que se pierda. El caso default del switch cuenta los eventos que no esperaba en lugar de descartarlos en silencio. Y el bucle principal no tiene esperas activas: o procesa un evento o duerme, que es lo que permite los 2,0 µA de reposo.

04 · El corazón del producto

Sensores, estados y lógica de alarma

La medida cruda del sensor pasa por tres pasos antes de convertirse en una decisión: validar (¿respondió?, ¿está en rango físicamente posible?), convertir a unidades con signo y resolución fija (centésimas de grado, en un entero de 16 bits) y evaluar contra el límite. La evaluación implementa dos ideas del tema 48: la histéresis (la alarma se activa por encima de 8,00 °C y se desactiva recién por debajo de 7,50 °C, para no parpadear en el límite) y la zona de alerta (cuando la temperatura se acerca al límite, se mide cada 2 s en lugar de cada 60 s).

#define LIM_ALTO_C     800      /* 8,00 °C en centésimas de grado */
#define HIST_C          50      /* se desactiva por debajo de 7,50 °C */
#define ZONA_C         300      /* 3,00 °C = pendiente máxima (0,05 °C/s) x 60 s entre medidas lentas */
#define MED_LENTA_S     60u
#define MED_RAPIDA_S     2u
#define REP_NORMAL_S   900u
#define REP_ALARMA_S    60u

static bool    alarma;
static uint8_t fallas_seguidas;

void app_medir(void) {
    int16_t t;                                           /* centésimas de grado */
    if (!sensor_leer(&t)) {                              /* el sensor no respondió o dio un valor imposible */
        if (++fallas_seguidas == 1u) { radio_enviar_falla(); }              /* se informa en la primera falla (R-5) */
        energia_programar_medida(MED_LENTA_S);
        wdt_alimentar();                                 /* el programa sigue vivo aunque el sensor no */
        return;
    }
    fallas_seguidas = 0u;
    registro_agregar(&(Muestra){ ahora_s(), t, estado_actual() });

    if (!alarma && t > LIM_ALTO_C) {                     /* cruzó el límite */
        alarma = true;  radio_enviar_alarma(t);  energia_programar_reporte(REP_ALARMA_S);
    } else if (alarma && t <= LIM_ALTO_C - HIST_C) {  /* volvió con histéresis */
        alarma = false; energia_programar_reporte(REP_NORMAL_S);
    }
    bool rapido = alarma || (t >= LIM_ALTO_C - ZONA_C);   /* cerca del límite: medir seguido */
    energia_programar_medida(rapido ? MED_RAPIDA_S : MED_LENTA_S);
    wdt_alimentar();                                     /* latido: solo si la cadena de medida terminó */
}

El tamaño de la zona de alerta no es un número arbitrario: es lo que la temperatura puede subir entre dos medidas lentas. Con una pendiente máxima de 0,05 °C/s (un supuesto que hay que confirmar con datos reales), en 60 s sube 3 °C, de modo que la zona debe ser de al menos 3 °C. Con menos, existe una fase desfavorable en la que una medida cae justo por fuera de la zona y la siguiente, 60 s después, ya encuentra la temperatura por encima del límite. La Parte 2 del programa y el laboratorio lo muestran con una excursión de la temperatura de 4 a 12 °C que empieza 30 s después de una medida lenta (la fase que hace daño):

Excursión de temperatura, zona de alerta y requisito R-2 (resultado de la Parte 2; tres días simulados).
ExcursiónZona de alertaLatencia de la alarmaR-2 (5 s)Corriente mediaVida
Lenta (0,01 °C/s)2 °C0,405 sCumple19,82 µA6,71 años
Lenta (0,01 °C/s)Ninguna (medir cada 60 s)56,405 sNo cumple19,72 µA6,74 años
Rápida (0,05 °C/s)2 °C10,405 sNo cumple19,13 µA6,90 años
Rápida (0,05 °C/s)3 °C0,405 sCumple19,15 µA6,89 años
Rápida (0,05 °C/s)4 °C0,405 sCumple40,22 µA3,73 años

La tabla enseña tres cosas. Sin zona de alerta, el equipo detecta la excursión lenta con 56,4 s de retraso en esta fase (el peor caso teórico es 60,4 s): el requisito R-2 solo se cumple por casualidad de fase, no por diseño. Con una zona de 2 °C la excursión lenta se resuelve (0,6 °C entre medidas lentas, menos que la zona), pero la rápida no: la temperatura sube 3 °C entre medidas y atraviesa el límite antes de que el equipo acelere (10,4 s). Con 3 °C, justo la pendiente por 60 s, ambas se cumplen y el costo en energía casi no cambia (19,15 µA). Y con 4 °C se «sobrediseña»: la zona empieza en 4,0 °C, que la temperatura normal (4,0 ± 0,5 °C) toca la mitad del tiempo, así que el equipo mide cada 2 s casi siempre (66 903 medidas en lugar de 6196) y la vida cae de 6,89 a 3,73 años. Cumple los requisitos, pero tira casi la mitad de la autonomía. El tamaño correcto de la zona es una consecuencia de los datos físicos, ni más angosta ni más ancha.

Y una observación de método: la latencia depende de la fase entre la excursión y las medidas. Una prueba que usa un único instante de inicio puede salir bien por suerte (los 0,405 s de la zona de 2 °C con la excursión lenta) o mal por mala suerte. Se prueba con varias fases (o con la peor, que se puede calcular, como hicimos al fijar los 30 s) y se compara el resultado con la cota teórica: periodo de medida más el tiempo de proceso y de radio.

05 · El presupuesto frente a la realidad

Bajo consumo en el conjunto

El tema 48 calculó un consumo del circuito de 15,78 µA y una vida de 7,97 años. La simulación del equipo completo, tres días de funcionamiento normal con reporte cada 15 minutos, da 15,90 µA y 7,93 años: el presupuesto estaba bien, con una diferencia explicable. La simulación cuenta lo que el presupuesto no contaba: escribir cada medida en la flash (0,01 mC por medida, unos 0,17 µA más) y, por el contrario, 287 reportes en tres días en lugar de 288 (porque el primero sale a los 900 s). El resultado de cualquier integración sirve para eso: comparar lo previsto con lo medido y explicar la diferencia. Una diferencia sin explicación es un modelo equivocado.

La energía en un producto con radio se la lleva casi toda la radio. Del total de 15,90 µA, la radio consume 12,4 µA (el 78 %), las medidas 1,5 µA y el reposo 2,0 µA. El laboratorio permite ver la consecuencia de un cambio de requisito: si el cliente pidiera un reporte cada 5 minutos en lugar de cada 15, la corriente subiría a 40,79 µA y la vida bajaría de 7,93 a 3,68 años: sigue cumpliendo los 2 años y el objetivo de diseño de 3 años, pero con un margen mucho menor. Es la conversación del tema 48 («cada reporte cuesta 11,2 mC») en forma de números.

Dónde se va la energía del registrador en funcionamiento normal (reporte cada 15 min).
ConsumidorCorriente mediaQué lo reduce
Radio (reportes)12,4 µA (78 %)Menos reportes, mensajes más cortos, potencia de transmisión menor, agrupar medidas en cada reporte
Medidas (sensor, cálculo, flash)1,5 µA (9 %)Medir menos seguido fuera de la zona de alerta; agrupar escrituras en flash (tema 41)
Reposo2,0 µA (13 %)Elegir un chip con menor corriente de sueño; apagar el regulador y los pines flotantes (tema 35)

Dos advertencias para pasar del modelo a la realidad. Primera: la energía de la radio y del sueño se mide, no se supone (tema 36): una corriente de sueño de 2,0 µA en la hoja de datos puede ser 10 µA en la placa por un pin flotante o un regulador mal elegido, y eso por sí solo cambiaría la conclusión de la tabla. Segunda: el modelo no sabe de la temperatura ni de la pila: con frío la capacidad de la pila baja (la simulación usa el 80 % utilizable, un supuesto que se confirma midiendo a −30 °C, que es donde viaja el producto), y la autodescarga y la resistencia interna cambian. El objetivo de diseño de 3 años con margen de 1,5 existe para absorber esas diferencias.

06 · Cuando algo sale mal

Watchdog y recuperación de fallas

El registrador debe poder fallar sin dejar de ser útil. Dos fallas del requisito están modeladas en el proyecto: que el programa se cuelgue (R-4) y que el sensor deje de responder (R-5). La Parte 3 las simula a los dos días de funcionamiento:

Fallas del equipo (resultado de la Parte 3; tres días simulados).
EscenarioCorrienteMedidasResultado
Sin fallas15,90 µA4320—
Programa colgado, watchdog de 120 s17,15 µA43191 reinicio; 125 s sin medir (cumple R-4: menos de 300 s)
El sensor deja de responder15,94 µA4320Falla informada en la primera medida fallida (cumple R-5)

El caso del cuelgue enseña dos cosas que el diseño del watchdog (tema 38) ya anticipaba. Primera: los 125 s son 120 s más 5 s de arranque contados desde la última medida y no desde el cuelgue. El watchdog se alimenta tras cada medida; si el programa se cuelga justo después de alimentarlo, pasan los 120 s completos de cuelgue; si se cuelga poco antes de la próxima medida, el reinicio llega antes. El tiempo sin medir es siempre el plazo del watchdog más el arranque, y por eso el plazo (120 s) se elige a partir del requisito (300 s) y del período de medida (60 s), con la regla de que sea mayor que el período de alimentación (si fuera de 30 s, el watchdog reiniciaría el equipo sano cada medio minuto, el error clásico del tema 38). Segunda: durante el cuelgue la CPU quedó ejecutando un bucle a 4 mA: unos 80 s en este caso, 320 mC, que son 1,25 µA promedio sobre los tres días. Un cuelgue por semana en todo el parque costaría poco; uno por hora vaciaría la pila, y por eso el informe de causa de reinicio (tema 37) debe viajar a la nube y alguien debe leerlo.

El watchdog solo detecta lo que se le pregunta. Alimentarlo desde una interrupción lo volvería inútil (se alimenta aunque el programa principal esté colgado, tema 38); alimentarlo en el bucle principal sin más detecta cuelgues del bucle pero no que una parte del sistema dejó de funcionar. Por eso el ejemplo lo alimenta al final de una medida completa: si el temporizador de medidas se detiene, si el sensor traba el bus, si la escritura en flash nunca termina, no hay latido y el equipo se reinicia. Para sistemas con varias tareas, la técnica es la de los puntos de control: cada tarea marca que cumplió su parte y solo se alimenta el watchdog si todas lo hicieron en su plazo.

Para la falla del sensor el requisito pide informarla en menos de 120 s, y el diseño lo hace en la primera medida fallida: como mucho 60 s después de que ocurra (en la simulación, 0 s porque la falla comienza justo en una medida). Dos detalles importan: se informa una vez (no un reporte por cada medida fallida, que vaciaría la pila) y el equipo sigue vivo (alimenta el watchdog, sigue midiendo cada 60 s por si el sensor se recupera, sigue reportando que está en falla). Un sensor roto no debería convertirse en un equipo roto.

07 · Registro y actualización

Registro y actualización segura

El registro de las medidas (R-7) usa la técnica del tema 41: un registro circular en la flash externa, con un CRC por registro y un número de secuencia, de modo que tras un corte de energía el equipo recupera el último registro válido y sigue desde allí. A 8 bytes por medida y una medida por minuto, los 30 días requeridos son 345 600 bytes; la flash externa de 512 KB alcanza con margen, y su desgaste (tema 40) se calcula con el número de borrados por sector, que el registro circular reparte parejo.

La actualización por radio (R-6) es donde más se paga haber pensado en el corte de energía. La imagen nueva llega en fragmentos y se graba en la flash externa; recién cuando está completa y verificada (CRC y firma, tema 43) se marca como candidata, se reinicia, se arranca en prueba y, solo si la versión nueva confirma que funciona, se vuelve definitiva; si no, el cargador vuelve a la anterior (tema 42). El orden de los pasos es lo que hace segura la secuencia, y la Parte 4 lo demuestra cortando la energía después de cada paso:

Corte de energía después de cada paso de la actualización (resultado de la Parte 4; 7 puntos de corte).
Orden de los pasosCargadorCortes seguros
Datos, validez y marca de prueba al finalComprueba la imagen antes de saltar7 de 7
Datos, validez y marca de prueba al finalSalta sin comprobar7 de 7
Marca de prueba primeroComprueba la imagen antes de saltar7 de 7
Marca de prueba primeroSalta sin comprobar2 de 7 (el equipo no arranca si se corta después de los pasos 1 a 5)

La lección es la de la defensa en profundidad: con el orden correcto, hasta un cargador ingenuo es seguro; con un cargador que comprueba la imagen, hasta el orden equivocado es seguro; solo la combinación de las dos fallas deja el equipo sin arrancar, en cinco de siete puntos de corte. Un producto serio hace las dos cosas: graba la marca de prueba al final, y el cargador verifica siempre lo que va a ejecutar. Y se prueba sistemáticamente, con un modelo de la flash que corta en cada paso (como la Parte 4) y, en el banco, con la fuente programable cortando durante cada fase.

/* Decisión del cargador de arranque: robusta ante una imagen incompleta y ante una versión nueva que no funciona */
typedef enum { BOOT_A, BOOT_B_PRUEBA, BOOT_B_CONFIRMADA } Marca;

void cargador_arrancar(void) {
    Marca m = marca_leer();
    if (m == BOOT_B_PRUEBA) {
        if (!imagen_b_valida()) { marca_escribir(BOOT_A); }                 /* incompleta o dañada: seguir con la anterior (nunca saltar a ciegas) */
        else if (intentos_prueba_incrementar() > 3u) { marca_escribir(BOOT_A); }  /* la nueva no se confirmó en 3 arranques: vuelta atrás */
    }
    saltar_a(marca_leer() == BOOT_A ? SLOT_A : SLOT_B);
}

/* La aplicación nueva confirma que funciona después de completar una medida y un reporte con éxito */
void arranque_confirmar_si_corresponde(void) {
    if (marca_leer() == BOOT_B_PRUEBA && autochequeo_ok()) { marca_escribir(BOOT_B_CONFIRMADA); }
}

08 · Antes de liberar

Pruebas del proyecto y liberación

Cada requisito tiene su método de verificación, y la mayor parte de las pruebas del proyecto ya las conocemos de los temas 44 a 47. Aquí se juntan en un plan de pruebas con su nivel en la pirámide:

Plan de pruebas del registrador.
RequisitoPruebaNivel
R-1 VidaConsumo medido de cada modo con fuente programable y medidor de corriente; vida calculada con el modelo; prueba de pila a −30 °CHardware en el lazo y análisis
R-2 AlarmaRampa de temperatura a distintas pendientes y varias fases; latencia medida con pin y analizador lógicoHardware en el lazo
R-3 ReporteSimulación de varios días con el reloj acelerado; conteo de reportesSimulación
R-4 CuelgueCuelgue provocado desde el modo de prueba en distintos puntos; medir el tiempo sin medirHardware en el lazo
R-5 Falla del sensorInyección de falla (desconexión del bus) y verificación del informe y de que sigue vivoHardware en el lazo y unitaria con un sensor falso
R-6 ActualizaciónCorte de energía en cada paso, imágenes dañadas, versión nueva que no confirma, retroceso rechazado (temas 42, 43 y 47)Unitaria con flash simulada y hardware en el lazo
R-7 RegistroCortes de energía durante cada escritura; recuperación; desgaste (tema 41)Unitaria con flash simulada
Lógica (histéresis, zona, estados)Tabla de casos en los límites a ambos lados (8 casos como mínimo), mutación y propiedades (tema 47)Unitaria en la PC

Antes de liberar una versión se recorre una lista de verificación que reúne los temas anteriores. Si algún punto no se puede marcar, no se libera:

Lista de verificación para liberar una versión.
PuntoTema
Todos los requisitos tienen su prueba, y la matriz de trazabilidad no tiene huecos48 y 50
La integración continua está en verde: compilación con -Werror, análisis estático, pruebas con sanitizers, presupuestos de flash, RAM y pila respetados46, 47 y 50
Versión marcada, huella de la compilación y ELF con su mapa archivados; la compilación se puede reproducir45 y 50
Depuración cerrada, sin información de prueba, imagen firmada, contador anti-retroceso actualizado43 y 45
Watchdog armado y alimentado solo al final de la medida; causa de reinicio informada37 y 38
Consumo medido en cada modo, sin la sonda conectada, y dentro del objetivo de diseño36 y 45
Actualización probada con cortes de energía y con versión nueva que falla; despliegue gradual planeado42 y 47
Documentación: README, arquitectura, ADR y registro de cambios al día; versiones de firmware, hardware y protocolo definidas49 y 50
Revisión de código hecha y desviaciones del estándar documentadas50
Plan de mantenimiento: política de versiones soportadas, seguimiento de avisos de seguridad, componentes con su ciclo de vida50

09 · Comprobar que funciona

Verificación y diagnóstico

Comprobaciones sobre el proyecto integrado.
Qué verificarCómoResultado esperado
El modelo coincide con la realidadComparar la simulación con las medidas del banco, modo por modoDiferencias explicadas (o el modelo se corrige)
Los requisitos con plazo se cumplen en todas las fasesRepetir la prueba con varias fases de la excursión y comparar con la cota teóricaLa peor fase cumple, no solo la casual
Los parámetros derivados están justificadosZona de alerta = pendiente máxima × período lento; plazo del watchdog > período de alimentaciónCada parámetro tiene su cuenta anotada en el ADR
El equipo se recupera de cada falla modeladaCuelgue, falla de sensor, corte de energía, imagen dañada: provocarlas en el bancoRecuperación sin intervención dentro del plazo
La actualización es segura en cada punto de corteModelo exhaustivo de cortes más fuente programableSiempre arranca una versión válida
La versión liberada es la probadaHuella de la compilación y firma verificadas sobre el binario que se entregaCoincide con la probada
Síntomas frecuentes y qué revisar.
SíntomaCausa probableQué hacer
La alarma tarda mucho solo con ciertas excursionesZona de alerta menor que la pendiente por el período lentoDimensionar la zona con la pendiente máxima medida; probar varias fases
El consumo real es el doble del calculadoZona de alerta demasiado ancha, reportes más frecuentes de lo supuesto, un pin flotante o un reguladorContar medidas y reportes por día; medir el sueño; revisar la zona
El equipo se reinicia cada medio minutoPlazo del watchdog menor que el período de alimentaciónPlazo mayor que el período, derivado del requisito (R-4)
El equipo no arranca después de una actualización cortadaMarca de prueba grabada antes de terminar la imagen, y un cargador que no verificaMarca al final; el cargador verifica siempre; probar todos los cortes
Un sensor roto vacía la pilaUn reporte por cada medida fallida, o reintentos sin límiteInformar una vez, reintentar con espera creciente y límite
La versión de campo no coincide con lo probadoCompilación sin huella ni versiones fijasManifiesto, compilación reproducible, binario firmado desde la integración continua
Los requisitos pasan en la simulación y fallan en el bancoHipótesis del modelo (corrientes, pendiente, capacidad) distintas de las realesReemplazar cada supuesto por una medida y reajustar el modelo

10 · Analogía con programación

Probar el modelo en Python

El programa es el modelo ejecutable del registrador completo: simula tres días a un paso de un segundo la máquina de estados (activo, alarma, falla), la zona de alerta, los reportes periódicos y de alarma, el consumo de cada operación, el watchdog con un cuelgue provocado y la falla del sensor; y, en la Parte 4, modela la actualización con corte de energía en cada paso con dos cargadores y dos órdenes. Es el mismo modelo que corre el laboratorio.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar; esta simulación recorre 259 200 pasos por escenario y puede tardar algunos segundos más.

# Proyecto integrador: el registrador de temperatura completo, simulado tres días a un paso de un segundo (energía, alarma, watchdog) y una actualización con corte de energía en cada paso.
import math

# ---- El modelo del dispositivo --------------------------------------------------------------------------------------------------------------------
N, L, HIST = 3 * 86400, 8.0, 0.5                                    # tres días simulados; límite de alarma 8 °C con histéresis de 0,5 °C
T_MED, T_RAPIDO, T_REP_ALARMA, WDT = 60, 2, 60, 120                 # períodos de medida, de reporte en alarma y plazo del watchdog (s)
CARGA_MED, CARGA_TX, SUENO_MC, CPU_MA = 0.09, 11.2, 0.002, 4.0      # mC por medida (sensor, cálculo y escritura en flash), mC por reporte, mC por segundo de sueño, mA de una CPU colgada
FALLA_T, HANG_T, T0 = 2 * 86400, 2 * 86400 + 1000, 86400 + 6 * 3600 + 30   # instante en que falla el sensor, en que se cuelga el programa y en que empieza la excursión (30 s después de una medida lenta: la fase importa)
def temperatura(t, esc):
    base = 4.0 + 0.5 * math.sin(2 * math.pi * t / 21600)
    if esc in ("lenta", "rapida"):
        p = 0.01 if esc == "lenta" else 0.05                        # °C por segundo
        r = 8.0 / p
        if T0 <= t < T0 + r: return base + p * (t - T0)
        if T0 + r <= t < T0 + r + 3600: return base + 8.0
        if T0 + r + 3600 <= t < T0 + 2 * r + 3600: return base + 8.0 - p * (t - (T0 + r + 3600))
    return base
def simular(esc, zona, t_rep, cuelgue=False):
    carga = 0.0; prox_med = 0; prox_rep = t_rep; alarma = False; rapido = False
    regs = reportes = reinicios = 0; lats = []; cruce = None; falla_rep = None
    colgado = False; ult_alim = 0; ult_med = 0; ant_hang = None; gap = None
    for t in range(N):
        carga += SUENO_MC
        v = temperatura(t, esc)
        if v > L and cruce is None and not alarma: cruce = t
        if cuelgue and not colgado and ant_hang is None and t == HANG_T:
            colgado, ant_hang = True, ult_med
        if colgado:
            carga += CPU_MA                                         # una CPU colgada en un bucle consume la corriente de funcionamiento
            if t - ult_alim >= WDT:
                colgado = False; reinicios += 1; prox_med = t + 5; prox_rep = t + 5 + t_rep
            continue
        if t >= prox_med:
            carga += CARGA_MED; regs += 1; ult_alim = t
            if reinicios and gap is None: gap = t - ant_hang
            ult_med = t
            if esc == "falla" and t >= FALLA_T:                     # el sensor no responde: se informa la falla una vez
                if falla_rep is None: falla_rep = t; reportes += 1; carga += CARGA_TX
                rapido = False
            else:
                if v > L and not alarma:
                    alarma = True; lats.append(t - cruce + 0.405); cruce = None; reportes += 1; carga += CARGA_TX; prox_rep = t + T_REP_ALARMA
                elif alarma and v <= L - HIST: alarma = False
                rapido = alarma or (zona > 0 and v >= L - zona)
            prox_med = t + (T_RAPIDO if rapido else T_MED)
        if t >= prox_rep:
            reportes += 1; carga += CARGA_TX; prox_rep = t + (T_REP_ALARMA if alarma else t_rep)
    ua = carga / N * 1000
    return dict(ua=ua, vida=1500 / ((ua + 5.70) / 1000) / 24 / 365, regs=regs, reportes=reportes, lat=max(lats) if lats else None,
                reinicios=reinicios, gap=gap, falla=None if falla_rep is None else falla_rep - FALLA_T)
def mostrar(titulo, r):
    lat = "sin alarma" if r["lat"] is None else f"{r['lat']:.3f} s"
    extra = (f"; sin medir {r['gap']} s tras {r['reinicios']} reinicio(s)" if r["gap"] is not None else "") + (f"; falla del sensor informada en {r['falla']} s" if r["falla"] is not None else "")
    print(f"  {titulo:<48} {r['ua']:6.2f} µA, vida {r['vida']:5.2f} años, {r['regs']:>5} medidas, {r['reportes']:>3} reportes, latencia de alarma {lat}{extra}")

print("Parte 1: tres días de funcionamiento normal (4 °C con una variación de ±0,5 °C), reporte cada 15 min")
mostrar("normal, zona de alerta de 2 °C", simular("normal", 2, 900))
print("  el presupuesto del tema 48 daba 15,78 µA; la simulación incluye además la escritura de cada medida en la flash (0,01 mC), que el presupuesto no contaba")
print()
print("Parte 2: una excursión de temperatura (sube 8 °C, se mantiene una hora y vuelve) y el requisito de alarma en menos de 5 s")
mostrar("lenta (0,01 °C/s), zona de 2 °C", simular("lenta", 2, 900))
mostrar("lenta (0,01 °C/s), sin zona (medir cada 60 s)", simular("lenta", 0, 900))
mostrar("rápida (0,05 °C/s), zona de 2 °C", simular("rapida", 2, 900))
mostrar("rápida (0,05 °C/s), zona de 3 °C", simular("rapida", 3, 900))
mostrar("rápida (0,05 °C/s), zona de 4 °C", simular("rapida", 4, 900))
print()
print("Parte 3: fallas del equipo: el programa se cuelga a los dos días con el watchdog de 120 s, y el sensor deja de responder")
mostrar("sin cuelgue", simular("normal", 2, 900))
mostrar("con cuelgue y watchdog de 120 s", simular("normal", 2, 900, cuelgue=True))
mostrar("falla del sensor a los dos días", simular("falla", 2, 900))

# ---- Parte 4: actualización con corte de energía en cada paso -------------------------------------------------------------------------------------
BUENO = ["fragmento 1", "fragmento 2", "fragmento 3", "fragmento 4", "imagen válida", "marca de prueba"]          # primero los datos, después la validez y por último la marca
MALO = ["marca de prueba"] + BUENO[:-1]                                                                          # la marca antes de terminar de grabar
def aplicar(pasos):
    e = {"frag": 0, "valida": False, "marca": False}
    for p in pasos:
        if p.startswith("fragmento"): e["frag"] += 1
        elif p == "imagen válida": e["valida"] = e["frag"] == 4
        elif p == "marca de prueba": e["marca"] = True
    return e
def arranque(e, robusto):
    if not e["marca"]: return "A"                                                                                 # sin marca: sigue la versión anterior
    if e["valida"]: return "B"
    return "A" if robusto else "NO ARRANCA"                                                                       # imagen incompleta: el cargador robusto la comprueba antes de saltar
print()
print("Parte 4: se corta la energía después de cada paso de la actualización y se mira qué versión arranca")
for nombre, orden in (("orden correcto (datos, validez, marca)", BUENO), ("orden incorrecto (marca primero)", MALO)):
    for robusto in (True, False):
        res = [arranque(aplicar(orden[:k]), robusto) for k in range(len(orden) + 1)]
        seguros = sum(r != "NO ARRANCA" for r in res)
        print(f"  {nombre}, cargador {'que comprueba la imagen' if robusto else 'que salta sin comprobar'}: {seguros} de {len(res)} cortes seguros; resultados {res}")

Resultado, parte 1: tres días de funcionamiento normal dan 15,90 µA, vida de 7,93 años, 4320 medidas y 287 reportes (el presupuesto del tema 48 daba 15,78 µA, sin contar la escritura de cada medida en la flash). Parte 2: excursión lenta con zona de 2 °C: 0,405 s, 19,82 µA y 6,71 años; lenta sin zona: 56,405 s (no cumple 5 s); rápida con zona de 2 °C: 10,405 s (no cumple); rápida con zona de 3 °C: 0,405 s, 19,15 µA; rápida con zona de 4 °C: 0,405 s pero 40,22 µA, 3,73 años y 66 903 medidas. Parte 3: con un cuelgue a los dos días y un watchdog de 120 s: 1 reinicio, 125 s sin medir, 17,15 µA, 7,49 años y 4319 medidas; con la falla del sensor: informada en 0 s (en la primera medida fallida), 288 reportes. Parte 4: con el orden correcto (datos, validez y marca al final), 7 de 7 cortes seguros con cualquier cargador; con la marca primero, 7 de 7 si el cargador comprueba la imagen y 2 de 7 si salta sin comprobar.

Probá cambiar en la Parte 2 la zona de alerta (zona) a 2,5 y a 3,5 °C, o el período de reporte a 300 s (la vida baja a 3,68 años); cambiar el plazo del watchdog (WDT) a 30 s y ver que el tiempo sin medir tras el cuelgue baja a 35 s (el modelo aplica el watchdog solo durante el cuelgue: el reinicio continuo de un plazo menor que el período de alimentación habría que agregarlo), o mover el instante de inicio de la excursión (T0) para ver cómo cambia la latencia con la fase. La lección del programa es que un modelo ejecutable del producto completo, con las hipótesis a la vista, descubre en segundos lo que de otro modo se descubriría con el hardware construido.

11 · Exploración interactiva

El registrador completo

El laboratorio ejecuta el modelo del programa, tres días a un paso de un segundo, y muestra la corriente media, la vida estimada, el número de medidas y reportes, la latencia de la alarma y un tablero de requisitos con cumple o no cumple. Elegís el escenario de temperatura (normal, excursión lenta, excursión rápida, falla del sensor), el tamaño de la zona de alerta (0 la desactiva), el período de reporte y si se provoca un cuelgue del programa con un watchdog de 120 s.

Simular el registrador tres días

Corriente media—
Vida estimada—
Medidas en 3 días—
Reportes en 3 días—
Latencia de la alarma—

Tablero de requisitos

Elegí un escenario.

Recorrido guiado

  1. Con los valores iniciales (normal, zona de 2 °C, reporte cada 15 min): 15,90 µA, 7,93 años, 4320 medidas y 287 reportes. R-1 y R-3 se cumplen; los demás requisitos no se ejercen, porque no pasó nada. Un tablero verde en un escenario tranquilo no prueba lo que no se ejercitó.
  2. Elegí la excursión lenta: la alarma sale en 0,405 s (R-2 cumple) y la corriente sube a 19,82 µA (la zona de alerta y la alarma consumen), vida 6,71 años. Ahora poné la zona en «Ninguna»: la latencia salta a 56,405 s y R-2 no cumple: el equipo medía cada 60 s y la temperatura ya había pasado el límite. El costo de la zona de alerta fue de apenas 0,10 µA.
  3. Elegí la excursión rápida con zona de 2 °C: latencia de 10,405 s, R-2 no cumple, aunque la zona «funciona» con la lenta. La temperatura sube 3 °C entre medidas lentas y atraviesa la zona de 2 °C sin que el equipo acelere. Probá 1 °C y verás lo mismo.
  4. Con la rápida y la zona de 3 °C (la pendiente por el período lento): 0,405 s, R-2 cumple y la corriente es 19,15 µA. Es el tamaño correcto. Con 4 °C también cumple, pero la corriente se dispara a 40,22 µA, con 66 903 medidas y una vida de 3,73 años: la zona toca la temperatura normal y el equipo mide cada 2 s casi siempre. «Más ancho» no es «más seguro»: es otro costo.
  5. Volvé al escenario normal y marcá «Provocar un cuelgue»: 4319 medidas (una menos), 17,15 µA, 7,49 años y R-4 cumple con 125 s sin medir (120 s del watchdog más 5 s de arranque, contados desde la última medida). El cuelgue costó 1,25 µA promedio en tres días porque la CPU colgada consumió 4 mA durante unos 80 s.
  6. Elegí «El sensor deja de responder»: R-5 cumple (informado en la primera medida fallida, 0 s en esta simulación; como máximo 60 s en el peor caso), 288 reportes (uno más: el de la falla) y el equipo sigue vivo. Y probá el período de reporte de 5 minutos en el escenario normal: 40,79 µA y 3,68 años. Sigue cumpliendo R-1, pero la radio pasó del 78 % a casi todo el consumo, y el margen se redujo a la mitad.
Desafío: ¿qué cambiarías del diseño para que la alarma cumpla en la excursión rápida sin gastar más de 25 µA?

Hay varias salidas, y el laboratorio sirve para comprobarlas con números. La más directa es la zona de 3 °C (la pendiente por el período lento), que cumple con 19,15 µA. Otras: acortar el período lento (a 30 s la zona mínima baja a 1,5 °C, pero el consumo de medidas se duplica: de 1,5 a unos 3,0 µA, todavía barato), medir con un umbral de pendiente (si entre dos medidas la temperatura subió más de 1 °C, pasar a modo rápido aunque esté lejos del límite: detecta la excursión rápida por su velocidad, no por su nivel), o usar la alarma por hardware (un sensor con comparador que despierte al microcontrolador al cruzar un umbral, sin necesidad de medir seguido: consume menos pero exige un componente que lo tenga y fija una decisión de hardware, tema 49). Cada una cambia un presupuesto distinto: la primera, nada; la segunda, medidas; la tercera, lógica y pruebas; la cuarta, hardware y costo. La elección se registra en un ADR con estos números.

12 · Método de trabajo

Método: integrar con orden

  1. Empezá por los requisitos con número y verificación (tema 48) y por los presupuestos con margen (tema 49): son el tablero contra el que se mide todo.
  2. Armá un esqueleto que funcione de punta a punta lo antes posible (entrada, cola de eventos, una medida falsa, una salida) y hacelo crecer. Un sistema integrado temprano muestra los problemas de interacción cuando todavía es barato corregirlos.
  3. Construí un modelo ejecutable del producto (en Python, en la PC) con las hipótesis a la vista, y usalo para dimensionar los parámetros derivados: la zona de alerta, el plazo del watchdog, los períodos.
  4. Calculá cada parámetro derivado y anotá la cuenta (en un ADR): zona = pendiente × período lento; watchdog > período de alimentación y plazo ≤ requisito; período de reporte según la energía.
  5. Probá en varias fases y en los casos extremos, no solo en el caso feliz: una latencia que cumple por casualidad de fase no cumple. Comparála con la cota teórica.
  6. Comparás siempre lo previsto con lo medido (15,78 contra 15,90 µA) y explicás la diferencia; una diferencia sin explicar indica un modelo o un presupuesto equivocado.
  7. Diseñá cada falla modelada con su recuperación (cuelgue, sensor, corte de energía, actualización) y provocala a propósito con un modo de prueba.
  8. Hacé que la actualización sea segura por orden y por verificación: marca al final, cargador que verifica siempre, versión nueva que debe confirmarse, vuelta atrás, y probalo cortando en cada punto.
  9. Automatizá todo en la integración continua y recorré la lista de verificación antes de liberar, con la matriz de trazabilidad sin huecos y los artefactos archivados.
  10. Documentá las decisiones y planificá la vida del producto: mantenimiento, avisos de seguridad, componentes y retirada (tema 50).

13 · Comprensión

Confusiones frecuentes

«Si cada módulo funciona por separado, el sistema funciona»

Los problemas de un producto aparecen en las interacciones: una zona de alerta que cumple con una pendiente y no con otra, un watchdog cuya cuenta depende del período de medida, una marca de actualización cuyo orden importa. Por eso se integra temprano y se prueba el conjunto con escenarios completos.

«Un tablero de requisitos en verde significa que el producto está bien»

Solo significa que los requisitos ejercitados se cumplieron en ese escenario. En el escenario normal, cinco de los siete requisitos no se ejercen. Hay que cubrir los escenarios que ponen a prueba cada uno, en distintas fases y condiciones extremas.

«La zona de alerta, cuanto más ancha, más segura»

Con 4 °C la alarma cumple, pero la zona toca la temperatura normal y el equipo mide cada 2 s casi todo el tiempo: la vida baja de 6,89 a 3,73 años. El tamaño correcto sale de los datos físicos (pendiente máxima por período lento); más ancho es otro costo, no más seguridad.

«El watchdog mide el tiempo desde el cuelgue»

Mide desde la última vez que se lo alimentó. El tiempo sin medir tras un cuelgue es siempre el plazo del watchdog más el arranque (125 s en el ejemplo), sea cual sea el instante del cuelgue. Y si el plazo fuera menor que el período de alimentación, reiniciaría el equipo sano.

«Para que una actualización sea segura basta con verificar la imagen al terminar»

También importa el orden de los pasos y qué hace el cargador: con la marca de prueba grabada antes de terminar y un cargador que salta sin comprobar, 5 de los 7 puntos de corte dejan el equipo sin arrancar. Se necesitan el orden correcto y la verificación, y se prueba cortando la energía en cada punto.

«El presupuesto de energía del diseño ya es el consumo real»

Es una estimación con hipótesis. La simulación completa agregó la escritura en flash y los reportes reales; la medición real agregará pines, regulador, temperatura y pila. La verificación consiste en comparar y explicar cada diferencia, y en reemplazar los supuestos por medidas.

«El proyecto termina cuando se libera la primera versión»

Empieza el mantenimiento: avisos de seguridad, correcciones, actualizaciones por el aire, componentes que se discontinúan, soporte de la flota (tema 50). La lista de verificación incluye el plan de mantenimiento antes de liberar, no después.

«Un modelo en Python es un juguete y no sirve para decidir»

Un modelo con las hipótesis a la vista permite dimensionar parámetros y descubrir contradicciones en segundos, antes de tener hardware. Su valor está en que sus supuestos se pueden discutir y reemplazar por medidas, y en que se puede repetir cada vez que cambia un requisito o una hipótesis.

14 · Práctica guiada

Ejercicios

1. Reportes más frecuentes

El cliente pide un reporte cada 5 minutos en lugar de cada 15. Cada reporte cuesta 11,2 mC. ¿Cuál es la corriente de la radio, la total (el resto del circuito consume 1,5 µA de medidas más 2,0 µA de reposo) y la vida estimada con 5,70 µA de autodescarga? ¿Se cumple el objetivo de diseño de 3 años?

Ver solución

Radio: 11,2 mC / 300 s = 0,03733 mA = 37,33 µA (contra 12,44 µA a 900 s). Total del circuito: 37,33 + 1,5 + 2,0 = 40,83 µA (la simulación da 40,79 µA porque cuenta un reporte menos al comienzo). Con la autodescarga: 46,53 µA; vida = 1500 mAh / 0,04653 mA = 32 237 h ≈ 3,68 años. Cumple los 2 años y el objetivo de 3 años, pero el margen sobre este último bajó de más del doble a un 23 %. Si el cliente quisiera reportes cada 2 minutos, ya no cumpliría el objetivo, y habría que renegociar o cambiar la batería.

2. Dimensionar la zona de alerta

Un contenedor puede calentarse como máximo 0,04 °C/s. El período lento es de 60 s y el límite, 8 °C; la temperatura normal máxima es 4,5 °C. ¿Qué zona mínima hace falta? ¿Y si la pendiente máxima fuera 0,1 °C/s?

Ver solución

Zona mínima = pendiente × período lento = 0,04 × 60 = 2,4 °C: la zona empieza en 8 − 2,4 = 5,6 °C, por encima de la temperatura normal máxima (4,5 °C), de modo que el equipo mide lento en condiciones normales. Con 0,1 °C/s: 0,1 × 60 = 6 °C, y la zona empezaría en 2 °C, dentro de la temperatura normal: el equipo mediría cada 2 s siempre. La solución es acortar el período lento: para que la zona no toque la temperatura normal, debe ser menor que 8 − 4,5 = 3,5 °C, es decir, 0,1 × T ≤ 3,5, T ≤ 35 s. Cambió una hipótesis física (la pendiente) y con ella el diseño de la medida.

3. El tiempo sin medir

El watchdog es de 120 s, se alimenta tras cada medida (cada 60 s) y el arranque tarda 5 s. ¿Cuánto tiempo sin medir deja un cuelgue? ¿Depende de cuándo ocurre? ¿Qué pasaría con un watchdog de 30 s?

Ver solución

El reinicio ocurre 120 s después de la última alimentación y la primera medida después, 5 s más tarde: 125 s sin medir, sea cual sea el instante del cuelgue (entre dos medidas). Lo que sí varía es cuánto tiempo estuvo colgada la CPU consumiendo 4 mA: entre 61 s (cuelgue justo antes de la medida siguiente) y 120 s (justo después de la anterior), es decir entre 244 y 480 mC. Con un watchdog de 30 s, que es menor que el período de alimentación de 60 s, el equipo sano se reiniciaría cada 30 s sin medir nunca: el plazo debe superar el período de alimentación.

4. Cortes de energía

Una actualización tiene seis pasos (cuatro fragmentos, validez y marca de prueba) y se prueba un corte antes de cada paso y uno al final. ¿Cuántos puntos de corte hay? Con la marca primero y un cargador que salta sin comprobar, ¿cuáles dejan al equipo sin arrancar?

Ver solución

Con 6 pasos hay 7 puntos de corte (después de 0, 1, 2, 3, 4, 5 o 6 pasos). Con la marca primero, el corte tras el paso 0 es seguro (no hay marca: sigue la versión anterior); tras los pasos 1 a 5 hay marca pero la imagen está incompleta o sin validar: el cargador ingenuo salta a una imagen inválida y el equipo no arranca (5 de 7 cortes); tras el paso 6 la imagen está completa y arranca la nueva. El cargador que comprueba la imagen antes de saltar vuelve a la anterior en los cinco casos: los 7 son seguros.

5. Presupuesto contra simulación

El presupuesto del tema 48 daba 15,78 µA y la simulación da 15,90 µA. Explicá la diferencia con números.

Ver solución

El presupuesto suponía 0,08 mC por medida (3 mA × 20 ms más 4 mA × 5 ms): 1,33 µA cada 60 s. La simulación agrega la escritura en flash, 0,01 mC (0,09 mC en total): 1,5 µA, o 0,17 µA más. Eso da 15,78 + 0,17 = 15,94 µA. La simulación da 15,90 µA y no 15,94 porque en tres días hay 287 reportes y no 288 (el primero sale a los 900 s): 11,2 mC × 287 / 259 200 s = 12,40 µA contra 12,44 µA, 0,04 µA menos. 15,94 − 0,04 = 15,90 µA. La diferencia queda explicada punto por punto: eso es validar un modelo.

6. Una liberación con un hueco

Al repasar la lista de verificación antes de liberar, descubrís que la matriz de trazabilidad no tiene prueba para R-5 (falla del sensor) y que la versión de campo se compiló en una máquina sin guardar el ELF. ¿Se libera? ¿Qué hacés?

Ver solución

No se libera. Un requisito sin prueba (R-5) es un deseo sin verificar: se escribe la prueba (inyección de falla en el banco y una unitaria con un sensor falso) y se ejecuta antes de liberar. La compilación sin ELF ni huella no se puede diagnosticar ni reproducir: un HardFault en el campo mostraría solo direcciones (tema 45). Se recompila desde la marca en el entorno de la integración continua, se archivan el ELF, el mapa y la huella, y se libera ese binario firmado. Los dos huecos se cierran por proceso: la matriz se comprueba en la integración continua (tema 50) y la liberación sale únicamente de ella.

15 · Síntesis

Ideas para recordar

  • Un proyecto integrador reúne las decisiones del curso y las pone a prueba juntas. El registrador tiene siete requisitos con número y verificación, una arquitectura dirigida por eventos (el reloj, la radio y el botón encolan; un solo bucle procesa; sin eventos, duerme) y un esqueleto de firmware sin esperas activas, con el watchdog armado primero y la causa de reinicio registrada.
  • La lógica de alarma combina histéresis y una zona de alerta. La zona debe ser al menos la pendiente máxima por el período lento (3 °C): con 2 °C la excursión rápida da 10,4 s (no cumple los 5 s); con 3 °C, 0,4 s y 19,15 µA; con 4 °C también cumple, pero toca la temperatura normal y la vida cae de 6,89 a 3,73 años. Sin zona, la alarma de la excursión lenta tardó 56,4 s.
  • La latencia depende de la fase entre la excursión y las medidas: se prueba en varias fases y se compara con la cota teórica, porque cumplir en una sola puede ser casualidad.
  • El consumo simulado (15,90 µA, 7,93 años) coincide con el presupuesto (15,78 µA, 7,97 años) salvo diferencias que se explican: la escritura en flash (+0,17 µA) y un reporte menos (−0,04 µA). La radio es el 78 % del consumo: pasar el reporte de 15 a 5 minutos lleva la corriente a 40,79 µA y la vida a 3,68 años.
  • El watchdog de 120 s reinicia un programa colgado y deja 125 s sin medir (plazo más arranque, contados desde la última alimentación); debe ser mayor que el período de alimentación y se alimenta al final de una medida completa. Una falla del sensor se informa una vez y el equipo sigue vivo.
  • La actualización es segura por orden y por verificación: marca de prueba al final y cargador que comprueba la imagen. Solo la combinación de las dos fallas (marca primero y cargador sin comprobar) deja 5 de 7 cortes sin arrancar. Se prueba cortando la energía en cada punto, con una flash simulada y con el banco.
  • Se libera con un plan de pruebas y una lista de verificación: trazabilidad sin huecos, integración continua en verde, versión marcada con huella y ELF archivados, depuración cerrada, consumo medido sin la sonda, actualización probada, documentación y plan de mantenimiento. Un tablero en verde solo prueba lo que se ejercitó.

¿Listo para el tema siguiente?

Antes de avanzar, tomá un proyecto tuyo, aunque sea pequeño, y probá este ejercicio: escribí sus cinco requisitos principales con número, construí un modelo ejecutable de veinte líneas que calcule su consumo y su latencia, y compará con lo que medís en una placa. Donde no coincidan, vas a aprender más que en cualquier tema.

En el último tema del curso hacemos el cierre: una revisión de lo recorrido, las buenas prácticas que se repiten en todos los bloques y el puente hacia el Internet de las Cosas, con los próximos pasos.