OpenDCC MobaList

Überblick, Entstehung


    Dieses Projekt entstand eigentlich bei Michael Volk (MoBaLiSt.de). Es beinhaltet eine Lichtsteuerung mit 24 Ausgängen und 2 Eingängen. MoBaLiSt war ursprünglich unabhängig von OpenDCC und BiDiB, allerdings wurde eine RS485-Schnittstelle verwendet, diese ist ab Platinenversion 2 kompatibel zu BiDiB.

    Im Zuge der Zusammenarbeit verschiedener OpenSource-Projekte habe ich für diese Hardware eine BiDiB-Firmware beigesteuert. Diese Firmware implementiert Makrosteuerung gemäß Level 2 nach BiDiB, alle 24 Ausgänge haben den vollen Funktionsumfang von BiDiB-Lichtkanälen und können Dimmen, Blinken, Doppelblitzen. Die Dimmkurven und Steuerungen beinhalten auch Neonröhren und Gaslaternensimulation sowie eine Zufallssteuerung. Somit kann MoBaLiSt als preiswertes Modul für nahezu alle Beleuchtungsaufgaben eingesetzt werden.


    Diese Hardware hat folgende Eigenschaften:
      Daten MoBaLiSt
      24 frei programmierbare Lichtausgänge mit je 300mA, Helligkeitssteuerung über PWM. (inkl. Augenkorrektur)
      2 universelle Eingänge (für Lagesensoren / Taster / Optokoppler)
      1 BiDiBus-Anschluß

Schaltplan

    Hier verweise ich auf die Unterlagen von MoBaLiSt.de. Als Prozessor ist ein Atmega32 eingesetzt, Ausgangstreiber sind die üblichen ULN2803. Jeder Ausgang kann kurzzeitig mit max. 500mA belastet werden, die Summe aller Ausgänge darf 1A nicht überschreiten. Für größere Belastungen, wie z.B. Magnetartikel oder Antriebe über 300mA Verbrauch, muss ein stärkerer Transistor oder ein Relais nachgeschaltet werden.
    Mobalist hat auch eine Version mit stärkeren Treibern beschrieben.

Download

    mobalist_V2.0.3: 24.01.2014 Komprimierte Speicherung von Makros, dadurch mehr Platz für Stack. Anzahl der Macroschritte reduziert auf 16 Einträge, nur noch 6 Begriffe je Accessory. Zusätzliche Stackabprüfung eingebaut, bei Stacküberschreitung gibt es Doppelblitze und der Knoten bleibt hart stehen.
    mobalist_V2.0.1: 04.01.2014 Ergänzung: Speichermöglichkeit eines Usernamens (Hinweis: durch die geänderte EEPROM Struktur ist ein Neuladen des EEPROMs erforderlich, gespeicherte Makros gehen dadurch verloren und müssen anderweitig gesichert werden; das ist auch der Grund für den Versionssprung).
    mobalist_V1.5.0: 14.10.2013 Ergänzung: es gibt ein weiteres Firmwaremodell (TURNOUT) mit anderer Aufteilung des Speicherplatzes. (Hinweis: die Stackkontrolle in V2.* legt den Verdacht nahe, dass die V1.5.* auch bereits Speicherplatzprobleme hatte.)
    mobalist_V1.4.0: 24.07.2013 Bugfix: im BiDiBus werden fälschlich Nachrichten an einen Subknoten hinter einen Hub auf einer anderen Adresse interpretiert. Update empfohlen. (EEPROM kann unverändert bleiben, Makros bleiben dann erhalten)
    mobalist_V1.3.9: 07.05.2013 Bugfix bei CV-read per MSG_VENDOR
    mobalist_V1.3.8: 13.04.2013 MSG_LOGON_REJECTED wird ausgewertet (wichtig, wenn mehr als 32 Nodes am Bus sind)
    mobalist_V1.3.7: 17.03.2013 bugfix bei Zahl der Macros je Accessory
    MobaList V1.3.6: 31.10.2012 Fixed Interruptproblem on BiDiB, neu dazu: Accessory Mapping
    MobaList V1.2.3: 14.10.2012 Fixed Init for Macro Size
    MobaList V1.1.1: 24.06.2012 erste Version

    Source:
    mobalist_src_V2.0.0

Firmware-Infos

    Es gibt ab Version 1.5.0 zwei verschiedene Firmwareversionen. Beide Versionen sind im Download enthalten. Beim Wechsel zwischen den Firmwareversionen sind immer beide Bestandteile (also Flash und EEPROM) auszutauschen. Die Datei mit der Endung *.000.hex enthält die Flash-Daten, die Datei mit der Endung *.001.hex enthält die EEPROM-Daten (*.eep).
  • Version STANDARD:
      - 8 Accessory
      - 12 Makros mit je 18 Plätzen
    Eignung: für Beleuchtungsaufgaben und für (komplexere) Signale; die Verwendung für Schaltaufgaben ist möglich, es kommt aber fallweise zu einem Engpass bei der Zahl der Makros.
  • Version TURNOUT:
      - 12 Accessory
      - 24 Makros mit je 6 Plätzen
    Eignung: für Schaltaufgaben und für Signale. Die Vorbelegung der Makros und Accessory ist für gepaarte Weichenantriebe mit Pulsansteuerung geeignet.

Firmware-Internas

    Modellversionen:
    Die Zahl möglicher Accessory, Makros und Plätzen in den Makros ist per #define-Anweisung in config.h festgelegt und in Summe durch den Speicher des Prozessors beschränkt. Zur leichteren Erzeugung der Firmware sind 'Modelle' definiert (→#define MOBALIST_MODEL), abhängig vom Wert dieser Compilekonstanten werden die #defines für Accessory und Makros gesetzt. Das Modell wird beim Übersetzen des Projektes als externer define mitgegeben (zusätzlicher Aufrufparameter des avrgcc: -DMOBALIST_MODEL=TURNOUT). Neben der Zahl der Accessory und Makros wird auch je Modell eine unterschiedliche Vorbelegung des Makrospeicherplatzes (#include "default_macro_model_turnout.h") angezogen.
    Das Durchreichen des Modells erfolgt auch im Makefile: ruft man make mit folgender Zeile auf,
    make MOBALIST_MODEL=TURNOUT --makefile=Makefile_modelle all
    so wird eine Variable MOBALIST_MODEL=TURNOUT in make angelegt. Diese Variable reicht man dann mit CFLAGS += -DMOBALIST_MODEL=$(MOBALIST_MODEL) an den gcc als Parameter weiter.

    Task, Schedule:
    Wie bereits bei einer Reihe anderer Projekte kommt ein simpler Echtzeitscheduler (Cortos) zum Einsatz.

    LED-Ansteuerung:
    Hier kommt eine Soft-PWM zum Einsatz, welche über einen Timer und dessen Compare-Interrupts kontrolliert wird. Damit man eine Gammakorrektur (also exponentionelle Kennlinie der Helligkeit) implementieren kann, benötigt man eine sehr feine Auflösung.
    Eine Soft-PWM steht und fällt mit der Dauer der ISR, je kürzer, desto besser die Auflösung. Und der Kehrwert von Dauer der ISR mal Auflösungsschritte ist die erzielbare Wiederholrate (wenn man den Prozessor voll auslastet), diese soll auch über 60 Hz liegen, sonst flimmerts.

    Die in der MobaList implementierte PWM-Steuerung macht im Gegensatz zu sonstigen Lösungsansätzen 'Transitional Timing', d.h. nur dann, wenn ein PWM Ausgang tatsächlich umspringt, gibt es eine ISR. Dazu muß man die ISR aus ihrem festen Zeitkorso lösen und mit Hilfe einer vorberechneten Tabelle durch die PWM durchhüpfen. Das reduziert die Zahl der Interrupts je Periode von etwa 4000 auf 25 (=Zahl der Ausgänge + 1). Wenn man zusätzlich den Schleifenzähler aus der ISR verbannt und mit dem zweiten Compareregister des Timers die Wiederholperiode kontrolliert, entsteht eine saubere und schnell auszuführende Soft-PWM.

    Es sind folgende Programmschritte nötig:
  • Einstellung Timer:
        #define T1_PRESCALER 8
        #if   (T1_PRESCALER==1)
          #define T1_PRESCALER_BITS   ((0<<CS12)|(0<<CS11)|(1<<CS10))
        #elif (T1_PRESCALER==8)
          #define T1_PRESCALER_BITS   ((0<<CS12)|(1<<CS11)|(0<<CS10))
        #elif (T1_PRESCALER==64)
          #define T1_PRESCALER_BITS   ((0<<CS12)|(1<<CS11)|(1<<CS10))
        #elif (T1_PRESCALER==256)
          #define T1_PRESCALER_BITS   ((1<<CS12)|(0<<CS11)|(0<<CS10))
        #elif (T1_PRESCALER==1024)
          #define T1_PRESCALER_BITS   ((1<<CS12)|(0<<CS11)|(1<<CS10))
        #else
          #error T1_PRESCALER is not defined or is not a supported value
        #endif
    
        TCCR1A = (0 << COM1A1) | (0 << COM1A0)
               | (0 << COM1B1) | (0 << COM1B0)
               | (0 << FOC1A) | (0 << FOC1B)
               | (0 << WGM11) | (0 << WGM10);
    
        TCCR1B = (0 << ICNC1)       // input noise canceler
               | (0 << ICES1)       // input cature edge
               | (0 << WGM13)
               | (0 << WGM12)
               | T1_PRESCALER_BITS;
        OCR1A = 0xFFFF;               // dieser Compare kontrolliert PWM
        OCR1B = MAX_PWMSTEPS;         // dieser Compare kontrolliert Periode
    
        TIMSK |= (1<<OCIE1A);
        TIMSK |= (1<<OCIE1B);
        
  • ISR (PWM): Der Compareinterrupt jeder Transistion aktualisiert die Ausgangsbits, lädt den nächsten Punkt und verschiebt den Pointer im Ausgabearray.
        ISR(TIMER1_COMPA_vect)
         {
           OCR1A = isr_ptr->delay;     // Naechsten Schaltpunkt laden
           PWM_PORT1 = isr_ptr->port1; // Ports ausgeben
           PWM_PORT2 = isr_ptr->port2;
           PWM_PORT3 = isr_ptr->port3;
           isr_ptr++;                  // auf naechste Transition stellen
         }
        
  • ISR (Periode): Der Compareinterrupt jeder Periode setzt die Pointer für die Transistioninterrupts wieder auf Start und aktualisiert fallweise das Ausgabearray. Hierzu werden Wechselpuffer verwendet, damit auch hier eine extrem kurze ISR erreicht wird.
          ISR(TIMER1_COMPB_vect)
            {
              if (semaphor_query(C_PWM_Buffer))
                {
                  TCNT1 = 0;
                  OCR1A = pwm_array1[0].delay;     // und den Start einladen
                  PWM_PORT1 = pwm_array1[0].port1;
                  PWM_PORT2 = pwm_array1[0].port2;
                  PWM_PORT3 = pwm_array1[0].port3;
                  isr_ptr = &pwm_array1[1];        // der erste COMPA Interrupt soll da beginnen
                }
              else
                {
                  TCNT1 = 0;
                  OCR1A = pwm_array0[0].delay;
                  PWM_PORT1 = pwm_array0[0].port1;
                  PWM_PORT2 = pwm_array0[0].port2;
                  PWM_PORT3 = pwm_array0[0].port3;
                  isr_ptr = &pwm_array0[1];
                }
            }
        
  • Mit dieser Technik erreicht man auf einem Atmega mit 16MHz unter 3us für eine ISR. Das bedeutet eine Auflösung der Soft-PWM von etwa 3000 Schritten bei 80Hz Wiederholrate! Damit kann leicht eine Kennlinie zur Gammakorrektur einrechnen und erhält sehr feinfühliges Dimmen. Helligkeitsverläufe sind auch im Schwachlichtbereich mit dem Auge nicht aufzulösen.


    BiDiB:
    Der BiDiBus wird über einen RS485-Transceiver empfangen. Der UART ist auf 9 Bit eingestellt. Wenn ein Byte mit gesetzem 9. Bit kommt (d.h. es ist ein Token für die Sendeerlaubnis), wird noch in der ISR überprüft, ob der Token die eigene Knotenadresse adressiert. Falls ja und falls eine abzusendende Nachricht vorliegt, wird direkt in der ISR auf Senden umgeschaltet, die TX-ISR freigegeben und auch gleich das erste Datum in den UART geschrieben.
    Wenn das letzte Byte der Nachricht geschrieben wird, dann wird der TX-Complete Interrupt aktiviert, welcher dann nach dem letzten Byte innerhalb von 5µs wieder auf Empfangen umschaltet.
    Der für BiDiB eigentlich notwendige Identify-Taster ist auf den Eingang PROG gelegt: schließt man hier gegen Masse kurz (z.B. mit Jumper), dann wird der Identify-Mode ausgelöst: die Prog-LED blinkt dann.

Bauanleitung

    Der Aufbau ist ausführlich auf mobalist.de beschrieben.
    Die Fuses des Prozessors sind wie folgt zu setzen:
    Fuses ATmega32, MoBaLiSt V2.0
    FUSEBYTE HIGH0xC1CKOPT
    FUSEBYTE LOW0x8FBODEN, Ext Crystal, High Freq.
    Neben den Files im Download muß man auch eine Seriennummer einspielen, diese kann man sich hier generieren. Die generierte Seriennummer bitte auf der Baugruppe vermerken.

    Das Einspielen der Firmware erfolgt in dieser Reihenfolge:
    1. Chip löschen
    2. Flash Speicher beschreiben. Anschließen blinken alle 2 Anzeige-LEDs, zum Zeichen, dass EEPROM noch nicht geladen wurde.
    3. EEPROM einspielen. Jetzt blinken zwei LEDs, d.h. Seriennummer für BiDiB fehlt noch.
    4. Seriennummer einspielen (und auf der Baugruppe notieren)
    5. EESAVE-Fuse setzen, damit bleibt bei einem Chip-Erase (z.B. bei Update der Firmware) die Seriennummer erhalten.

Makros

    Kern der Ansteuerung ist eine Makromaschine, diese umfaßt Level 2 gemäß BiDiB-Spezifikation. Implementiert sind hier 12 Makrolisten mit je 18 Einträgen.

    Details zu den Makros finden sich hier.

Accessory-Mapping

    Makros lassen sich zu Zubehörobjekten zusammenfassen. Die MoBaList kann 8 Accessory-Objekte mit je max. 8 Begriffen. Für Details verweise ich hier auf die Beschreibung der LightControl.