Inhaltsverzeichnis

TinyWD

This is a hardware watchdog, build for Arduino and other MCU directly pluggable to the ISP connector.

It's build from an Attiny 45/85.

The NoSMD Version on an Uno.

from here I describe the structure in German

Dies ist ein Hardware Watchdog, aufgebaut mit einem ATTiny84. Ziel ist es, eine vorhanden Controllerplatine nachträglich mit einem Watchdog auszustatten. Denn manchmal reicht der in den Chips eingebaute Watchdog nicht aus, bzw. ist nicht zuverlässig genug. So ist es mir bei meinem Tonnenpumpen Projekt ergangen. Der im ATTiny84 eingebaute Watchdog konnte den Controller nicht zuverlässig vor einem Einfrieren schützen. Immer wieder musste ich den Controller per Hand Resetten. Natürlich gibt es auch fertige Watchdogs, meist in Transistor oder DIP-8 Form. Doch die Beschaffung war schwierig und außerdem macht es doch Spaß, sowas selber zu designen. Deswegen habe ich auf Basis des ATTiny85 diesen Hardware Watchdog gebaut, der auf einen normalen 6-Pol ISP Programmierstecker aufgesteckt werden kann. Zunächst aber habe ich eine Variante für den Digispark entworfen, um die prinzipielle Funktionsweise zu testen. Der Vorteil der ISP Aufsteckvariante ist der, das man ja üblicherweise die Pins des ISP selten für seine eigene Schaltung verwendet. Und wenn, dann doch als SPI (was direkt den WD triggern könnte) um nicht durch die eigene Schaltung das ISP zu verwirren.

Github Projekt: https://github.com/willie68/TinyWD

Digispark Version

Als erste Variante hab ich den Digispark ale Entwicklungsplatform benutzt.

Die ersten Tests hab ich mit einem Digispark gemacht. Leider ergibt sich durch den USB Bootloader, dass man beim Digispark nicht alle Pins für den Watchdog verwenden kann. Bei den Pins für den USB kommt es dazu, dass der Digispark einfach nicht starten möchte. Ursache ist der [Micronucleus](https://github.com/micronucleus/micronucleus) Bootloader.

Genauer: Der ATTiny85 arbeitet mit einem Micronucleus Bootlaoder. Dieser simuliert über 2 Pins (3,4) ein USB Schnittstelle. Diese wird dann vom Host (PC) erkannt und man kann dann das Programm in den ATTiny hochladen.

Der Bootloader hat ich 2048 Bytes vom Flash reserviert. D.h. die Anwenderprogramm dürfen nicht mahr als 6KB haben.

Daneben gibt es noch weitere Einschränkungen. Für den Watchdog fand ich folgende Pin Zuordnung eigentlich optimal, da sie mit dem ISP korrosdondiert. Einzig der Reset Pin musste so auf einen anderen Pin gelegt werden. So ist auch die eigene Hardware gebaut. PB4 ist dabei für die visuelle Rückmeldung (LED) zuständig. Beim Digispark sind aber leider verschiedene Änderungen nötig. PB1 ist für die Onboard LED da. PB3 ist ein USB Data Pin und kann leider somit nicht als Reset Output funktionieren. Das Problem ist, bei einem Neustart setzt der Micronucleus Bootloader diesen Pin auf 0. Somit wird dann gesteuerte Controller ion den Resetmodus versetzt. Auch Pin 4 wird Ausgang benutzt. Bei der o.g. Beschaltung hängt sich dann aber der Bootlaoder auf, normalerweise startet der Bootloader nach 6 Sekunden das Anwenderprogramm (in unserem Fall den Watchdog) mit der äußeren Beschaltung tat er das aber nicht. Somit waren sowohl der Digispark wie auch der angeschlossene Controller geblockt. Deswegen gilt für den Digispark eine andere Pinbelegung.

PB0 ist ein WD Pin PB1 ist die LED PB2 ist der WDReset Pin PB3, PB4, PB5 werden nicht verwendet.

PCB Variante

Der Digispark ist zwar nett, aber eine eigenes PCB könnte man deutlich kleiner machen. Sowohl mit als auch ohne SMD Bausteine.

Hier der Schaltplan: Oben die normale Variante, unten die SMD.

Steckerbelegung ISP:

ISPNameATTiny
1MISOPB1
2VCC+5V
3SCKPB2
4MOSIPB0
5ResetPB3
6GNDGND

Hier mal die fertige Platine:

Links ist die klassische Variante mit normalen Bauteilen, rechts die deutlich kleinere SMD Variante. (Der Chip wird auf der Unterseite montiert.)

Hier die Rückseite. Oben im Bild sieht man auch den SOIC-8 Programmieradapter und mein Programmiergerät.

Wichtig ist, das man vorher weiß, wo der WD eingesetzt werden soll. Will man den WD, so wie ich, direkt auf den ISP aufsetzen, ist es wichtig, die Buchse (2×3) auf der Platinen Unterseite zu platzieren. (Siehe Fotos)

Will man den WD per 6-pol Kabel mit dem ISP verbinden, braucht man eine 2×3 Stiftleiste, die auf die Vorderseite (wie aufgedruckt) gelötet wird.

Will man gar keinen ISP zur Kopplung verwenden, kann man einfach die 3 rechten Lötpunkte, plus dem WD Reset von dem ISP verwenden. Dabei gilt

Pin Bedeutung
—– ———
Pin 2 +5V
Pin 4 Hearbeat
Pin 5 WD_Reset
Pin 6 GND

NoSMD Variante

Hier mal die normale Variante:

Aufgesetzt auf meine Tonnenpumpe sieht dass so aus:

Verwendet werden hier 2 Low-Current 3mm LEDs.

BOM

Anzahl Bauteil Gehäuse
—— ———————– ——-
1 ATTiny85 DIP8
1 IC Sockel DIP8
2 1k5 Metallschicht
1 10k Metallschicht
2 100nF RM2.54
1 3mm LED LowCurrent grün
1 3mm LED LowCurrent rot

SMD Variante

Bestückt sieht die SMD Version so aus:

Und auf die Tonnenpumpeplatine aufgesteckt:

BOM

Anzahl Bauteil Gehäuse
—— ——————— ——-
1 SMD ATTiny85 SOIC-8
2 SMD 1k5 1206
1 SMD 10k Metallschicht 1206
2 SMD 100nF 1206
1 SMD LED grün 1206
1 SMD LED rot 1206

Andere mögliche Varianten

Software

Die Software für den WD findet ihr hier in dem Github Repo: https://github.com/willie68/TinyWD

Projekt

Die Software auf der Gegenseiten ist recht einfach. Man mus nur immer einen der ISP Pins als Ausgang definieren und in regelmäßigen Abständen diesen Pin toggeln.

das geht recht einfach mit `digitalWrite(pin, !digitalRead(pin))`

Bei meiner Tonnenpumpe musste ich allerdings etwas anders vorgehen, da der Pin für den Heartbeat bereits anderweitig (LED Pumpe) vergeben war. Also gebe ich hier ca. jede Sekunde einen kurzen Implus (ca 10ms) auf den Pin. Um den Pin Status nicht zu verlieren, speichere ich mir diesen einmal vorher ab.

Wenn man den TinyWD aber von vornherein berücksichtigt, erspart man sich diesen zusätzlichen Aufwand.

unsigned long saved = 0; 
void heartbeat() { 
  if (millis() > saved) { 
    saved = millis() + 1000; 
    bool tmp = digitalRead(LED_PUMP); 
    digitalWrite(LED_PUMP, !tmp); 
    delay(10); 
    digitalWrite(LED_PUMP, tmp); 
  } 
} 

Firmware

Die Software ist sehr einfach.

In void setup() setzte ich die Ein/Ausgänge entsprechend. Eingänge jeweils mit Pullup Widerstand. Zur Startsignalisierung blinkt einmal kurz die LED. Im nächsten Schritt werden für die Eingänge sog. PinChange Interrupts konfiguriert. D.h. ändert einer der Eingänge seinen Status, wird automatisch ein Interrupt ausgeführt. Dieseer steht in der Methode ISR (PCINT0_vect).

Als letztes erzeuge ich mir einen Timer, der automatisch alle 10 Sekunden feuert. Diese Routine setzt dann ein Flag, welcher in der void main() dann getestet wird. In der main wird auch ein Heartbeat Signal an die LED gesendet.

Funktionsweise

In der ISR wird einfach ein Variable namens changed auf true gesetzt. In der Hauptloop wird genau auf changed == true geprüft und dann der TImer resettet. Changed wird dann wieder auf false gesetzt und eine visuelle Rückmeldung gegeben. Fehlt länger als 10 Sekunden der Interrupt, weil sich kein Pin geändert hat, löst der Timer die Reset Methode aus. Diese legt den Resetpin für 1 Sekunde auf GND. Danach hat der angeschlossene Controller wieder 10 Sekunden Zeit, einen der Eingänge zu toggeln.