Sleep y WakeUp con PIC

Esta nota sera de utilidad para trabajar el bajo consumo de un microcontrolador PIC.
A menudo tenemos aplicaciones donde se requiere trabajar en bajo consumo, aplicaciones que utilizan pilas, donde queremos que la autonomía sea lo suficiente para que el dispositivo no requiera de un cambio de pilas frecuente, o bien funcione con energía alternativa (Solar, Piezoelectrica, Harvesting, etc...), o también para dispositivos descartables.
Aprovechando la tecnología nanoWatt de Microchip, vamos a implementar un pequeño ejemplo donde mostraremos como dormir y despertar el microcontrolador para realizar alguna pequeña tarea.
Por ejemplo, el microcontrolador PIC16F676 (un microcontrolador de bajo costo y bajas prestaciones) posee tecnología nanoWatt que tendremos que ver en su datasheet que valores de consumo maneja según la configuración del clock que utiliza.
En la figura de arriba, podemos ver que el datasheet nos proporciona distintas características para trabajar en baja potencia.
Analizaremos cada una de ellas:

  • Standby Current: Este es un estado donde el microcontrolador se encuentra en modo Sleep "dormido" y la única manera de realizar un WakeUp "despertar" es mediante una interrupción externa (por ejemplo cambio de estado en un GPIO), Este estado tiene un consumo de tan solo 1nA si el microcontrolador se alimenta a 2V, pero estamos hablando de 1nA es realmente muy bajo consumo.
  • Operating Current: Este estado es el modo común de operación donde no utilizamos ningún bajo consumo, solamente nos detalla el consumo si trabajamos a 32kHz alimentado con 2V donde el consumo sera de 8.5uA, o bien, si trabajamos a 1MHz sera de 100uA, pero esto hay que tener cuidado que por cada MHz de clock sera 100uA de consumo, ejemplo para 20MHz tendremos 2mA.
  • Watchdog Timer Current: Este metodo es el que emplearemos en el ejemplo, es el método que solamente tiene corriendo o ejecutando el timer del WDT, es decir, en el primer caso el microcontrolador se encuentra totalmente congelado, sin realizar ninguna acción hasta que aparece una interrupción externa por hardware, en este caso requiere que el timer WDT se encuentre activo y contando. Para este contador WDT el consumo es de 300nA a 2V
  • Timer 1 Oscillator Currnet: Este estado es igual al del WDT pero en lugar de mantener el timer WDT activo, mantiene solo el Timer1, que posee un consumo mayor al WDT de al menos 4uA a 32kHz, siempre alimentado con 2V.

En el caso del contador WDT "WatchDogTimer" tenemos que hablar primero de que es el WDT.
El timer WatchDog, o también conocido como el temporizador de perro guardián, es un timer creado para realizar un reset al microcontrolador cuando el mismo desborda su cuenta, es decir, el timer WDT comienza a contar, cuando el mismo llega al valor máximo y se desborda produce un reset que reinicia el microcontrolador.
Para evitar este reinicio podemos resetear el WDT para que nunca llegue a desbordarse y nos reinicie el microcontrolador.
Este proceso es útil cuando nuestro programa podría entrar en un loop o bucle donde quede colgado y no pueda salir.
Es decir, si nosotros tenemos un programa donde algunas condiciones del mismo llevan a que se cuelgue (queda en loop cerrado en alguna instrucción y no puede salir) debemos reiniciar el microcontrolador mediante el botón de reset.
Pero si en cambio utilizamos el WDT, podemos configurarlo para que el WDT produzca un reinicio del microcontrolador cada determinado tiempo, por ejemplo 1000ms, entonces en distintos sectores del programa pondremos la instrucción que borra el WDT, para que borre la cuenta y no llegue a contar esos 1000ms y no reinicie el MCU, pero si nuestro programa queda colgado en Loop cerrado dentro de una rutina y nunca llega a borrar la cuenta del WDT, el mismo seguirá contando y cuando llegue a 1000ms reiniciara el MCU. 
De ahi el nombre de perro guardián, porque esta todo el tiempo mirando que no se cuelgue el programa, y si eso pasara, reiniciaría el MCU.

Bueno hasta aquí, no hablamos de bajo consumo.
Entonces lo que nosotros debemos utilizar es una función que duerme al microcontrolador, esta función se denomina SLEEP, la misma duerme el microcontrolador y solamente lo podemos despertar por Reset o alguna interrupción externa.
Entonces, si nosotros mandamos a dormir al microcontrolador con SLEEP y utilizamos el WDT por ejemplo a 2304ms (sin borrar su cuenta en ningún lado porque el MCU se encuentra en SLEEP y no ejecuta programa), entonces tendremos un RESET programado cada 2304ms, ese reset nos despertara el microcntrolador "WakeUp" y podremos hacer la tarea que queremos y luego de hacer la tarea, mandamos a dormir al microcontrolador con "sleep".

Entonces, 

  1. Activamos los fuses del WDT
  2. Configuramos el WDT a 2304ms (es un valor raro, pero es el valor múltiplo del oscilador, el prescaler, etc...)
  3. Realizamos nuestro programa
  4. Incluimos el Sleep al finalizar la rutina cuando queremos que duerma.

  1. #include <16F676.h>
  2. #FUSES WDT
  3. #FUSES INTRC_IO
  4. #FUSES NOMCLR
  5. #use delay(int=4000000,RESTART_WDT)
  6. #define LED PIN_A0
  7. void main(){
  8.    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  9.    setup_wdt(WDT_2304MS);
  10.    while(true){
  11.       output_low(LED);
  12.       delay_ms(200);
  13.       output_high(LED);
  14.       delay_ms(200);
  15.       sleep();
  16.    }
  17. }

#FUSES WDT
Este es el fuse que debe utilizarse para activar el WDT

#use delay(int=4000000,RESTART_WDT)
Dentro del delay, donde configuramos el clock, tendremos que agregar RESTART_WDT

setup_wdt(WDT_2304MS);
En la configuración del MCU dentro de la función principal "main" debemos configurar el mismo, siempre con el mismo intervalo.

sleep();
Esta es la funcion SLEEP para dormir al MCU, luego de realizar la tarea.

Nuestro programa prende y apaga un LED cada 2,3s

Entonces cuando se encuentra en sleep, el MCU pasara a 300nA (si se encuentra alimentado a 2V) durante 2304ms, y luego cuando se despierta eleva el consumo, realiza la tarea y vuelve a dormir. entonces en cuanto a la energía consumida, podemos obtener un bajo consumo (siempre que el tiempo en Sleep sea mayor que el tiempo activo) y aumentar la autonomía de las pilas o la fuente que lo alimenta.

El datasheet también menciona que los GPIO que no se utilizan, deben ser ruteados a GND en nuestro PCB para reducir el consumo y lograr los 300nA.

Por ejemplo en el gráfico, si tenemos un bloque RUN de 10ms y 1mA, y un bloque SLEEP de 2304ms y 300nA, podemos calcular el consumo promedio de 4.62uA que para una pila tipo CR2032 de 200mA, nos proporciona 4 Años, 343 dias, 15Hs, 56 min.
Tranquilamente podria ser un sistema descartable como los que se acostumbran hoy con los beacon BLE, LoRa, Zigbee, etc...

Generador de Funciones AF con 555 (Simple)

Este generador esta basado en el timer 555, a diferencia de el otro post que tengo realizado con el XR2206, que claramente tiene una mejor calidad de señal, una frecuencia de trabajo mayor y una relación señal ruido menor. Esta claro que este generador con 555 es muy simple, pero también es de bajo costo.
El bajo costo y la facilidad para conseguir los componentes lo hacen muy interesante para ser improvisado incluso en el protoboard.
Es un circuito que no requiere de una fuente simétrica, funciona con un rango de alimentación que va desde los 3V hasta los 12V sin problemas.
En este caso el circuito se ha simplificado al máximo en cuanto a sus componentes, se ha elegido un rango de frecuencias AF que comprende desde los 400Hz hasta los 10kHz aproximadamente, depende del circuito RC del timer 555 en modo astable. 
Luego generamos una señal de forma cuadrada que esta sera una forma de onda que aprovecharemos como salida cuadrada que servirá para inyectar en otros circuitos o como señal de sincronismo en algún otro instrumental como por ejemplo el osciloscopio.
Luego a la salida del 555 tenemos un capacitor de bloqueo de DC, donde en este punto ya tenemos una señal amortiguada que no sera cuadrada y luego pasa por dos filtros RC pasa bajo, o un filtro de segundo orden que tomaremos como salida triangular el punto medio de este filtro de segundo orden, y la salida la tomaremos como señal senoidal, claramente al pasar por estos filtros tendremos una atenuación en la amplitud que sera dinámica en función de la frecuencia.
Tanto la salida triangular como la senoidal se selecciona con una simple llave inversora y esta alimenta la entrada de un amplificador de 500mW basado en el LM386, al tratarse de un generador AF podemos implementar un amplificador de audio de pequeña señal como buffer de salida, y también podremos variar su "volumen" que en este caso sera el potenciometro de variación de amplitud.
Luego en la salida del LM386 tenemos una resistencia de 50R (2 de 100R en paralelo) que hacen las veces de impedancia de salida estándar para el generador de funciones.


Filtro Pasa Bajos

Circuito y PCB