Watch Dog Timers
Material requerido
;
Arduino Uno o compatible |
Que son los Watch Dog Timers
Supongo que los que estáis leyendo esto, estáis sobradamente acostumbrados a los ordenadores personales. Y si es así, todos os habéis hartado a ver colgarse a Windows. La infame pantalla azul que te pide que reinicies el equipo por las malas perdiendo todo el curro que llevabas hecho y que naturalmente no habías salvado a tiempo (Si fueras ordenado no estarías leyendo esto).
Con el último Windows 10, la cosa ha mejorado, pero aun es fácil encontrarse un pantallazo de ese estilo.Este es el punto en que los Macintosheros sonríen con suficiencia mientras te explican que eso en Mac no pasa.
No les creas. El Mac peta. Menos que Windows pero peta, vaya que sí.
Aunque aparentemente, por más que les pete el sistema te juran (Repetidamente, y en días diferentes después de verlo petar) que no les había pasado eso antes y que seguramente son las malos efluvios de Windows que arrastro conmigo como si de un halo mortífero se tratara
Les pasa como a Pedro que negó a no sé quién varias veces, pero hacedme caso, también falla, aun siendo Unix como le pasa a Linux en bastante menor medida, y es que no es posible construir nada con garantías de que no falle, y tu Arduino no es la excepción a la norma.
Hay un millón de motivos que pueden colgar al material informático. Empezando por una programación chapucera (Muy habitual en algunos proveedores de soft), seguimos con hardware defectuoso, Interferencias electromagnéticas, y señales espurias de diferentes tipos y variedades que pueden llevar al traste tu sistema electrónico programable de última generación.
En realidad lo sorprendente no es que esto ocurra, lo sorprendente es lo poco que ocurre. Ten en cuenta que tu Arduino, que es un chisme ciertamente lento, hace varias decenas de miles de operaciones por segundo con absoluta precisión y libre de errores. Pero uno solo error en los miles de operacioness por segundo, que son millones de ellos por mes o año, es suficiente para que empiecen los problemas.
Imagínate que montas con tu flamante Arduino un sistema de riego para tus plantas o jardín mientras te vas un par de semanas de vacaciones. Lamentablemente, uno de los sensores de humedad está mal y provoca un cortocircuito que tumba tu Arduino dejando abiertos los grifos, de agua.
Si vives en una planta baja a lo mejor todo se arregla con pagar un recibo de agua por una cantidad desagradable, pero si era para regar los tomates de un 6º piso, los bomberos pueden acabar derribando tu puerta mientras los vecinos cabreados te hacen voodoo por inundar hasta el 2º.
Estos días hablábamos de dejar un Arduino funcionando en baterías durante un año, e imagínate que vuelves al año a recoger tus preciosos datos y a tu controlador le dio por colgarse a los 15 días de empezar y has desperdiciado el año.
Cuando haces un proyecto así, tienes que estar seguro, de que cuando vuelvas, tu Arduino sigue funcionando como el primer día,sin excepciones, y que si en algún momento se cuelga, alguien pulse el botón de Reset, preferiblemente algo automático.
Y queridos amigos para eso son los Watch Dog Timers, (o WDT de aquí en adelante), y en esta sesión nos vamos a pelear con ellos, porque ya los hemos mencionado de pasada un par de veces y ha llegado el momento de meterles mano.
Los Watch Dog Timers
No creáis que los cuelgues simplemente se debe a malos programas, o a defectos de hardware. Hay mil motivos para que se os cuelgue. Recuerdo un proyecto de prueba del que tuve que desistir.
Se trataba de medir la intensidad de corriente que circulaban por unos motores trifásicos (leyendo solo una fase cada vez) aunque el problema eran que había picos de 200 Amperios (Eran molinos de chatarra) y todo iba bien hasta que alguna señal espuria se colaba por los hilos del sensor y me dejaba gilipollas mi Arduino Uno a pesar de que le hice una jaula de Faraday y todo eso además de una pica con masa a tierra.
En un plazo que iba entre 2 horas y 2 días, mi UNO se quedaba frito y había que resetearlo manualmente, con lo que a freír puñetas la toma de datos durante días enteros, haciéndolo inservible. Y como en esa época aun no conocía los WDT tuve que renunciar al proyecto.
Los WDT, literalmente Timers de perro guardián, son algo así como un procedimiento de seguridad, para garantizar que si nuestro Arduino se cuelga, podemos detectarlo y resetear en automatico el sistema para que se reinicie sin más.
Es algo así como esas pelis en las que el prota dice a los amigos algo del tipo: “Si no he vuelto en una hora avisad a la policía”
Y aunque os parezca increíble prácticamente todos los MCU tienen uno previsto, incluyendo tu Arduino.
De haberlo sabido entonces, hubiera bastado con definir un WDT en mi Arduino UNO de forma que cuando se colgase, simplemente reiniciase y vuelta a empezar, quizás perdería una medida (Eran cada media hora) pero no se notaría gran cosa.
Un WDT básicamente es un Timer, de corto recorrido e independiente de los otros, que vimos en su día, que es como un reloj de arena: Lo pones a 0 y antes de que llegue al final, tienes que pasar por allí y dar la vuelta a la clepsidra.
Si no lo haces antes de la arena llegue al final, el sistema pulsa el botón de Reset directamente sin más consideraciones y ahí te apañes. En definitiva es un sistema de seguridad que entiende que si no pasas a tiempo es porque ha ocurrido algo y ya no vas a pasar (Que trágico todo ¿no?)
Los WDT te dan una enorme ventaja en proyectos de larga duración. Sabes que si pasa algo, el propio sistema reseteará y volverá a empezar sin más. Si estabas guardando datos en una SD por ejemplo, reiniciaras y volverás a grabar, quizás en otro fichero, pero perderás un mínimo de lecturas.
Claro que en la vida no hay felicidad perfecta (Creo que ya lo sabias) y los WDT también tienen problemas propios.
Por ejemplo, si el tiempo de disparo es menor de lo que tu programa tarda en el peor caso en pasar por meta y dar la vuelta al reloj, tendrás un Reset aleatorio y no estarás muy seguro de porque razón. Será un problema esporádico y muy difícil de detectar.
Peor aún, si te equivocas con el tiempo de disparo del WDT, tu programa puede entrar en un bucle infinito de reinicios, llevándole a lo que cariñosamente se llama en el gremio un Dead Lock.
Como siempre, los WDT son un sistema excepcionalmente útil, para prevenir cuelgues, pero si las usas a lo tonto el mismo se puede encargar de hacerte lamentarlo. Cuando los uses, se un poco sensato y manéjalos con cuidado.
Si tienes cabeza, son una herramienta insuperable para garantizar la vida a largo plazo de tu proyecto con Arduino, pero si no te van a marear.
Usando los WDT
Pues es bastante fácil. Solo hay que usar la librería que los gestiona, que ya viene instalada por defecto con el conjunto estándar de librerías en Arduino.
#include <avr/wdt.h>
Y después solo tenemos tres instrucciones:
wdt_enable(timeout) wdt_disable() wdt_reset()
La primera pone en marcha el WDT y hay que pasarle el plazo de disparo de la alarma. Ya vimos cómo sin querer en una sesión anterior que los plazo son predeterminados y con un máximo de 8 segundos:
Threshold value | Constant name | Supported on |
---|---|---|
15 ms | WDTO_15MS | ATMega 8, 168, 328, 1280, 2560 |
30 ms | WDTO_30MS | ATMega 8, 168, 328, 1280, 2560 |
60 ms | WDTO_60MS | ATMega 8, 168, 328, 1280, 2560 |
120 ms | WDTO_120MS | ATMega 8, 168, 328, 1280, 2560 |
250 ms | WDTO_250MS | ATMega 8, 168, 328, 1280, 2560 |
500 ms | WDTO_500MS | ATMega 8, 168, 328, 1280, 2560 |
1 s | WDTO_1S | ATMega 8, 168, 328, 1280, 2560 |
2 s | WDTO_2S | ATMega 8, 168, 328, 1280, 2560 |
4 s | WDTO_4S | ATMega 168, 328, 1280, 2560 |
8 s | WDTO_8S | ATMega 168, 328, 1280, 2560 |
La segunda, wdt_disable(), para el reloj y desautoriza el WDT. Siempre que uses un WDT debe ser la primera instrucción de tu setup()
void setup() { wdt_disable(); …………… }
Esto no es imprescindible, pero es una precaución muy recomendable, porque cuando tu Arduino se resetea, el WDT sigue en marcha, y si has cometido un error de cálculo, tu WDT puede disparar antes de que te dé tiempo a reaccionar y entrarías en un ciclo mortal de reinicios continuos.
Por eso es muy buena política cuando usas WDT, poner la primera línea de tu código el desactivarlo, haces lo que quieras y luego lo activas con wdt_enable().
Por ultimo para dar la vuelta al reloj de arena haces wdt_reset() y el tiempo vuelve a empezar.
Ni que decir tiene que debes asegúrate de que tu programa pasa a tiempo a dar la vuelta a la clepsidra. No te basta con suponerlo, TIENES que asegúrate de que en el peor caso tienes tiempo de sobra o te vas a encontrar con problemas raros que solo pasan de vez en cuando, (En ese caso raro uno entre mil que no llegas a tiempo)
Por ejemplo, si estas transmitiendo algo por la puerta serie, deberías asegúrate de que el tiempo de transmisión de los datos no supere el límite del WDT
Vamos con un ejemplo práctico.
Programando un WDT
Vamos a usar un programa muy sencillo que provoque un Reset continuo (Para hacer una demostración de lo que no deberías hacer). Empezamos incluyendo la librería:
#include <avr/wdt.h>
Y pasamos al setup:
void setup() { wdt_disable(); // No te olvides Serial.begin(9600); Serial.println("Entrando…."); wdt_enable(WDTO_1S); }
Seguimos la buena costumbre de empezar desautorizando el WDT (Siempre es buena costumbre) y después sacamos un mensaje por la puerta serie para demostrar que estamos en el setup, y antes de salir activamos el WDT con un lapso de 1 segundo.
void loop() { wdt_reset(); Serial.println(“Todo bien…”); }
Simplemente empezamos dando la vuelta al reloj de arena e imprimimos un mensaje. Veamos el resultado:
Perfecto. Nuestro programa indica que está entrando y luego el ciclo normal del programa saca el mismo mensaje una y otra vez como era de esperar, porque las dos instrucciones se realizan mucho antes del segundo que tarda en disparar el Watch Dog.
¿Pero qué pasa si cometemos un pequeño error de novato como este?
void loop() { delay(1500) ; wdt_reset(); Serial.println(“Todo bien…”); }
Nos despistamos y metemos un sencillo delay, con más tiempo del que tarda en disparar el WDT. EL resultado es este:
Nuestro Arduino entra en un ciclo inmediato de reinicios porque estamos bloqueando la ejecución normal del programa con un delay, que nos impide resetear el WDT a tiempo.
Es muy fácil ver el problema aquí, pero si no hubiéramos tenido la cautela (Que casualidad) de poner un mensaje desde el setup, algo poco frecuente, puede costarte los suyo entender por qué tu Arduino se cuelga sin una razón clara y reinicia de continuo sin razón aparente.
No quiero complicar más el programa. Creo que el ejemplo, por más que sencillo, ilustra muy bien las ideas básicas que gobiernan los WDT.
Si vas a correr un programa a largo plazo, con baterías o no, pero esperas que funcione de continuo durante muchos meses o semanas, los WDT son una herramienta imprescindible para garantizar la viabilidad de tu proyecto y desde luego os recomiendo que los uséis.
Pero a cambio tienen una pequeña complicación adicional que puede darnos más de un dolor de cabeza si no usáis la vuestra a la hora de programar.
Resumen de la sesión