DCC Decoder Programmierung im Service-Mode

In NMRA RP 9.2.3 sind die Prozeduren und Methoden für die Programmierung beschrieben.

Empfohlen wird, dieses Verfahren auf dem Programmiergleis mit Strombegrenzung auf
250 mA anzuwenden. Wenn man auf die Rückmeldung (Acknowledgement) verzichtet,
gelingt die Programmierung am Booster für die Fahrstrecke. Allerdings muss man dabei
beachten, dass im Sevicemode KEINE Decoderadresse in den Instruktionen enthalten
ist, d.h. alle Decoder die eine Service-Mode-Instruktion empfangen, führen sie auch aus.

Ergo wird man mindestens einen Umschalter einbauen um das Risiko der "Zerprogrammierung"
klein zu halten und ein 47 Ohm /2 W Widerstand in einer Zuleitung schadet auch nicht.

Die Service-Mode-Instruction-Packets haben vor allem eine "Long Preamble" mit
mindestens 20 1-Bit's statt der "normalen" Präambel mit deren 10 bis 12.

RP 9.2.3 definiert 4 Methoden für die Programmierung der CV's:

Adress-Only,    Register-Mode,    Paged CV    und     Direct CV

Vermutlich ist dies in der Entwicklung und Historie der DCC-Decoder begründet. Nach
meiner Einschätzung genügt es, eine Methode vorzusehen, mit der ALLE CV's von
CV #1 bis CV #1024 programmiert werden können und die, zumindest von aktuellen
und moderneren Decodern, verstanden wird. Also werde ich mich (vorerst) auf den
Direct CV-Mode beschränken.

Nachzulesen sind die Details in NRMA 9.3.3. Seite 3 ab Zeile 93.

Packet-definition:

long-preamble 0 0111CCAA 0 AAAAAAAA 0 DDDDDDDD 0 EEEEEEEE 1

CC        sind die beiden Command-Bit, zum Schreiben == 11
A...A     sind die 10 Bit CV-Nummer. ACHTUNG !! Hier ist CV - 1 einzutragen !!
D...D    sind die 8 Datenbit, der neue CV-Wert
E...E    sind Prüfbits, das EXOR-Verknüpfungsergebnis = Byte1^Byte2^Byte3

Um eine CV zu ändern genügt es nach NMRA NICHT dieses Paket an den Decoder zu senden,
sondern es muss eine ganze Paket-Sequenz auf das Programmiergleis gelegt werden:

1.    Mindestens 3 mal ein Reset-Paket mit langer Präambel
2.    Mindestens 5 identische Schreib-Pakete, gleiche CV, gleicher Wert
3.    Mindestens 6 mal ein Reset-Paket mit langer Präambel

Reset-Paket:

1111111111111111111111111 0 00000000 0 00000000 0 00000000 1

das sind: z.B. 25 mal 1-Bit, 27 mal 0-Bit 1 mal 1-Bit, was mit ein paar Schleifen in "C"
simpel zu programmieren ist:

 

//*************************************************************************
//****     CV Schreiben im Servicemode CV-direct-write             ****
//****    int CV_Num und char CV_Wert  vorbesetzt                   ****


void dcc_cv_direct(void)
            // Direct CV Write Sequenz
{
// long-preamble 0 0111CCAA 0 AAAAAAAA 0 DDDDDDDD 0 EEEEEEEE 1

dcc_byte1 = 0b01111100 | ((CV_Num - 1) >> 8) ;
    // Commando, 2 Bit CV_Num
dcc_byte2 = (CV_Num - 1) & 0xFF;
                          // 8 Bit CV-Adresse
dcc_byte3 = CV_Wert;
dcc_pruef = dcc_byte1^dcc_byte2^dcc_byte3;

// RESET

for ( j=0; j<4; j++)
        // 4 x Reset senden
{
    for (i = 0; i<25; i++)    
// Präambel 25 x 1-Bit
    {
        OCR1AL = 57;
       // ergibt 58 Mikrosekunden

        bitsend();
    }

    for (i = 0; i<27; i++)    
// 27 x 0-Bit
    {
        OCR1AL = 115;     
// ergibt 58 Mikrosekunden
        bitsend();
    }
    OCR1AL = 57;
         // 1-Bit senden
    bitsend();
}

// KOMMANDO BYTES

for (j = 0; j < 6; j++)        
// 6 mal Kommando
{
    for (i = 0; i<25; i++)    
// Long Präambel 25 x 1-Bit
    {
        OCR1AL = 57;        
// ergibt 58 Mikrosekunden, wegen 8 Takte Int.
        bitsend();
    }
    OCR1AL = 115;         
// 0-Bit senden mit 116 Mikrosekunden
    bitsend();

    tes = 128;                  
// Testbyte vorbereiten auf Bit 7

    for ( i = 0; i <8; i++)   
// Kommando senden
        {
            if (dcc_byte1 & tes) OCR1AL = 57;      
// 1-Bit senden
            else OCR1AL = 115;
                            // 0-Bit senden
            bitsend();
            tes = tes >> 1;
        }
        OCR1AL = 115;                                    
// 0-Bit senden
        bitsend();

        tes = 128;                    
// Testbyte vorbereiten auf Bit 7

        for ( i = 0; i <8; i++)     
// CV-Adresse senden
        {
            if (dcc_byte2 & tes) OCR1AL = 57;
// 1-Bit senden
            else OCR1AL = 115;    
// 0-Bit senden
            bitsend();
            tes = tes >> 1;
        }
        OCR1AL = 115;
            // 0-Bit senden
        bitsend();

        tes = 128;                    
// Testbyte vorbereiten auf Bit 7

        for ( i = 0; i <8; i++)
      // CV-Wert  senden
        {
            if (dcc_byte3 & tes) OCR1AL = 57;
// 1-Bit senden
            else OCR1AL = 115;  
// 0-Bit senden
            bitsend();
            tes = tes >> 1;
        }
        OCR1AL = 115;         
// 0-Bit senden
        bitsend();


// PRUEFBYTE
        tes = 128;                  
// Testbyte vorbereiten auf Bit 7

        for ( i = 0; i <8; i++)    
// Prüfbyte senden
        {
            if (dcc_pruef & tes) OCR1AL = 57;    
  // 1-Bit senden
            else OCR1AL = 115;                            
// 0-Bit senden
            bitsend();
            tes = tes >> 1;
        }
        OCR1AL = 57;
            // 1-Bit senden
        bitsend();

}
// Ende for (6 mal)

// RESET

for ( j=0; j<6; j++)
            // 6 x Reset senden
{
    for (i = 0; i<25; i++)    
// Long Präambel 25 x 1-Bit
    {
        OCR1AL = 57;       
// ergibt 58 Mikrosekunden, wegen 8 Takte Int.

        bitsend();
    }

    for (i = 0; i<27; i++)
    // 27 x 0-Bit
    {
        OCR1AL = 115;     
// ergibt 58 Mikrosekunden, wegen 8 Takte Int.
        bitsend();
    }
    OCR1AL = 57;
           // 1-Bit senden
    bitsend();
}
}
// Ende

Das kann man natürlich viel "eleganter" codieren, aber so funktioniert es auch.

Insgesamt werden 9 3-Byte und 6 4-Byte Pakete gesendet = 9 x 53 + 6 x 62 = 849 Bit
aber nach rund 130 Millisekunden sollte das erledigt sein.

Jonathan Bohmer, April 2009