Problem: Totalausfall des Convac-Spinätzers durch Hirntod.
Im Zuge des „Hirntodes“ der vorhergehenden Steuerung wurde der Mikrocontroller mitsamt Software im Zeitraum August-Dezember 2016 durch einen Arduino Micro ersetzt. Die Boards der Arduino-Serie enthalten einen Mikrocontroller mitsamt Standard-Außenbeschaltung und Programmier-Interface per USB.
Das erspart das Anfertigen von Platinen und das Löten der sehr kleinen Gehäuse, es wurde der pragmatische Ansatz einer Lochrasterplatte zum Anschluss genutzt. Diese passt prompt als weitere Platine in das vorhandene Gefäß- und Bussystem.
Um zu verhindern, dass über die USB-Buchse die gesamte Maschine gespeist wird, muss der Transistor T1 (PMV48XP, p-Kanal-MOSFET, SOT23, Markierung KNW48) einseitig ausgelötet werden. So wird ein „self-powered“ USB-Gerät draus.
Die alte Prozessorplatine mit 80186 wurde soweit abgeschrottet, dass nur noch die digitalen Eingänge mit Optokoppler übrig blieben. Diese wurden via Adressdekoder und Pufferschaltkreis an den Bus der Rückplatine gelegt. Knifflig, weil dazu doch der gesamte Schaltplan „disassembliert“ werden musste, um keine Fehler einzubauen.
Dass als Nachteil dessen die Eingänge gepollt (= einzeln abgefragt) werden müssen und nicht mehr interruptfähig sind, ist für diesen Anwendungsfall unerheblich.
Im Zuge der Anpassung mussten für alle Einsteckkarten Schaltpläne erstellt werden, die so gut wie möglich den Istzustand wiedergeben. Siehe Ressourcen.
Von den Platinen HANA und HTOP habe ich keine Schaltpläne. Informationen zu deren etwaiger Netzliste befinden sich in den Dateien Analog.cpp und Digital.cpp.
Der allererste Ansatz, die Anzeige über die serielle Schnittstelle und den vorgesetzten 8051-kompatiblen Mikrocontroller anzusprechen, war vergeblich, weil das Protokoll nicht enträtselt werden konnte.
Daraufhin wurde der 8051 samt EPROM und RAM abgeschrottet und versucht, den Displaycontroller HD61830B direkt im Textmodus anzusprechen. Auch das wurde verworfen, weil die Anzeige sich dabei fehlerhaft verhalten hatte.
Daher gab es schließlich für die Software keine andere Chance, als das Display vollgrafisch anzusteuern: Eine zusätzliche, unerwartete Herausforderung!
Der verwendete Mikrocontroller hat folgende maßgebliche Eigenschaften:
Er ist deutlich leistungsswächer als der vorher eingesetzte 80186, ein 16-Bit-Controller mit externem Flash- und RAM-Speicher. Eine Disassemblierung kam schon wegen der schieren Größe nicht in Frage.
Die Software wurde komplett neu geschrieben. „So etwas profanes wie eine Waschmaschinensteuerung muss in einen dermaßen komfortablen Mikrocontroller passen!“ Erst mit dem Rezept-Editor (den es bei echten Waschmaschinen gar nicht gibt) wurden die Grenzen dann doch erreicht.
Das Hauptprogramm kümmert sich um die Benutzeroberfläche
und ruft gelegentlich idle()
auf.
Diese Routine kümmert sich als Zustandsmaschine mit den beiden Variablen
run.rezept und run.aktion um die schrittweise
und zeitgesteuerte Abarbeitung eines Rezepts sowie das Aktualisieren der Uhr.
Damit liegt kooperatives Multitasking vor.
Gegenüber verdrängendem Multitasking entfallen Bedenkzeit,
Laufzeit und Programmspeicherplatz fressende Probleme der Synchronisation
beim Zugriff auf gemeinsame Ressourcen wie dem Bussystem, der Anzeige,
dem Lautsprecher und verkoppelten Variablen im Speicher.
Der Watchdog prüft, ob idle()
in einer bestimmten
Mindestfrequenz (zurzeit 2 Hz entsprechend 500 ms) aufgerufen wird.
Wenn nicht, gibt es einen definierten Absturz („Bluescreen“),
wobei sämtliche Ausgänge deaktiviert werden.
Dann ist ein Dauerpiep zu hören, und der Urlader ist aktiv.
Die Hauptquelle für idle()
-Aufrufe ist die Tastenabfrage.
Längere Bildaufbausequenzen sind ebenfalls
mit idle()
-Aufrufen gespickt.
Interrupts werden fast nicht verwendet. Der Verzicht auf Interrupts erleichtert die Fehlersuche (Debuggen) erheblich; diese Möglichkeit habe ich bis jetzt nicht verwendet.
Als intern verwendeter Zeichensatz des Programms wurde UTF-8 (unverändert) verwendet. Konvertierungsroutinen in der Anzeige-Steuerung erledigen die Zuordnung von Mehr-Byte-Zeichen zur in der Zeichenbildtabelle vorhandenen Buchstabenform (= Pixelinformation).
Die Firmware enthält Kode zur USB-Kommunikation, insbesondere um den EEPROM-Inhalt zu retten bzw. wiederherzustellen. Auf der Windows-PC-Seite steht ein Rezept-Editor zur Verfügung, der zurzeit nur das Betrachten und Retten von Rezepten erlaubt. Im Vollausbau dient es zum komfortableren Erstellen von Rezepten (insbesondere mit Zeitablaufgrafik), und auch der Download wird dann funktionieren.
Ein wesentlicher Teil der Software kümmert sich um die vollgrafische Schwarz-Weiß-LC-Anzeige mit 240 × 64 Pixeln. Die Kernroutinen stammen vom Arduino-Projekt UTFT, wurden jedoch auf Schwarzweiß-Ausgabe und maximal 256 Pixel (in jeder Richtung) zurechtgestutzt. Damit wird vor allem Programmspeicher gespart, da 8-Bit-Werte weniger Befehle zur Verarbeitung erfordern als größere.
Im Gegensatz zu UTFT wurde ein pixelgenaues Rechteck-Clipping, pixelgenauer Bit-Block-Transfer mit allen 16 möglichen booleschen Rasteroperationen sowie pixelgenauer Bildlauf in X- und Y-Richtung (auch zugleich) implementiert. Damit wurde der Grundstein für die viel besser lesbare und Platz sparende Proportionalschriftausgabe gelegt, die beliebig abgeschnitten werden kann. Der Bildlauf unterstützt die Anzeige längerer Listen in einem Fenster. Nicht implementiert wurde Drehung/Spiegelung/Skalierung beim Bit-Block-Transfer.
Der Vektor-Teil der „Grafikbibliothek“ unterstützt nur Rechtecke und Linien. Auf der Basis der vorherigen Rasteroperationen lassen sich Kreise, Bögen, Rundecke, Polygone und Pfade (auch mit 8×8-Schraffur gefüllt sowie via Pfadumwandlung mehr als 1 Pixel breite Umfassungslinien) realisieren, wird aber hier nicht benötigt und wurde daher nicht implementiert.
Für die „Grafikbibliothek“ gibt es wegen ihres Umfangs eine eigene Kopfdatei Display.h.
Der Speicher, insbesondere der String-Zugriff wurde „von-neumannisiert“: Alle Adressen ≥ 0x8000 meinen Flash-Adressen. Dies ist den neueren PIC-Mikrocontrollern sowie ATtiny4..10 nachempfunden und stellt eine wesentlich bessere Lösung als die im avr-gcc eingebaute (namentlich progmem.h und deren Makros) dar. Dadurch ist dem Zeiger implizit der Typ mitgegeben, und es genügt 1 Set von Einsprungpunkten in die Grafikdisplay-Klasse. Die einzige Einschränkung ist, dass Strings in den ersten 32 KByte Flash eines Mikrocontrollers liegen müssen, und nicht, wie früher, in den ersten 64 KByte.
Der Programmspeicher ist nahezu komplett ausgefüllt. Damit ist der Mikrocontroller eigentlich zu klein, da im Industrieumfeld < 50 % Füllstand angestrebt werden, nur bei Konsumgütern sind es 90 %. Leider gibt's da 2017 keinen pinkompatiblen Ersatz.
Der 1 KByte große EEPROM wird durch die Globale Sicherheitsliste und die Rezeptliste belegt. Jeder Eintrag schlägt mit folgendem Byteverbrauch zu Buche:
Die maximale Anzahl an verwaltbaren Rezepten ist 63.
Die maximale Anzahl von Schritten pro Rezept ist 62.
Die maximale Anzahl von Einzelaktionen pro Schritt ist 63.
Das sollte hinreichend flexibel sein.
Der Programmspeicher darf 10.000 Mal überschrieben (reprogrammiert) werden.
Der EEPROM darf 100.000 Mal überschrieben werden.
Jedes Bewegen des Fokusrechtecks, jede Änderung an der Rezeptliste,
auch das Auf und Zuklappen von Ästen führt zu einem Schreibzugriff.
Die Zahl 100.000 ist jedoch eine recht große Zahl und nur das garantierte Minimum.
Es werden nur sich ändernde Bytes aktualisiert, nicht jedesmal alles.
Auch das passiert im Hintergrund via idle()
.
Nicht gespeichert werden:
Alle diese Werte fallen beim Einschalten der Maschine auf Null zurück; das Fortsetzen eines laufenden Rezeptes nach Stromausfall ist nicht vorgesehen.
Die Rezeptabarbeitung wird alle 100 ms zur Abarbeitung auf den Plan gerufen, mit einem Jitter von < 500 ms. Unabhängig vom Jitter werden Ablaufzeiten in Summe quarzgenau eingehalten. Die maximale Zeit pro Rezeptschritt beträgt 655,35 Sekunden, also reichlich 10 Minuten. Notfalls muss man mehrere Schritte aneinanderhängen.
Der Arduino beinhaltet keine Echtzeituhr. Daher wird einfach die Betriebszeit (seit dem letzten Einschalten) gemessen und angezeigt. Ein 32-Bit-Zähler wird dazu mit 100 Hz getaktet. Dieser läuft nach > 1 Jahr über. Zur Zeitanzeige wird davon eine 16-Bit-Zahl der Sekunden (max. 65535 s) extrahiert. Die Anzeige läuft daher nach 18:12:15 zu 00:00:00 über. Reicht für einen Arbeitstag.
Der Quellkode besteht aus:
Der Quellkode wurde in einigen Teilen auf die Bandagen von 8-bit-Controllern getrimmt, sollte (bis auf die paar Assembler-Anweisungen) auch für künftige und breitere Controller übersetzbar sein. Für bessere 16- oder 32-Bit-Performance wäre der Quelltext sicherlich überarbeitbar, aber da dann ohnehin mehr Rechenleistung und Programmspeicher zur Verfügung steht, wenig zielführend.
Gleitkomma wurde vermieden, stattdessen eine eigene simple Festkomma-Aus- und Eingaberoutine geschrieben, die gleich Komma statt Punkt ausgibt bzw. verarbeitet. Das spart erheblich Programmspeicherplatz und man erspart sich Rundungseffekte. Teilweise wurden die irregulären Werte NaN, −∞ und +∞ als Integerzahlen -32768, -32767 und +32767 nachgebildet. Insbesondere die Zahlen-Ein- und -Ausgaberoutine kann diese Symbole akzeptieren bzw. ausgeben.
Zur Kompilierung wurde zunächst die letzte Version 20100110 von winavr. winavr enthält avr-gcc (Gnu-C-Compiler für AVR-Mikrocontroller) sowie gawk. Diese Version produziert beim Erstellen eine Unmenge Warnungen mit dem Inhalt
warning: only initialized variables can be placed into program memory area
(Dies tritt nur unter C++ auf und ist ein bekannter Fehler von avr-gcc.) Ansonsten sollte sich der Quelltext stets ohne Warnungen und Fehler übersetzen lassen! Warnungen sollten wie Fehler behandelt werden.
Wegen dieser Warnings sowie für bessere Optimierung und C++11-Kompatibilität wurde im Laufe der Software-Entwicklung auf avr-gcc 2014 umgestellt. Die Umstellung war problemfrei. Nun gibt es weder Fehlermeldungen noch Warnungen.
Als Editor habe ich das beim winavr mitgelieferte Programmer's Notepad benutzt. Im Gegensatz zum verbreiteteren notepad++ hat es eine eingebaute Schnittstelle zum Aufruf von Compilern und makefiles mit der Darstellung deren Ausgabetexte mitsamt Parser zum Aufsuchen fehlerhafter Zeilen. Es kann jeder andere Editor zur Weiterverarbeitung verwendet werden, mit folgenden Voraussetzungen:
Typische Vertreter sind Atmel Studio, Microsoft Visual Studio, notepad++, Eclipse, alle Linux-Editoren, vmtl. alle MacOSX-Editoren. Von großem Vorteil ist verfügbare Syntax-Hervorhebung, aber kein Muss. Windows Notepad ist nicht geeignet. Die Arduino-Software ginge auch, ist aber nicht empfehlenswert, viel zu unflexibel.
Sind alle Pfade korrekt eingestellt, genügt der Aufruf von
Zum Programmieren wird die Software dfu-programmer verwendet, die im Gegensatz zu Atmel Flip eine Kommandozeile zulässt und viel, viel kleiner und schneller ist.
Die gesamte Softwarekette zur Erstellung ist open-source.
Das Programmieren kann „in-system“ erfolgen, weil das Bedienprogramm einen Rücksprung zum Urlader beinhaltet.
Nur wenn das nicht funktioniert, benötigt man einen Zugang zur Reset-Taste des Arduino-Boards, durch Ausbau der Verarbeitungseinheit aus der Ätzmaschine. Es ist egal, ob:
Es muss:
Daraufhin erscheint ein „Atmel DFU Device“ im Geräte-Manager, und der Chip ist bereit zum Programmieren. Nach dem Programmiervorgang startet der Controller automatisch mit der neuen Software.
Der Inhalt des EEPROMs, also die Rezeptliste, bleibt erhalten.
Sollte der Mikrocontroller ausfallen, genügt die Beschaffung eines Boards namens „Arduino Micro“. Es kostete im Jahr 2016 knapp 25 Euro. Es ist davon auszugehen, dass dieses noch für 10 Jahre beschaffbar sein wird. Die derzeitige Bestückung erfolgt mit ATmega32U4. Es ist davon auszugehen, dass dieser oder pinkompatible Nachfolgetypen für 20 Jahre beschaffbar sind.
Wer Arduinos kennt, wird sich über o.g. „Atmel DFU Device“ gewundert haben: Ich habe den Arduino-Urlader mit Hilfe eines PCs mit Parallelport und einem sog. ISP-Adapter mit 6-poligem Pfostenstecker (am Lötplatz deponiert) durch den original Atmel-Urlader (der normalerweise bei Auslieferung der Chips enthalten ist) überschrieben. Das hat folgende Konsequenzen:
Will man den Arduino-Urlader belassen, ist das Makefile zum Programmieren daraufhin zu ändern (in etwa):
avrdude -c arduino -P COMx -p $(DEVICE) -e -U flash:w:$<
Ein Problem mit dem Mikrocontroller ATmega32U4 ist die schiere Größe des Urladers. Etwas kleiner und schon wäre mehr Platz für das Anwendungsprogramm.
BOOTSZ[1:0] | Größe | Startadresse | Platz für Äpp | Beispiel | Kompatibel? | Äpp kann Flash schreiben? | Quelltext? | Programmiersoftware | Erreichbarkeit |
---|---|---|---|---|---|---|---|---|---|
00 | 4 KByte | 0x7000 | 28 KByte | Vorprogrammierter Atmel-Urlader | nein | ja | nein | Atmel Flip; dfu-programmer | |
01 | 2 KByte | 0x7800 | 30 KByte | Arduino-Urlader „Caterina“ | avr109 | nein! | C++: LUFA | Arduino: avrdude (langsam!) | 2× |
10 | 1 KByte | 0x7C00 | 31 KByte | nicht gesichtet | |||||
11 | 0,5 KByte | 0x7E00 | 31,5 KByte | ubaboot | untereinander | ja | Assembler | Python-Skript | |
Mein ubaboot | Assembler | Win32-Programm | |||||||
egal | 0 | — | 32 KByte | Kein Urlader! | jedes ISP-Programmiergerät | ja | — | avrdude | vom Programmiergerät gesteuert |
Bei Änderung der Urlader-Größe sind die Fuses entsprechend anzupassen!
BOOTSZ[1:0] | Größe | Startadresse | LFUSE | HFUSE | EFUSE | LOCK |
---|---|---|---|---|---|---|
00 | 4 KByte | 0x7000 | 0x5E = 0b01011110 | 0x99 = 0b10011001 | 0b11110011 | 0xEC = 0b11101100 |
01 | 2 KByte | 0x7800 | 0x9B = 0b10011011 | |||
10 | 1 KByte | 0x7C00 | 0x9D = 0b10011101 | |||
11 | 0,5 KByte | 0x7E00 | 0x9F = 0b10011111 |
Keiner der Urlader kann Fuses setzen. Daher sind applikationsspezifische Fuses beim Programmieren des Urladers zu setzen, etwa:
Die übrigen Fuses können entweder durch Software in ihrer Wirkung überschrieben werden oder haben starke Auswirkungen auf den Urlader selbst. Jeder dieser Urlader muss auf andere Quarzfrequenzen angepasst werden; nur der Original-Atmel-Urlader kann automatisch zwischen 8-MHz- und 16-MHz-Quarz umschalten. Gesonderte Energiesparoptionen sind bei Verwendung von USB (erlaubte Schlafstromaufnahme: 500 µA) kaum relevant. Für batteriebetriebene Systeme (in der Kapazität einer CR2032-Knopfzelle) eignet sich der ATmega32U4 ohnehin nicht allzu sehr, da für Batteriebetrieb nicht auf einen alternativen Oszillator umgeschaltet werden kann. Zudem fehlt der vom ATmega328 bzw. ATmega8 bekannte asynchrone Oszillator mit dem 32-KHz-Uhrenquarz.
Wie der Original-Atmel-Urlader ist ubaboot Low-Speed-fähig, d.h. läuft (prinzipiell: ungetestet!) auf einem Controller ohne Quarz, typischerweise dem ATmega32U4RC. Der Arduino-Urlader Caterina benötigt Full-Speed für USB-Konformität und damit einen Quarz.
Ändern des Urladers: Geht nur mit dem ISP-Anschluss! Man braucht dazu ein konventionelles Programmiergerät oder einen als solchen hergerichteten und betankten Arduino.
Default-Urlader: Microchip liefert die Chips ab Werk mit dem 4-KByte-Atmel-Urlader betankt. Die Arduino-Hersteller ändern diesen ab durch „ihren“ 2-KByte-Caterina-Urlader. Das betrifft faktisch alle Boards mit aufgelöteten Chips, also Leonardo, Mini, Pro Micro usw. jedoch nicht solche die als Entwicklungssystem verkauft werden.
Urlader | Treiber | Zugriff |
---|---|---|
Original Atmel | libusb | dfu-programmer |
Atmel Flip | ||
winusb | (uba.exe geht nicht) | |
Arduino Caterina | usbser | avrdude -p arduino |
ubaboot | libusb | uba.exe |
winusb | TODO: uba.exe erweitern! |
Dieser unterscheidet sich von ubaboot nur:
Download Fertig und reif für die Allgemeinheit, getestet für ATmega32U4 und AT90USB162, daher geeignet für Arduino Leonardo, Pro Micro u.ä. Boards. Außerdem für den zweiten Mikrocontroller ATmega16U2 (USB-Seriell-Wandler) des Arduino Uno.