← Índice del curso

Sistemas Embebidos · Tema 35 · Bloque 7

Firmware de bajo consumo

Conocer los modos de sueño (tema 34) no alcanza: un firmware escrito como un bucle que consulta todo el tiempo no los puede aprovechar, porque nunca tiene un momento en que dormir. El bajo consumo es una propiedad de la arquitectura del programa. Este tema muestra cómo se estructura un firmware para que duerma casi todo el tiempo y trabaje a ráfagas breves: dejando que el hardware espere, convirtiendo cada tarea en una respuesta a un evento, suspendiendo el tick, alimentando cada periférico solo mientras se usa, configurando los pines para que no gasten y hablando por la radio lo menos posible.

01 · El enemigo

Del bucle ocupado a las ráfagas

Los primeros programas de todo aprendiz de firmware tienen la misma forma: un bucle infinito que lee un botón, lee un sensor, actualiza un LED y espera un poco con un retardo. Funciona perfectamente y es lo peor que se le puede hacer a una batería: la CPU ejecuta instrucciones sin parar, aun cuando no tiene nada útil que hacer, y el consumo es el de un núcleo activo (miliamperios) todo el tiempo. El objetivo de este tema es el contrario: que la CPU esté dormida casi siempre y despierte solo para un trabajo concreto, que termina lo antes posible.

Casi todos los consumos evitables de un firmware tienen una de seis formas:

Los patrones que impiden dormir y su reemplazo.
Patrón que gastaPor qué gastaReemplazo
Retardo por conteo (for (...) ;, delay_ms() con bucle)La CPU cuenta en vacío, al 100 %, durante todo el retardoUn temporizador de hardware que despierte al terminar, con la CPU dormida
Encuesta (polling) de un botón, un pin o una banderaLa CPU pregunta una y otra vez por algo que casi nunca cambiaUna interrupción por flanco: el hardware avisa y la CPU duerme mientras tanto
Espera activa a un periférico (while (!listo); con el ADC, la UART, el SPI)La CPU espera con el reloj completo lo que el periférico hace soloInterrupción de fin de operación, o WFI hasta que termine, o DMA
Tick periódico a 1 kHz «por si acaso»Despierta a la CPU mil veces por segundo aunque no haya trabajoUn sistema sin tick (apartado 4): se despierta solo cuando vence algo
Periféricos y sensores siempre encendidosEl ADC, el sensor y las comunicaciones consumen aunque no se usenEncender, usar y apagar (apartado 5)
Trabajo de más: muestrear, calcular o transmitir más seguido que lo necesarioCada ciclo cuesta un costo fijo de despertar, medir y transmitirMenos ciclos: informar por excepción, agrupar (apartados 3 y 7)
Tres formas de esperar y cuánto despierta la CPU Tres perfiles de actividad de la CPU en el tiempo. Arriba, un bucle con retardos: la CPU está activa todo el tiempo, una banda continua. En el medio, un sistema con WFI y tick de 1 kHz: la CPU está dormida en un nivel ligero pero con una espiga de despertar muy frecuente. Abajo, un sistema sin tick con sueño profundo: la CPU está casi siempre en un nivel mínimo, con solo dos espigas de trabajo real. 1. Bucle con retardos: la CPU nunca descansa 2. WFI con un tick de 1 kHz: duerme poco, despierta mil veces por segundo 3. Sin tick y con sueño profundo: despierta solo cuando hay trabajo real trabajotrabajo Lo que importa no es la altura de cada espiga sino cuánto tiempo pasa la CPU «arriba» y con qué frecuencia vuelve a subir. Los tres niveles de base (no a escala): activo, sleep ligero y stop o standby.

02 · La arquitectura

Diseño por eventos para poder dormir

La arquitectura que permite dormir es la orientada a eventos del tema 26, con una vuelta de tuerca: cuando la cola de eventos está vacía, el procesador duerme. Las interrupciones (de un temporizador, un pin, un periférico) publican eventos y despiertan al procesador; el bucle principal los procesa; y cuando no queda ninguno, vuelve a dormir. El bucle principal deja de ser un bucle que gira y pasa a ser un despachador que se detiene en el WFI:

typedef enum { EV_LECTURA_VENCIDA, EV_BOTON, EV_RX_LISTO, EV_FIN_TX } Evento;

/* La ISR hace lo mínimo: publica un evento (tema 16 y 26) y vuelve */
void EXTI0_IRQHandler(void)  { borrar_bandera_exti0(); cola_poner(EV_BOTON); }
void RTC_Alarm_IRQHandler(void) { borrar_bandera_rtc();  cola_poner(EV_LECTURA_VENCIDA); }

int main(void) {
    iniciar_hardware();
    iniciar_modulos();
    for (;;) {
        Evento e;
        __disable_irq();                          /* comprobar y dormir sin carrera (tema 34) */
        bool vacia = !cola_sacar(&e);
        if (vacia) energia_esperar();             /* WFI (sleep o stop) con las interrupciones aún enmascaradas */
        __enable_irq();                           /* aquí corre la ISR pendiente, que publica el evento */
        if (!vacia) despachar(e);                 /* el trabajo se hace FUERA de la sección crítica */
    }
}

static void despachar(Evento e) {
    switch (e) {
        case EV_LECTURA_VENCIDA: medir_y_guardar();  programar_proxima_lectura(); break;
        case EV_BOTON:           atender_boton();                                  break;
        case EV_RX_LISTO:        procesar_mensaje();                               break;
        case EV_FIN_TX:          radio_apagar();                                   break;
    }
}

Observá cómo se aplican los apartados de los temas anteriores: la cola es la de los temas 16 y 26, la comprobación atómica es la del tema 34, y energia_esperar() es el módulo que oculta qué modo se usa. Pero hay una propiedad nueva que el diseño debe cumplir: ninguna tarea puede esperar activamente. Cada vez que el código necesita «esperar a que algo termine», la espera se convierte en un evento:

Convertir una espera en un evento.
Diseño que bloqueaDiseño por eventos
adc_iniciar(); while (!adc_listo()); v = adc_leer();adc_iniciar(); y salir; la ISR de fin de conversión publica EV_ADC_LISTO; el manejador del evento lee el valor
uart_enviar(buf, n); while (!uart_vacia());Envío por interrupción o DMA; el fin de la transmisión publica EV_FIN_TX; recién entonces se apaga el periférico
delay_ms(5); para esperar que un sensor se estabiliceProgramar un temporizador de 5 ms y salir; su vencimiento publica el evento que sigue con la medición
Consultar cada 10 ms si el botón se apretóInterrupción por flanco del pin, con antirrebote por temporizador de una sola vez (tema 24)

El costo de este estilo es de diseño: el código de una operación larga (medir, transmitir, esperar la respuesta) se parte en varios manejadores encadenados por eventos. Es exactamente la máquina de estados del bloque 5: cada estado espera un evento, y el sistema duerme entre ellos. Un firmware de bajo consumo suele ser, en el fondo, una máquina de estados jerárquica con un WFI en el medio.

Existe una variante más extrema para programas simples que viven solo de interrupciones: con el bit SLEEPONEXIT (tema 34), el procesador vuelve a dormir automáticamente al terminar cada ISR, sin volver nunca al programa principal. Es la forma más económica (no hay bucle principal ni cambio de contexto), pero sirve solo cuando todo el trabajo cabe dentro de las interrupciones, con las limitaciones de tiempo y de datos compartidos que eso implica (tema 16).

03 · Trabajar a ráfagas

El ciclo de trabajo

Si el firmware trabaja a ráfagas, su consumo queda determinado por el ciclo de trabajo (duty cycle): la fracción del tiempo que pasa activo. Con una corriente activa Ia, una de reposo Ir y un ciclo de trabajo D = tactivo / T, la corriente media es:

Ciclo de trabajo y corriente media.
MagnitudFórmulaEjemplo
Ciclo de trabajoD = tactivo / T12 ms activos por cada 1 s: D = 1,2 %
Corriente mediaImedia = D · Ia + (1 − D) · Ir0,012 · 6 mA + 0,988 · 3 µA ≈ 75 µA

En el ejemplo, el 96 % de la corriente media viene de la parte activa, que ocupa el 1,2 % del tiempo. La fórmula dice que hay dos formas de bajar la media, y las dos son de diseño, no de optimización de instrucciones:

  • Hacer cada ráfaga más corta (menos tactivo): terminar el trabajo rápido y volver a dormir. Se logra con una frecuencia de reloj que acorte la tarea (tema 33), con menos cálculo, con hardware que trabaje solo (DMA), y evitando esperas dentro de la ráfaga.
  • Hacer menos ráfagas (más T): muestrear, calcular y transmitir lo mínimo que el requisito permite. Es la palanca más poderosa: la mejor operación es la que no se hace. Duplicar el período casi duplica la autonomía cuando domina la parte activa.

Además de la duración, cada ráfaga tiene un costo fijo: despertar (tema 34), encender el sensor, arrancar y sincronizar la radio. Ese costo no depende de cuánto se haga en la ráfaga, sino de que haya una. Eso lleva a una de las técnicas de mayor rendimiento: agrupar. En lugar de transmitir cada lectura, se acumulan N lecturas y se transmiten juntas, pagando el costo fijo de la radio una vez cada N. Con un costo fijo de 60 µC por transmisión y 30 µC por lectura transmitida (valores didácticos), el costo por lectura es 60 / N + 30:

Costo de radio por lectura según cuántas se agrupan por transmisión.
Lecturas por transmisión (N)Costo por lecturaAhorro frente a N = 1Lo que se paga
190 µC—Nada: cada dato sale al instante
445 µC50 %Un dato puede esperar hasta 3 períodos
1036 µC60 %Hasta 9 períodos de demora; memoria para 10 lecturas
3032 µC64 %Hasta 29 períodos de demora; el ahorro ya casi no crece

El ahorro tiene un límite (el costo variable de 30 µC no se elimina) y un precio: la latencia (un dato llega tarde) y la memoria para acumularlos (tema 30). Es una decisión de requisitos: si el usuario necesita saber de inmediato cuando algo cambia, se combina con el envío por excepción (apartado 7), que envía al instante lo importante y agrupa el resto.

04 · El latido que no deja dormir

El tick y el firmware sin tick

La mayoría de los firmware con RTOS o con un planificador (temas 17 a 20) tienen un tick: una interrupción periódica, casi siempre del SysTick y casi siempre de 1 ms, que mantiene la hora del sistema y despierta al planificador. Es cómodo, y es un enemigo del bajo consumo por dos motivos distintos:

  • Despierta a la CPU mil veces por segundo, aunque no haya nada que hacer. Cada despertar es breve (unos microsegundos), pero gasta energía de entrada y salida, y mil por segundo suman. Con valores didácticos (10 µs activos a 5 mA por despertar), la Parte 2 del programa de Python da 50 µA solo por el tick de 1 kHz, más que todo el consumo de un nodo bien diseñado.
  • El SysTick usa el reloj del núcleo, que se apaga en los sueños profundos. Con un tick de 1 kHz el procesador no puede entrar en stop ni en standby: se queda en el escalón de sleep ligero, con una corriente cientos de veces mayor. Es la causa más común de que un firmware con RTOS «no baje de un miliamperio».
Costo de un tick periódico (resultado de la Parte 2; cada despertar: 10 µs activos a 5 mA).
Frecuencia del tickDespertares por segundoCorriente media por despertar
1000 Hz100050 µA
100 Hz1005 µA
10 Hz100,5 µA
1 Hz10,05 µA

La solución es el firmware sin tick (tickless): en lugar de despertar cada milisegundo para ver si venció algo, el sistema calcula cuándo vence lo próximo, programa un temporizador de bajo consumo (el RTC o un temporizador que sigue corriendo dormido) para ese instante, y duerme profundo hasta entonces. Al despertar, corrige la hora del sistema con el tiempo que realmente pasó. Los RTOS lo ofrecen incorporado: en FreeRTOS se activa con configUSE_TICKLESS_IDLE, y cuando la tarea inactiva detecta que no habrá trabajo por al menos configEXPECTED_IDLE_TIME_BEFORE_SLEEP ticks, llama a la macro portSUPPRESS_TICKS_AND_SLEEP(), que el puerto implementa con el temporizador de bajo consumo y el sueño del chip, y a la vuelta ajusta la cuenta de ticks con vTaskStepTick(). Los ganchos configPRE_SLEEP_PROCESSING y configPOST_SLEEP_PROCESSING permiten apagar y volver a encender relojes y periféricos alrededor del sueño.

En un firmware sin RTOS, la misma idea se programa en pocas líneas: la hora sale del contador del RTC (que corre dormido) y el planificador duerme hasta la próxima tarea que vence:

/* Un planificador cooperativo sin tick: duerme hasta la próxima tarea que vence */
uint32_t ahora_ms(void);                       /* lee el contador del RTC: sigue corriendo con el chip dormido */
void     rtc_alarma_en(uint32_t ms);           /* programa la alarma del RTC para dentro de 'ms' */

void planificador_esperar(void) {
    uint32_t t = ahora_ms(), siguiente = UINT32_MAX;
    for (int i = 0; i < N_TAREAS; i++) {
        uint32_t resta = tareas[i].proxima - t;          /* aritmética sin signo: sigue bien aunque el contador dé la vuelta */
        if ((int32_t)resta < 0) resta = 0;               /* ya venció */
        if (resta < siguiente) siguiente = resta;
    }
    if (siguiente > MARGEN_MINIMO_MS) {                  /* solo vale la pena dormir profundo si la espera amortiza el despertar */
        rtc_alarma_en(siguiente);
        energia_dormir_profundo();                       /* stop o standby: el tema 34 dice cuál */
    }                                                    /* si falta muy poco, se queda despierto o duerme ligero */
}

Dos cuidados. Primero, el MARGEN_MINIMO_MS: dormir profundo solo se amortiza si la espera supera el punto de equilibrio del tema 34; para esperas más cortas, un sueño ligero o seguir despierto cuesta menos. Segundo, la precisión del tiempo: el RTC con un cristal de 32,768 kHz es preciso; con un oscilador RC interno la hora se desvía, y las tareas con plazos exactos deben tenerlo en cuenta.

05 · Encender, usar y apagar

Periféricos apagados y relojes lentos

Un periférico con el reloj habilitado consume, lo use o no (tema 33). La regla de oro es el ciclo encender, usar, apagar, aplicada a tres niveles: el reloj del periférico dentro del chip, el periférico mismo, y el circuito externo al que sirve (un sensor, una memoria, una radio). El caso típico, una medición con alimentación del sensor controlada por un pin:

uint16_t medir_temperatura(void) {
    gpio_escribir(PIN_SENSOR_ALIM, 1);           /* alimentar el sensor desde un pin: sin medir, no consume */
    esperar_ms_dormido(5);                       /* estabilización que pide la hoja de datos: con un temporizador y la CPU dormida */
    adc_encender();                              /* habilita el reloj del ADC y lo activa */
    uint16_t v = adc_convertir(CANAL_TEMP);      /* conversión por interrupción: la CPU duerme mientras convierte */
    adc_apagar();                                /* apaga el ADC y su reloj */
    gpio_escribir(PIN_SENSOR_ALIM, 0);           /* quitar la alimentación al sensor */
    return v;
}

Observá esperar_ms_dormido: la espera del sensor es uno de los puntos donde un retardo por conteo desperdiciaría los 5 ms con la CPU activa. Y la alimentación desde un pin sirve mientras la corriente del sensor sea menor que lo que el pin entrega (algunos mA); para cargas mayores se usa un transistor o un interruptor de carga controlado por el pin. El ahorro de este patrón es grande: en la Parte 1 del programa, un sensor siempre alimentado (150 µA de reposo en el ejemplo) pasaba de dominar el consumo a no aparecer en la cuenta.

El segundo recurso son los relojes. Un chip suele tener varias fuentes de reloj, con compromisos de precisión, consumo y tiempo de arranque que conviene conocer:

Fuentes de reloj típicas de un microcontrolador y sus compromisos (orientativo).
FuenteFrecuencia típicaPrecisiónConsumo y arranqueSe usa para
Oscilador RC interno rápido (HSI)Algunos MHz a decenas de MHzModerada (del orden del 1 %)Bajo; arranca en microsegundosReloj de arranque y de trabajo cuando no hay comunicaciones exigentes; reloj al salir de stop
Cristal externo rápido (HSE)Pocos MHz a 25 MHzAltaMayor; milisegundos en estabilizarseUSB, radio, comunicaciones precisas
PLLDecenas a cientos de MHzLa del reloj de entradaAlto; decenas a cientos de µs en engancharseMáxima velocidad; se apaga cuando no hace falta
Cristal de 32,768 kHz (LSE)32 768 HzAltaDel orden de unos µA o menosRTC y despertares precisos mientras todo lo demás duerme
Oscilador RC interno lento (LSI)Unas decenas de kHzBajaMuy bajoWatchdog independiente; temporizadores sin precisión

Las prácticas que se derivan:

  • Para el tiempo mientras se duerme, el cristal de 32,768 kHz. Consume muy poco y da una base precisa para el RTC y los despertares. Un RC lento ahorra el cristal, pero la hora se desvía y hay que sobredimensionar los márgenes.
  • El reloj rápido solo mientras trabaja. Una estrategia común: despertar con el oscilador interno (que arranca enseguida), hacer el trabajo, y subir el PLL y el cristal solo si hace falta una comunicación precisa o un cálculo pesado. Si el trabajo corto no necesita más, no se sube.
  • La frecuencia como parámetro de diseño. Como vimos en el tema 33 (Parte 5), correr más rápido y dormir antes puede gastar menos energía por tarea si el consumo fijo es apreciable, pero no siempre. Para una carga continua y liviana que no permite dormir (un control de lazo cerrado de 1 kHz, por ejemplo), conviene en cambio la frecuencia más baja que cumple el plazo. Se decide midiendo.
  • Al cambiar la frecuencia, reconfigurar lo que depende de ella: los divisores de la UART, los preescalares de los temporizadores y los estados de espera de la flash. Un error clásico del tema 34: despertar con otro reloj y que la comunicación salga como basura.
  • Apagar los relojes de los módulos que no se usan (tema 9): en los STM32, __HAL_RCC_xxx_CLK_DISABLE(); en los AVR, power_xxx_disable(). Muchos chips los dejan encendidos por defecto o los encienden la HAL de ST al inicializar.

06 · El consumo invisible

Pines que no gastan

Los pines son una fuente de consumo traicionera, porque no aparecen en ninguna línea del programa que «haga» algo. Un pin configurado como entrada flotante (sin nada que fije su nivel) tiene una tensión que deriva por el aire; el buffer de entrada CMOS, al quedar en la zona intermedia, conduce una corriente a través de sus dos transistores, y la fuga puede ser de decenas o cientos de µA por pin según el chip y las condiciones. Un nodo con diez pines sin configurar puede gastar más dormido que durante toda una transmisión. La regla es que todos los pines tienen que estar en un estado definido antes de dormir:

Cómo configurar cada pin para dormir.
Situación del pinConfiguración recomendadaPor qué
Sin conectar a nadaModo analógico (en STM32) o salida a nivel bajoEl modo analógico desconecta el buffer de entrada: el consumo mínimo
Entrada con un nivel externo siempre definido (otro chip lo maneja)Entrada sin resistencia internaEl nivel está fijado desde afuera
Entrada que puede quedar flotante (un conector, un sensor desconectable)Entrada con resistencia interna hacia un nivel (arriba o abajo)Fija el nivel y evita la deriva
Pulsador con resistencia hacia arribaEntrada con pull-up, despertar por flancoConsume solo mientras está apretado: 3,3 V / 40 kΩ ≈ 82 µA durante el tiempo de pulsación
Salida sin cargaAl nivel que el circuito externo necesite, nunca flotanteNo consume, pero un nivel incorrecto puede excitar algo
Salida que excita una carga (LED, sensor)En el nivel que apaga la carga antes de dormirLa corriente de la carga se suma al consumo dormido
Pines de depuración (SWD)Mantenerlos mientras se depura; liberarlos o fijarlos en el producto finalPonerlos en analógico corta la comunicación con el depurador
/* Antes de dormir: todos los pines en modo analógico (consumo mínimo), y después se vuelven a configurar solo los que SÍ se usan */
void pines_modo_sueno(void) {
    GPIO_InitTypeDef g = { .Pin = GPIO_PIN_All, .Mode = GPIO_MODE_ANALOG, .Pull = GPIO_NOPULL };
    HAL_GPIO_Init(GPIOA, &g);   HAL_GPIO_Init(GPIOB, &g);   HAL_GPIO_Init(GPIOC, &g);

    /* Los que sí tienen una función durante el sueño: */
    gpio_configurar_entrada_con_pull_up(PIN_BOTON);        /* despertar por flanco */
    gpio_configurar_salida(PIN_SENSOR_ALIM, NIVEL_BAJO);   /* el sensor apagado */
    /* En desarrollo se excluyen PA13 y PA14 (SWD): en analógico se pierde la conexión con el depurador */
}

El paso complementario es revisar el esquema electrónico con la hoja de datos del chip abierta: qué pines tiene el chip, a qué está conectado cada uno, y en qué estado queda. Es un trabajo de una hora que suele recuperar decenas de µA; la Parte 1 del programa de Python muestra que 30 µA de pines flotantes, en un nodo con 32 µA, duplican el consumo.

07 · El mayor consumidor

Hablar poco: la comunicación

En casi todo dispositivo conectado, el módulo de comunicación inalámbrica (Wi-Fi, Bluetooth, LoRa, celular) es el mayor consumidor de energía por mucho: decenas a cientos de miliamperios al transmitir, y también al escuchar. En el tema 33 vimos que acortar a la mitad el tiempo de radio rendía casi seis veces más que bajar el reposo. Por eso el diseño de la comunicación es la palanca principal en cualquier equipo a batería, y tiene cuatro principios:

  • Transmitir lo menos posible. Cada mensaje cuesta lo mismo, lleve poco o mucho. Antes de optimizar cómo se envía, la pregunta es si hace falta enviarlo.
  • Agrupar (apartado 3): acumular y enviar juntos reparte el costo fijo de cada transmisión.
  • Mensajes cortos. Menos bytes, menos tiempo de radio encendida: codificar en binario en lugar de texto, enviar diferencias en lugar de valores completos, descartar campos que el receptor puede deducir.
  • Escuchar es caro. Un receptor encendido consume tanto como (o más que) uno que transmite. Los protocolos de bajo consumo evitan la escucha continua con ventanas de recepción programadas: el dispositivo abre el receptor solo en momentos acordados, justo después de transmitir.

Informar por excepción

Cuando la magnitud medida cambia lentamente (una temperatura, un nivel de depósito, un estado), la técnica de mayor rendimiento es transmitir solo cuando hay un cambio significativo, más un latido periódico que confirma que el dispositivo sigue vivo. El receptor asume que, si no llegó nada, el valor no cambió más que el umbral. La Parte 3 del programa lo simula con 24 horas de lecturas de temperatura cada 10 s (una caminata al azar):

Mensajes en un día según la política de transmisión (resultado de la Parte 3).
PolíticaMensajes por díaRespecto del periódicoError máximo del último valor informado
Periódico, cada 60 s1440100 %—
Por excepción, umbral 0,10 °C56939,5 %0,10 °C
Por excepción, umbral 0,25 °C1047,2 %0,25 °C
Por excepción, umbral 0,50 °C392,7 %0,50 °C
Por excepción, umbral 1,00 °C251,7 %0,99 °C

Con un umbral de 0,5 °C (un error que muchos usos toleran), se transmite el 2,7 % de los mensajes. Con 90 µC por mensaje (valores didácticos), el costo de radio pasa de 1,50 µA de media a 0,04 µA. El precio es doble: el error acotado por el umbral (el receptor sabe el valor con esa tolerancia, no exacto) y la necesidad del latido, sin el cual el receptor no puede distinguir «no hay cambios» de «el dispositivo murió». Tampoco sirve cuando el receptor necesita el historial completo de las lecturas.

08 · El resto de los detalles

Otros hábitos que cuestan o ahorran

Hábitos de programación y configuración con efecto sobre el consumo.
HábitoEfectoQué hacer
Mensajes de depuración por la UART en el productoMantienen la UART y el procesador activos; formatear texto cuesta ciclos y flashCompilarlos fuera del producto con una macro; registros compactos por códigos (tema 32)
Depurador conectadoMantiene relojes y dominios de depuración activos (tema 34)Medir sin él; en el producto final, desactivar la depuración si la seguridad lo pide
Watchdog independienteSigue corriendo dormido con su reloj lento; consume un poco y exige despertar para atenderloElegir el período del watchdog en función del ciclo de sueño (tema 38); un despertar de mantenimiento solo para el perro es un costo real
Detector de baja tensión (BOR)Consume unos µA, siempreDejar habilitado el nivel que la batería necesita (tema 37); no deshabilitarlo sin análisis: protege los datos
Retención de RAMEn chips que permiten retener solo parte de la RAM en el sueño, cada bloque retenido consumeRetener solo lo que hace falta, y sacar el resto
Esperas de la flash a alta frecuenciaEjecutar a la frecuencia máxima exige ciclos de espera y consume más por cicloElegir la frecuencia que cumple el plazo con el menor consumo (se mide)
Bibliotecas y HAL genéricasSuelen dejar periféricos y relojes habilitados «por si acaso»Revisar qué deja encendido cada inicialización, y apagar lo que sobra
Corrientes de polarización externasDivisores, pull-ups y LED de estado de la placa (tema 33)Cambiar valores, desconectar con un pin o quitarlos del diseño

El patrón común: casi todos estos consumos son decisiones por defecto que nadie tomó a conciencia. Los chips y las bibliotecas vienen configurados para que todo funcione, no para que consuma poco, y el trabajo de un firmware de bajo consumo es revisar cada valor por defecto y preguntar si hace falta.

09 · Comprobar que funciona

Verificación y diagnóstico

Comprobaciones sobre un firmware de bajo consumo.
Qué verificarCómoResultado esperado
Que la CPU duerme casi todo el tiempoSacar un pin a nivel alto al despertar y a bajo al dormir; medirlo con un analizador (tema 18)El pin está en alto una fracción pequeña del ciclo (el ciclo de trabajo esperado)
El perfil de corrienteRegistrar la corriente de la placa durante varios ciclos con un analizador de consumo (tema 36)Espigas del tamaño y la duración del presupuesto; una línea base igual al reposo calculado
Ausencia de espera activaBuscar en el código while (!...) sobre periféricos y retardos por conteoNinguno en la ruta normal; los que queden, justificados y acotados
Ausencia de despertares espuriosContar los despertares por minuto en un contador de depuraciónCoincide con los eventos esperados; el tick no despierta en el sueño profundo
Estado de los pines al dormirComparar la corriente dormido con los pines en un estado y en otroSin diferencias de decenas de µA entre configuraciones razonables
Periféricos y relojes habilitadosLeer los registros de habilitación de relojes con el depurador antes de dormirSolo los que se necesitan para despertar
Número de transmisiones por díaContarlas en el firmware y compararlas con el diseñoEl esperado según la política (periódica, por excepción, agrupada)
La autonomíaRepetir el presupuesto del tema 33 con las corrientes medidasCumple el requisito con margen
Síntomas frecuentes y qué revisar.
SíntomaCausa probableQué hacer
El consumo dormido es del orden de 1 mA con un RTOSEl tick del SysTick impide los sueños profundosActivar el modo sin tick del RTOS; verificar los ganchos de sueño y los relojes
El consumo dormido es de cientos de µA en un equipo sin RTOSPines flotantes, periféricos con el reloj habilitado, un sensor siempre alimentadoRecorrer la tabla del apartado 6 y la de los consumidores del tema 33
El equipo despierta muchas más veces de las esperadasUna fuente por nivel, rebotes, una bandera que no se borra, interrupciones de periféricos sin usarContar las causas de despertar; borrar banderas; deshabilitar lo que no se usa
La CPU está activa más tiempo que el diseñoEsperas activas escondidas (en bibliotecas, en el controlador de un periférico)Medir cuánto dura cada ráfaga; revisar con un analizador qué la alarga
La medición con el sensor da valores raros tras apagarlo y encenderloNo se respetó el tiempo de estabilizaciónEsperar lo que pide la hoja de datos (dormido, con un temporizador)
Se perdió un evento mientras el equipo dormíaLa carrera entre comprobar y dormir (tema 34), o una cola sin protecciónEnmascarar las interrupciones al comprobar; revisar la cola
La hora del sistema se desvíaSe usa un oscilador RC lento para el RTC, o no se corrige el tick al despertarCristal de 32,768 kHz; corregir la hora con el tiempo medido por el RTC
El consumo medio supera al calculado pese a todoEventos raros (reintentos de radio, reconexiones) que el presupuesto no incluyóMedir durante un período largo, con los eventos de falla incluidos

10 · Analogía con programación

Probar el modelo en Python

El programa rediseña paso a paso el mismo nodo del tema 33 (una lectura cada 10 s, con dos pilas AA), sumando una decisión de diseño por vez, y tiene tres partes: la escalera de rediseño con la corriente media y la autonomía de cada versión, el costo de distintos ticks periódicos, y la simulación de 24 horas de lecturas para comparar el envío periódico con el envío por excepción. Los valores eléctricos son didácticos; lo que se aprende es el orden de magnitud de cada decisión y cuál rinde más.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

# Firmware de bajo consumo: la misma tarea, rediseñada paso a paso. Valores DIDÁCTICOS (órdenes de magnitud de un Cortex-M).
import random
HORAS_ANIO = 8766
CAPACIDAD_UTIL_MAH, AUTODESCARGA_UA = 2500 * 0.75, 5.70          # 2 AA alcalinas del tema 33
T = 10.0                                                         # una lectura cada 10 s

IDLE = {                                                         # (corriente de espera en µA, carga extra por despertar en µC)
    "bucle con retardos (CPU activa)": (5000.0, 0.0),
    "WFI con tick de 1 kHz": (1500.0 + 1000 * 0.05 * 1000 / 1000, 0.0),      # 1500 µA de sleep + 1000 despertares/s de 10 µs a 5 mA = 50 µA
    "stop con despertar por RTC (sin tick)": (20.0, 5.0 * 0.2),               # 20 µA; cada despertar cuesta 5 mA * 0,2 ms = 1 µC
    "standby con despertar por RTC": (2.0, 5.0 * 6.0),                        # 2 µA; cada despertar cuesta 5 mA * 6 ms = 30 µC
}
def corriente_media(idle, sensor_apagado, pines_ok, n_por_paquete):
    i_idle, q_despertar = IDLE[idle]
    q_medida = 3.0 * 10.0                                        # 3 mA * 10 ms = 30 µC por lectura
    q_radio = (60.0 + 30.0 * n_por_paquete) / n_por_paquete      # 60 µC fijos por paquete + 30 µC por lectura transmitida, repartidos
    i_sensor = 0.0 if sensor_apagado else 150.0                  # un sensor siempre alimentado
    i_pines = 0.0 if pines_ok else 30.0                          # pines flotantes
    return i_idle + (q_despertar + q_medida + q_radio) / T + i_sensor + i_pines
def anios(i_ua):
    return CAPACIDAD_UTIL_MAH / ((i_ua + AUTODESCARGA_UA) / 1000) / HORAS_ANIO

print("Parte 1: el mismo nodo (una lectura cada 10 s), rediseñado paso a paso")
escalera = [
    ("diseño ingenuo: bucle con retardos, sensor siempre alimentado, pines sin configurar", ("bucle con retardos (CPU activa)", False, False, 1)),
    ("+ por eventos con WFI y tick de 1 kHz",                                           ("WFI con tick de 1 kHz", False, False, 1)),
    ("+ sin tick: stop con despertar por RTC",                                          ("stop con despertar por RTC (sin tick)", False, False, 1)),
    ("+ sensor alimentado solo al medir",                                               ("stop con despertar por RTC (sin tick)", True, False, 1)),
    ("+ pines sin usar en modo analógico",                                              ("stop con despertar por RTC (sin tick)", True, True, 1)),
    ("+ una transmisión cada 10 lecturas",                                              ("stop con despertar por RTC (sin tick)", True, True, 10)),
    ("+ standby en lugar de stop (la RAM no hace falta)",                               ("standby con despertar por RTC", True, True, 10)),
]
anterior = None
for etiqueta, args in escalera:
    i = corriente_media(*args)
    mejora = "" if anterior is None else f"  (÷ {anterior / i:.1f})"
    print(f"  {etiqueta:<82} {i:9.1f} µA -> {anios(i):8.2f} años{mejora}")
    anterior = i

print()
print("Parte 2: el costo de un tick periódico (cada despertar: 10 µs activos a 5 mA = 0,05 µC)")
for f in (1000, 100, 10, 1):
    print(f"  tick de {f:>4} Hz: {f * 0.05:6.2f} µA de media solo por despertar al procesador")
print(f"  un stop con RTC cuesta 20 µA de base; con un tick de 1 kHz el SysTick ni siquiera funciona en stop (su reloj se detiene)")

print()
print("Parte 3: informar solo cuando cambia (24 h, una lectura cada 10 s, caminata al azar)")
rnd = random.Random(3)
valor, lecturas = 20.0, []
for _ in range(8640):
    valor += rnd.gauss(0.0, 0.03)
    lecturas.append(valor)
def simular(umbral, latido_s):
    enviados, ultimo, desde = 0, None, 0
    peor_error = 0.0
    for lectura in lecturas:
        desde += 10
        if ultimo is None or abs(lectura - ultimo) >= umbral or desde >= latido_s:
            ultimo, desde = lectura, 0
            enviados += 1
        peor_error = max(peor_error, abs(lectura - ultimo))
    return enviados, peor_error
print(f"  periódico cada 60 s            : {86400 // 60:5d} mensajes en el día")
for umbral in (0.1, 0.25, 0.5, 1.0):
    n, err = simular(umbral, 3600)
    print(f"  por excepción (umbral {umbral:4.2f} °C, latido de 1 h): {n:5d} mensajes ({n / 1440 * 100:5.1f} % del periódico), error máximo del último valor informado {err:4.2f} °C")

Resultado, parte 1: el diseño ingenuo (bucle con retardos, sensor siempre alimentado y pines sin configurar) consume 5192 µA y dura 0,04 años (unos 15 días). Cada rediseño suma una mejora: pasar a eventos con WFI y tick de 1 kHz baja a 1742 µA (÷3,0, 0,12 años); quitar el tick y usar stop con despertar por RTC, a 212,1 µA (÷8,2, 0,98 años); alimentar el sensor solo al medir, a 62,1 µA (÷3,4, 3,15 años); poner los pines en analógico, a 32,1 µA (÷1,9, 5,66 años); agrupar una transmisión cada 10 lecturas, a 26,7 µA (÷1,2, 6,60 años); y pasar a standby (si la RAM no hace falta), a 11,6 µA (÷2,3, 12,36 años). El total es una mejora de unas 450 veces en el consumo y de unas 300 veces en la autonomía, sin cambiar ni una sola de las funciones del producto. Parte 2: un tick de 1000 Hz cuesta 50 µA, uno de 100 Hz 5 µA, uno de 10 Hz 0,5 µA y uno de 1 Hz 0,05 µA, y el SysTick no funciona en stop. Parte 3: el envío periódico cada minuto son 1440 mensajes por día; por excepción con un latido de una hora, el umbral de 0,10 °C da 569 (39,5 %), el de 0,25 °C da 104 (7,2 %), el de 0,50 °C da 39 (2,7 %) y el de 1,00 °C da 25 (1,7 %), con un error máximo igual al umbral.

Probá cambiar el orden de la escalera (por ejemplo, empezar por agrupar la radio) y mirá que las mejoras no se suman, se multiplican en cadena, y que cada una vale más o menos según lo que ya se arregló antes: arreglar los pines vale 30 µA, que importan poco en un diseño de 5000 µA y mucho en uno de 62. Por eso se ataca siempre primero lo que más pesa.

11 · Exploración interactiva

Rediseñar el nodo

El laboratorio usa el modelo de la Parte 1: un nodo que mide cada T segundos y transmite, con dos pilas AA. Elegís cómo espera (bucle con retardos, WFI con tick, stop o standby), si el sensor se alimenta solo al medir, si los pines están configurados y cuántas lecturas se agrupan por transmisión. Ves la corriente media (que incluye los 5,7 µA de autodescarga de las pilas), la autonomía y qué componente pesa más en cada versión.

De un firmware ingenuo a uno de bajo consumo

Corriente media total—
Autonomía (2 AA, 75 %)—

Reparto de la corriente

Elegí un diseño.

Recorrido guiado

  1. Con el diseño ingenuo (los valores iniciales), la corriente media es de unos 5200 µA y el nodo dura unos 15 días. La barra «Espera» ocupa casi todo: la CPU nunca duerme.
  2. Apretá «Por eventos con WFI y tick»: baja a unos 1750 µA (÷3). Ahora la CPU duerme, pero el tick y el escalón ligero del sueño siguen pesando.
  3. Cambiá la espera a Stop con despertar por RTC: la corriente cae a unos 218 µA (÷8). Quitar el tick y dormir profundo es el salto más grande de toda la escalera. Ahora el mayor consumidor es el sensor siempre alimentado (150 µA).
  4. Marcá «El sensor se alimenta solo al medir»: unos 68 µA. Y luego «Pines sin usar en modo analógico»: unos 38 µA, y la autonomía pasa de unos 3 años a unos 5,7.
  5. Subí las lecturas por transmisión a 10: baja a unos 32 µA. Es una mejora chica (÷1,2) porque lo que queda es sobre todo el reposo del stop y la autodescarga. Fijate que las barras de «Radio» y «Medida» son ahora pequeñas.
  6. Cambiá la espera a Standby (si la RAM no hace falta): unos 17 µA (11,6 del equipo y 5,7 de autodescarga de las pilas) y más de 12 años. Y probá el período de 10 minutos: la radio y la medida casi desaparecen del reparto y manda la espera; entonces importa mucho más el modo de sueño que el resto.
Desafío: ¿qué cambiaría si el nodo tuviera que reaccionar en menos de 1 ms a un evento externo?

La espera dejaría de poder ser standby, cuyo despertar tarda milisegundos (tema 34), y probablemente de poder ser stop si su latencia (cientos de µs en el ejemplo) más la restauración del reloj compromete el plazo. Se podría usar sleep ligero con un reloj activo, pagando una corriente de espera cientos de veces mayor, o buscar hardware que haga la parte urgente sin la CPU: un comparador analógico o un periférico de captura que reaccione al evento por sí mismo (cambiando una salida, disparando un DMA) y que despierte a la CPU solo para el trabajo no urgente. El diseño de bajo consumo, en estos casos, baja la responsabilidad a un hardware que gasta microamperios en lugar de dejar despierta a una CPU que gasta miliamperios. Es el motivo por el que los chips modernos de bajo consumo tienen periféricos que operan en los modos profundos.

12 · Método de trabajo

Método: diseñar para dormir

  1. Empezá por el presupuesto (tema 33): el requisito de autonomía, la batería y el perfil de consumo esperado. Dice cuánta corriente media se puede gastar, y entonces qué técnicas hacen falta.
  2. Listá lo que despierta al sistema: temporizadores, pines, comunicaciones. Para cada evento, ¿qué hardware lo espera? Ninguna espera se hace con la CPU.
  3. Estructurá el programa por eventos con un único lugar donde se duerme, comprobando de forma atómica que no hay trabajo pendiente.
  4. Eliminá el tick o reducilo al mínimo: un temporizador de bajo consumo que despierte solo cuando vence algo.
  5. Aplicá el ciclo «encender, usar, apagar» a cada periférico y a cada circuito externo, incluida la alimentación de los sensores.
  6. Definí el estado de cada pin para dormir, revisando el esquema con la hoja de datos.
  7. Elegí los relojes: cristal de 32,768 kHz para el tiempo mientras duerme; reloj rápido solo mientras se trabaja; la frecuencia más baja que cumpla los plazos en cargas continuas.
  8. Diseñá la comunicación primero para no usarla: informar por excepción, agrupar, mensajes cortos, ventanas de escucha.
  9. Atacá en el orden en que pesa: medí, mirá la barra más grande del reparto, arreglala y repetí. Un cambio mejora más o menos según lo que ya se arregló.
  10. Medí el producto real (tema 36) sin el depurador y con eventos raros incluidos. Un firmware de bajo consumo no se declara así: se mide así.

13 · Comprensión

Confusiones frecuentes

«Con ponerle un __WFI() al bucle principal, el firmware es de bajo consumo»

Lo es solo si no hay nada más que despierte al chip todo el tiempo. Un tick de 1 kHz lo despierta mil veces por segundo, un periférico habilitado sigue consumiendo, un sensor sigue encendido. En el escalón de la Parte 1, WFI con tick baja el consumo a un tercio; el resto de la mejora viene de otras decisiones.

«Un retardo de pocos milisegundos no importa»

Si se repite en cada ciclo, es tiempo activo puro. Un delay_ms(5) en un ciclo de 10 s mantiene la CPU a plena potencia durante el 0,05 % del tiempo, pero a 5 mA eso son 25 µC por ciclo, comparable al costo de toda la medición del ejemplo. Se hace con un temporizador y la CPU dormida.

«El tick de 1 ms es inofensivo: son unos pocos ciclos»

Mil veces por segundo. Con valores razonables suma decenas de µA, más que todo el consumo de un nodo bien diseñado, y además impide los sueños profundos porque el SysTick usa un reloj que se apaga. Para un dispositivo a batería, el tick periódico es lo primero que se elimina.

«Los pines que no uso no gastan nada»

Un pin sin configurar es una entrada flotante, y su buffer puede conducir una corriente de decenas o cientos de µA. La configuración de los pines sin usar (analógico o nivel definido) es una de las mejoras más baratas del diseño.

«Agrupar mensajes siempre ahorra»

Ahorra el costo fijo, pero el ahorro tiene un tope (el costo variable no desaparece), agrega latencia (los datos llegan tarde) y obliga a acumular en memoria. Si el requisito exige la inmediatez, se combina con el envío por excepción, o directamente no se agrupa.

«Informar por excepción pierde información»

Pierde la que cambió menos que el umbral, que por diseño no interesaba. El receptor conoce el valor con una tolerancia acotada. Lo que sí hace falta es un latido para distinguir «sin cambios» de «dispositivo caído». Si el uso requiere todas las lecturas, no es la técnica adecuada.

«Optimizar el firmware se hace al final, cuando todo funciona»

Las decisiones de este tema son de arquitectura: si el firmware nació con retardos por conteo, sondeos y un tick, hay que reestructurarlo, no ajustarlo. El bajo consumo se diseña desde el principio, con el presupuesto del tema 33 a la vista, y se mide durante todo el desarrollo.

«Un firmware de bajo consumo es un firmware lento»

Al contrario: suele ser más reactivo, porque está dormido esperando eventos en lugar de ocupado haciendo otra cosa. Lo que se sacrifica es la comodidad de «pensar en bucle»; lo que se gana es un sistema donde todo es una respuesta a algo que pasó, el estilo que ya vimos en el bloque de máquinas de estados.

14 · Práctica guiada

Ejercicios

1. El costo de un tick

Un sistema tiene un tick de 100 Hz. Cada despertar dura 20 µs a 8 mA. ¿Qué corriente media agrega solo por el tick? ¿Y si el tick fuera de 1 kHz?

Ver solución

Cada despertar gasta 8 mA × 20 µs = 0,16 µC. A 100 Hz: 100 × 0,16 µC = 16 µC por segundo = 16 µA. A 1 kHz: 1000 × 0,16 = 160 µC por segundo = 160 µA. Para un nodo cuyo objetivo es consumir unas decenas de µA en total, ni el de 100 Hz es aceptable: hay que eliminarlo o pasar a un sistema sin tick.

2. Agrupar

Una transmisión cuesta 80 µC fijos más 20 µC por cada lectura incluida. Se mide cada 30 s. Calculá el costo por lectura y la corriente media de radio con N = 1 y con N = 8. ¿Cuánto puede demorarse un dato con N = 8?

Ver solución

N = 1: 80 + 20 = 100 µC por lectura; media = 100 / 30 s = 3,33 µA. N = 8: 80 / 8 + 20 = 30 µC por lectura; media = 30 / 30 = 1,0 µA. El ahorro es del 70 %. La primera lectura de cada paquete espera a las otras siete: hasta 7 × 30 s = 210 s (3,5 minutos). Si ese plazo es aceptable, la técnica es muy buena; si el requisito dice «avisar en menos de 1 minuto», no.

3. Ciclo de trabajo

Un equipo trabaja 12 ms a 6 mA cada 1 s y duerme a 3 µA el resto. Calculá el ciclo de trabajo, la corriente media y qué parte aporta la ráfaga. ¿Qué pasa con la media si se mide cada 500 ms en lugar de cada 1 s?

Ver solución

D = 12 ms / 1000 ms = 1,2 %. Media = 0,012 × 6 mA + 0,988 × 0,003 mA = 0,072 + 0,00296 ≈ 0,0750 mA = 75 µA. La ráfaga aporta 72 de 75 µA: el 96 %. Si se mide cada 500 ms, el ciclo de trabajo se duplica a 2,4 % y la media casi se duplica: unos 147 µA (0,024 × 6 + 0,976 × 0,003 = 0,147 mA). Es la prueba de que, con el ciclo de trabajo chico, la autonomía es casi inversamente proporcional a la frecuencia de las mediciones.

4. El pulsador y la resistencia

Un pulsador usa el pull-up interno de 40 kΩ a 3,3 V. ¿Qué corriente consume mientras está apretado? Si el usuario lo aprieta 10 % del día, ¿cuánto es la media?

Ver solución

I = 3,3 V / 40 kΩ = 82,5 µA mientras está apretado. Con el 10 % del día apretado, la media es 0,10 × 82,5 = 8,25 µA: para un nodo de 30 µA, un 27 % más. Soluciones: un pull-up de mayor valor (el despertar por flanco no necesita una corriente alta), o activar el pull-up solo mientras se muestrea la entrada, o un diseño en que el pulsador cierre contra una resistencia que solo conduzca al apretar.

5. Despertares por minuto

Un sistema con eventos reales una vez por segundo usa un tick de 1 ms. ¿Cuántos despertares por minuto hace? ¿Y con un sistema sin tick? ¿Cuántas veces menos?

Ver solución

Con tick de 1 ms: 1000 despertares por segundo × 60 = 60 000 por minuto. Sin tick, solo despierta por los eventos: 60 por minuto. Son 1000 veces menos. Con el costo por despertar del ejercicio 1 (0,16 µC), son 9600 µC por minuto contra 9,6 µC. Y, más importante todavía, sin tick el procesador puede usar el sueño profundo entre eventos.

6. Informar por excepción

Con los resultados de la Parte 3, un mensaje cuesta 90 µC. Calculá el costo de radio diario (en µC) y la corriente media del periódico (1440 mensajes) y del de umbral 0,5 °C (39 mensajes). ¿Qué hay que agregar para que el receptor confíe en el sistema?

Ver solución

Periódico: 1440 × 90 = 129 600 µC por día; en 86 400 s son 1,50 µA de media. Por excepción: 39 × 90 = 3510 µC; 0,041 µA. Es una reducción de 37 veces. Para que el receptor confíe hace falta un latido (en la simulación, uno por hora, ya incluido en los 39 mensajes) para distinguir «sin cambios» de «dispositivo sin batería o sin cobertura», y que el receptor sepa y acepte la tolerancia de 0,5 °C. Si hay que detectar el fallo en menos de una hora, el latido tiene que ser más frecuente, y la reducción, menor.

15 · Síntesis

Ideas para recordar

  • El bajo consumo es una propiedad de la arquitectura: el firmware tiene que estar dormido casi siempre y trabajar a ráfagas. Los enemigos son los retardos por conteo, la encuesta, la espera activa, el tick periódico, los periféricos siempre encendidos y el trabajo de más.
  • La arquitectura que permite dormir es la orientada a eventos: las ISR publican eventos, el bucle principal los despacha y, con la cola vacía, duerme (comprobando y durmiendo sin carrera). Ninguna tarea espera activamente: cada espera se convierte en un evento.
  • El ciclo de trabajo D = tactivo / T da la corriente media: Imedia = D·Ia + (1 − D)·Ir. Se baja haciendo cada ráfaga más corta o haciendo menos ráfagas, y agrupar reparte el costo fijo de cada ráfaga.
  • El tick periódico despierta mil veces por segundo (50 µA con valores típicos) e impide los sueños profundos. El firmware sin tick programa un temporizador de bajo consumo para el próximo vencimiento (en FreeRTOS, configUSE_TICKLESS_IDLE).
  • Cada periférico y circuito externo sigue el ciclo encender, usar, apagar, incluida la alimentación del sensor desde un pin. Los relojes: cristal de 32,768 kHz para dormir con precisión, reloj rápido solo mientras se trabaja.
  • Todos los pines deben estar en un estado definido antes de dormir (analógico si no se usan): una entrada flotante puede consumir decenas o cientos de µA.
  • La comunicación es el mayor consumidor: transmitir poco, agrupar, mensajes cortos, ventanas de escucha e informar por excepción (con latido): en la simulación, el 2,7 % de los mensajes con un error máximo de 0,5 °C.
  • Las mejoras se encadenan: en el ejemplo, de 5192 µA (15 días) a 11,6 µA (12 años) sin quitar una función del producto. Se ataca siempre lo que más pesa, se mide con el producto real y se vuelve a medir.

¿Listo para el tema siguiente?

Antes de avanzar, tomá un firmware tuyo y buscá cinco cosas: ¿hay retardos por conteo?, ¿hay while (!...) sobre periféricos?, ¿hay un tick, y de qué frecuencia?, ¿qué periféricos y relojes están habilitados al dormir?, ¿qué pines están sin configurar? Cada «sí» es una mejora concreta. Y calculá cuánto vale la más grande con el modelo de este tema.

En el próximo tema cerramos el bloque con un taller: medir y estimar la duración de la batería. Cómo se mide la corriente de un dispositivo real, cómo se arma su perfil de consumo, y cómo se compara con el presupuesto para llegar a una autonomía en la que confiar.