Contents
Im Folgenden sollen der grundlegende Aufbau und insbesondere die DCC-Signalerzeugung der ARC1 Firmware betrachtet werden. Die dargestellten Flussdiagramme sollen dabei zum leichteren Verständnis der Abläufe dienen. Momentan sind die Flussdiagramme ausschließlich auf Englisch verfügbar, da auch die Code-Dokumentation rein Englisch gehalten ist.
Main Program
Nach dem Systemstart werden zunächst alle Gerätetreiber (z.B. für serielle Kommunikation, digitale Ein- / Ausgänge, Flash, Timer etc.) und die auf dem Board oder extern befindlichen Komponenten initialisiert (BSP – Board Support Package). Dies sind bspw. Display, Touchscreen, SDRAM, LED Ring etc. Da die gesamte Firmware auf Basis eines statischen Schedulers und Timer-Interrupts arbeitet, müssen auch diese entsprechend initialisiert und gestartet werden. Nach dem Laden aller gespeicherten Einstellungen und Lokomotiven aus dem nichtflüchtigen Flash-Speicher des Prozessors geht die Firmware in den Betriebsmodus über und der statische Scheduler steuert die zeitliche Ausführung verschiedener Programmteile. Im wesentlichen ist das der 100Hz-Task zur Erfassung der Eingabegeräte und zur GUI-Ablaufsteuerung.
SysTick Timer 100Hz-Task
Mit 100Hz (also im Abstand von 10ms) werden durch den statischen Scheduler des Hauptprogrammes alle Eingabegeräte (Touchscreen, Buttons, Fahrtregler) erfasst und enstsprechende Events für die aktuelle GUI-Ansicht in einem dynamischen Event-Buffer angelegt. Die Verwendung des Event-Buffers ermöglicht ARC1, parallele Events zu erfassen und zu verarbeiten (bspw. die gleichzeitige Bedienung von Touch und Fahrtregler, oder die gleichzeitige Bedienung von Fahrtregler und Buttons). Ein Sonderfall ist hier nur der Nothalt-Button, der direkt zu einer Erzeugung der Nothalt-DCC-Nachricht an die Gleise führt. Nach Erfassung der Eingabegeräte wird der Event-Buffer abgearbeitet und die entsprechenden Event-Callback Funktionen der aktuellen GUI-Ansicht aufgerufen. Dort findet dann die Verarbeitung und das Aktualisieren des Display-Inhaltes statt.
DCC Managing Timer IRQ
Der DCC Manager ist für den bandbreitenoptimierten Parallelbetrieb vieler Loks optimiert und verwaltet mit insgesamt 3 prioritätsbasierten DCC-Signalbuffern die Erzeugung und Steuerung der DCC-Kommandos. Um die Verwaltung der Buffer und die Echtzeit-Erzeugung der logischen DCC-Signale sauber zu trennen, kommen zwei sogenannte „Launchpads“ zum Einsatz – zwei geschützte Speicherbereiche deren Adressen jeweils im Wechsel dem DCC-Signalgenerator übergeben werden. Somit kann eine Nachricht bereits aus einem Buffer in das Standy-Launchpad kopiert werden, während die aktuelle Nachricht im Active-Launchpad noch vom Signalgenerator abgearbeitet wird.
Zum Einsatz kommen drei FIFO-Ringbuffer. Einen Buffer hoher Priorität, bspw. für Geschwindigkeits-Kommandos, einen Buffer niedriger Priorität, bspw. für Licht / Funktionen, sowie einen Wiederholungs-Buffer. Der Wiederholungs-Buffer hat die niedrigste Priorität und dient zum einen dazu, hohe oder niedrigpriore Nachrichten direkt zu Beginn zu wiederholen, zum anderen werden über ihn die aktuellen Lok-Zustände (Geschwindigkeit, Licht, Funktionen) aller Loks in regelmäßigen Abständen erneut gesendet. Dies ist notwendig, um nach Kontaktverlust einer Lokomotive zum Gleis und daraus resultierendem Neustart des Lok-Dekoders den Fahrbetrieb aufrecht zu erhalten.
Der DCC Manager ist Interrupt-gesteuert und arbeitet mit 1kHz. Zu Beginn werden die drei DCC-Buffer ihrer Priorität nach durchlaufen und nach DCC-Kommandos gesucht, die zum einen noch nicht durch ein jeweils aktuelleres Kommando an die gleiche Lok-Adresse abgelöst wurden (obsolete) und deren Lok-Adressen nicht der 5ms Adress-Sperre (vgl. NMRA S-9.2, Frequency Of Packet Transmission) unterliegen. Wird ein gültiges Kommando gefunden und ist das Standby-Launchpad noch nicht belegt, wird die Nachricht zum einen dorthin kopiert, zum anderen die Adresse mit der 5ms Adress-Sperre belegt. Wird in allen Buffern keine gültige DCC-Nachricht gefunden, wird ein Flag zur Steuerung der Kommando-Wiederholung gesetzt. Nach dem Durchlaufen der Buffer werden alle gespeicherten Lokomotiven auf Änderungen in ihrem Zustand geprüft und entsprechende DCC-Kommandos generiert und den Buffern hinzugefügt. Sind keine Änderungen vorhanden und ist das Flag zur Kommando-Wiederholung gesetzt (waren also auch vorher schon alle Buffer leer) werden die Lokomotiv-Zustände aller Loks der Reihe nach zur Wiederholung freigegeben. Sind keine Lokomotiven auf ARC1 gespeichert, versendet der DCC Manager Idle Messages, um den Wechsel von auf dem Gleis vorhandenen Loks in den Analog-Modus zu vermeiden.
DCC Signal Generation
Der DCC Signalgenerator basiert auf einem PWM-Timer-Interrupt, dessen Frequenz durch das DCC Signal selbst gesteuert wird und der die höchste Interrupt-Priorität besitzt. Gemäß NMRA DCC-Spezifikation S-9.1 wird eine logische 1 über eine nominelle Pegelbreite von 58us und eine logische 0 über eine nominelle Pegelbreite von 100us definiert. Bei 50% Duty-Cycle des PWM-Signals zum Erzeugen des Flankenwechsels zwischen positivem und negativem Pegel, führt das zu Timer Frequenzen von 8,62kHz für eine logische 1 und 5,00kHz für eine logische 0 (f=1/(0.000058s*2) bzw. f=1/(0.0001s*2)).
Tritt der Interrupt ein, wurde also 1 Bit der DCC-Nachricht als Pegel ausgegeben, werden zunächst alle weiteren Interrupts gesperrt. Mit Hilfe einer State-Machine wird die DCC-Nachricht sektions-, byte- und bitweise durchlaufen und abhängig vom zu verarbeitenden Bit-Zustand das Auto-Reload-Register des PWM-Timers neu gesetzt. Wurde eine Nachricht komplett bearbeitet, werden die Adressreferenzen von Standby- und Active-Launchpad getauscht, um nahtlos und ohne Zeitverzug die Folgenachricht auf das Gleis abzusetzen.
Buffer
Die Funktion zum Anhängen einer neuen DCC-Nachricht an einen der drei Ringbuffer wird sowohl innerhalb des DCC Managers als auch beim Anlegen einer Nothalt-Nachricht direkt aus dem SysTick 100Hz-Task heraus aufgerufen. Zunächst wird geprüft, ob sich ein gleiches DCC-Kommando mit derselben Zieladresse bereits im angegebenen Buffer befindet. Ist dies der Fall, wird die alte Nachricht als obsolet markiert. Handelt es sich bei dem Bestimmungsbuffer der Nachricht entweder um den Low- oder High-Priority Buffer, wird die Nachricht zunächst dort angehängt, bevor sie zusätzlich 3x in den Wiederholungs-Buffer geladen wird, um die Kommandoübermittlung auch bei schlechtem Gleiskontakt zu sichern. Handelt es sich bei dem Bestimmungsbuffer gleich um den Wiederholungs-Buffer (etwa wenn Lok-Kommandos zyklisch wiederholt werden), wird die Nachricht ausschließlich dem Wiederholungs-Buffer angehängt.