Convac-Steuerung mit ATmega32U4

Problem: Totalausfall des Convac-Spinätzers durch Hirntod.

Bedientableau mit Rezept-Editor in Aktion

Hardware

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.

Anschlussbelegung mit Prozessorpinnamen (und verfügbaren Funktionen)

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.

Der Schaltplan der neuen Platine: Simpel
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.

Schaltpläne

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.

Anzeige

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.

Der Schaltplan der abgeräumten LC-Anzeigen-Platine: Kniffliger

Daher gab es schließlich für die Software keine andere Chance, als das Display vollgrafisch anzusteuern: Eine zusätzliche, unerwartete Herausforderung!

Software

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.

Arbeitsweise des Programms

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.

Anzeige

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.

Grenzen

Speicher

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.

Zeit

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.

Software-Erstellung

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.

Programmieren des Chips

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.

Ersatzbeschaffung

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:$<

Ressourcen

Der häufig verbaute 74HCT244 mit seiner wirren Anschlussbelegung

Urlader

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.

Mögliche Urlader-Größen
BOOTSZ[1:0]GrößeStartadressePlatz für ÄppBeispielKompatibel?Quelltext?ProgrammiersoftwareErreichbarkeit
004 KByte0x700028 KByteVorprogrammierter Atmel-UrladerneinneinAtmel Flip; dfu-programmerRESET während PE6/HWBE = Low
012 KByte0x780030 KByteArduino-Urlader „Caterina“avr109C++: LUFAArduino: avrdude (langsam!)RESET, Timeout 8 Sekunden
101 KByte0x7C0031 KBytenicht gesichtet
110,5 KByte0x7E0031,5 KByteubabootuntereinanderAssemblerPython-SkriptRESET während PE6/HWBE = Low
Mein ubabootAssemblerWin32-Programm

Bei Änderung der Urlader-Größe sind die Fuses entsprechend anzupassen!

Urlader-Größen und Fuses
BOOTSZ[1:0]GrößeStartadresseLFUSEHFUSEEFUSELOCK
004 KByte0x7000 0x5E = 0b01011110 0x99 = 0b10011001 0b11110011 0xEC = 0b11101100
012 KByte0x7800 0x9B = 0b10011011
101 KByte0x7C00 0x9D = 0b10011101
110,5 KByte0x7E00 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.

Eigener Urlader

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.