Mini SX1 Decoder Programmiermodul


Ein weiteres Mini-Projekt wurde "notwendig" um feststellen zu können, ob die gewonnenen Einsichten
ausreichend sind, um wenigstens SX1-Decoder der Fa. Doehler und Haass programmieren zu können.

Dieses Modul eignet sich NICHT für den Betrieb an einer Standardzentrale wie die CC2000 o.ä.

weil der Datentransfer auf dem Bus die SX-Adressen 106 und 109 verändert.
Mit meiner Mini-Zentrale ist das kein Problem, weil dort keine Gleisfunktionen implementiert sind und
keine Veränderung von irgendeiner Adresse stattfindet oder darauf reagiert wird.

Um mit möglichst wenig Bauteilen, und den damit verbundenen Lötstellen, auszukommen habe ich diese
Schaltung auf einer Lochrasterplatine aufgebaut.




Weglassen könnte ich noch den Programmierstecker und den Quarz mit den beiden Kondensatoren.
Aber in Erwartung häufig notwendiger Programmierung und um exakte Impulszeiten realisieren zu
können, habe ich nicht darauf verzichtet.




Das Hardwarekonzept:

Zur Ansteuerung des Programmiergleises dient die L6202 Vollbrücke, die der Atmel Mikro Mega8 direkt
ansteuern kann. Lt. Datenblatt sind C1 bis C3 notwendig und der Siebelko C10 sollte samt D2 eine
ordentliche Versorgungsspannung liefern. Der Baustein hat einen Anschluss für den Strommesswiderstand
(Sense). D1 begrenzt die Messspannung am Eingang des Analogkomparator AIN0.
Die Vergleichsspannung liefert der Spannungsteiler R4, R3, ca.0,3 Volt. Die Schreibleitung X1 Pin 5 ist
über die empfohlenen 100 Ohm an PD4 angeschlossen. Der 7805 wird auch gebraucht und versorgt den
Prozessor.

Mit 10 Euro ist alles bezahlt und in 3 Stunden gelötet. Die beiden IC's haben edle Sockel bekommen.
Praktisch sind noch 2 Messdrähte an PD5 und am enable Eingang der Brücke zum Triggern des Scope's.

Das Softwarekonzept:

Den Datenaustausch habe ich via SX-Bus vorgesehen, d.h. die Funktionalität zum Lesen und Schreiben
bestimmter Adressen unter Programmkontrolle ist notwendig. Die Routinen für den SX-Bus habe ich
meinen Decodern für Schalten und Melden entnommen und angepasst.

Eine wichtige Ergänzung der SX-Routinen ist die Einführung von Flags für den Synchronbereich und als
"Done" Bit für Schreiben und Lesen. Das ermöglicht die simple Synchronisation der Hauptprogramm-
Funktionen mit den Interrupt gesteuerten SX Programmteilen.

Ereignisgesteuerte Programme sind wesentlich einfacher zu gestalten, wenn man für Eingangssignale
eine Flankenerkennung einbaut. Deshalb folgt nach jedem Lesen des Anforderungskanals, K106, die
hierfür notwendige Logik:

ldi r17,106         ; K106 ist der Anforderungskanal
rcall adre_rech
rcall wart_lesen
lds r30,$62         ; K106 akt Stand aus Übergabezelle holen
sts K106,r30        ; und im Statusbyte speichern

;** Flankenerkennung ************** **
lds r31,$65     ; letzten gelesenen Wert holen
sts $66,r31     ; nach alt schieben
sts $65,r30     ; nach neu speichern
mov r11,r30     ; Neu
eor r11,r31     ; veränderte Bit sind in r11 Hi
and r30,r11     ; neue Hi in r30
and r31,r11     ; neue Lo in r31


sbrc r30,6     ; Programmieren anfordern mit neuem Hi in Bit 6
rjmp anforder
sbrc r30,7     ; Do it = neues Hi
rjmp doit
sbrc r31,7     ; Do it = neues Lo zum Abbau des Vorganges
rjmp doit_abbau
rjmp nixles


Die Bit in r30 und r31 sind nur 1 Zyklus lang gesetzt, d.h. sie sind wieder Lo wenn der
nächste Lesevorgang den identischen Logikpegel liefert.


Die Subroutinen:


adre_rech:
    mov r18,r17         ; Dezimaladresse
    andi r18,0b01110000 ; Unteradresse isolieren
    swap r18
    ldi r19,6
    sub r19,r18
    sts $61,r19         ; abspeichern
    ldi r18,0b00001111  ; Gruppenadresse isolieren
    and r17,r18
    eor r17,r18         ; invertieren
    sts $60,r17         ; abspeichern zur Übergabe an Leseroutine
    ret

wart_lesen:
    clr r29
 wa_3:
    sbis PIND,3         ; Warten bis Schreiben gestartet
    rjmp wa_3
 wa_4:
    sbic PIND,3         ; Warten bis fertig geschrieben
    rjmp wa_4
    ret



Die eigentlichen Decoderprogrammteile "loklesen" bzw. "lokschreiben" sind ablaufgesteuert und dürfen
wegen der notwendigen genauen Impulszeiten nicht unterbrochen werden. Deshalb wird vor dem " rcall " der
externe Interrupt  " INT0 "  abgeschaltet.
Ersts nach Beendigung der Programmierfunktion erfolgt die Wiederfreigabe für den Datentransfer auf dem
Sx-Bus. Hier die Programmstellle zum Aufruf der Schreibfunktion  " lokschreiben ":

bit3set:
ldi r17,105         ; K105 ist H-Bit und Adressen Kanal
rcall adre_rech
rcall wart_lesen
lds r30,$62         ; K105 akt
sts K105,r30

ldi r17,104         ; K104 ist "II BBB VVV"
rcall adre_rech
rcall wart_lesen
lds r30,$62         ; K104 akt
sts K104,r30

clr r17
out GICR,r17         ; enable INT10 AUS

rcall lokschreiben

ldi r17,0x40
out GICR,r17         ; enable INT10 EIN




Lesen und Schreiben auf dem SX-Bus:

Der Funktionswechsel zwischen Lesen und Schreiben und der Adresswechsel darf nur dann erfolgen, wenn kein
Vorgang läuft und der aktuelle Zustand der SX-Datenleitung erfasst ist. Hier die Programmstelle:

;** Datenleitung übernehmen **

sbis PIND,0       ; Skip wenn Datenleitung LO
rjmp dat_hi

ldi r25,0x01      ; Setze LSB weil Datenleitung HI
or r1,r25         ; Eintragen in Vorlaufregister

;** Innerhalb der gültigen Synchrongruppe ist PD1 = 1 oder PD3 =1 **
;** der Wartezähler ist bis zum gültigen Datebyte != 0

dat_hi:

    sbic PIND,1        ; Schreiben bereits Ein ?
    rjmp schreib       ; ja, weiterschreiben

    sbic PIND,3        ; Lesen Bereits Ein ?
    rjmp lesen         ; ja, weiterlesen


    sbis PIND,5        ; Sync gültig = 1
    rjmp synctest      ; nein weiterscannen


    dec r20            ; Wartezähler fertig ?
    breq auftrag       ; ja, neuer Auftrag kann begonnen werden
    rjmp synctest      ; Nein, weiter auf Unteradresse warten

;** Entscheidung lesen oder Schreiben **

auftrag:
    cbi PORTD,5     ; Wartezähler = 0, Flag Syncbit Aus!

    tst r29         ; Anforderung aus dem Hauptprogramm
    brne schreibsta ; Schreiben = 1
    rjmp lessta     ; Lesen     = 0
;***************************************************************************
schreibsta:         ; der Schreibstart

      lds r10, $63 ; in $63 ist das zu schreibende Byte
     usw. usw.


Soweit die Ablaufsteuerung und Kommunikation mit der Steuersoftware. Es folgt das "Eingemachte" der
Decoderbedienung, die ich, wie beschrieben, weitgehend aus dem Testprogramm von Herrn Haass übernommen
habe. Ich denke das sind Programmmodule, die es schon seit geraumer Zeit gibt und die sich bewährt haben.
Möglicherweise ist es auch eine Portierung von "kenne ich nicht Prozessor" auf den Atmel Mega8.

Nach diversen Stunden Assemblerzeilen studieren, wurde mir aber die, stellenweise elegante (trickreiche)
Programmierung klar und ich musste lediglich die Bedienung der Hardware, sprich die Ansteuerung des L6202
und den Messeingang anpassen .
Die Isolierung der SX1-relevanten Teile aus dem " Multiprotokoll-System " (SX1, SX2, DCC, Motorola) für alle
D&H-Decoder ist letztlich auch gelungen und im Teil "haassprog.asm" nachzulesen.


Doehler & Haass Subroutinen:

Die Details zu den Prinzipien und Signalverläufen habe ich an anderer Stelle bereits beschrieben.

Unterprogramm "loklesen":

Dieses Modul benötigt keine Startdaten und schreibt das Leseergebnis umcodiert in das SX1-Format
in die Speicherzellen der Kanäle (Adressen) K104 und K105.
Die Adresszuweisungen des SRAM stehen im Hauptprogramm:

.EQU K104    = $D8 ;    Adresskanal
.EQU K105    = $D9 ;    Datenkanal
.EQU K106    = $DA ;    Anforderungskanal
.EQU K109    = $DD ;    Zustandskanal


Für die Ansteuerung der Gleise verwende ich die integrierte Motor-Vollbrücke L6202. Die Eingangssignale
kommen direkt vom AT Mega8. Die Portpins sind im Hauptprogramm zugewiesen:

.EQU enable  = 3   ;    für L6202 Brücke
.EQU IN1     = 4
.EQU IN2     = 5

Das Ausgangssignal des Mega8 Analogkomparators ist auf dem I/O Register ACSR das Bit ACO und wird
z.B. so abgefragt:

sbic ACSR,ACO     ; Skip wenn kein Strom fließt: AIN0 > AIN1 ACO = Lo


Ich habe mich bemüht, das Programm so zu kommentieren, dass ich es hoffentlich in einem Jahr wieder verstehe.
Ergo gibt es diese Informationen nur dort !


Unterprogramm "lokschreiben":

Für das Programmieren der Decoderdaten werden die Kanäle K104, K105, K106 und K109 verwendet.
Die erforderlichen Zuweisungen sind bereits erläutert.

Beim Start des Programmierens werden die Daten im Decoder zuerst gelöscht. Dazu werden in den beiden
Sende-Bytes   
" byte_1 und byte_2 "   alle Bits gesetzt (255 = 0xFF= 0b11111111) bevor die
Senderoutine  
 " p_altzyk "   in Aktion kommt. Aus diesem Modul wird die Erzeugung der Gleisspannung
"gecallt". Dieses Modul hat 3 Einsprungadressen:

        o_pd1:      für Ausgabe log Hi,
        o_pd0:      für Ausgabe log Lo
        o_pdat:     für die Ausgabe entsprechen logischem Zustand des Carry-Bit.

Nach der für D&H Decoder notwendigen Wartezeit von etwa 250 Millisekunden, erfolgt der 2. Schreibvorgang
mit den neuen Parametern für Adresse, Anzahl Halteabschnitte,  Impulsbreite der Motorregelung, Wert für die
Massensimulation (Beschleunigung) und dem Wert der maximalen Geschwindigkeit. Die in K104 und K105
übergebenen Werte müssen aber noch " D&H-gerecht" umkodiert werden. Die geschieht hier:

p_altp2:                 ; 2. Durchlauf:
cbr r25,bit5             ; 'error' - bit

; *** Datenbyte1 Adresse und Halteabschnitte aufbereiten ********************

ldi yl,K105              ; K105
ld byte_1,Y              ;
ldi temp1,0b11110000     ; Korrektur Adresse
eor byte_1,temp1         ; Gruppenadresse invertieren

; *** Datenbyte2 Beschleunigungswert, Impulsbreite und max Geschwindigkeit **

ldi yl,K104     ;
ld temp2,Y      ;

; *** Korrektur Beschleunigungswert **

ldi temp1,0b00100000      ; Bit 5 invertieren
eor temp2,temp1
;
ldi temp1,0b00111000 ;
sbrc temp2,5              ; Wenn Bit 5 gesetzt B = 7 addieren
add temp2,temp1 ;

andi temp2,0b00111111     ; Bit 6 und 7 löschen
mov byte_2,temp2 ;
ld temp2,Y                ; K104 nochmal laden
clr temp1                 ; Korrektur I1,I2 vertauschen

sbrc temp2,7              ; Wenn Bit7 in K104 gesetzt ....
sbr temp1,bit6            ; Bit6 setzen im Sendebyte

sbrc temp2,6              ; Wenn Bit6 in K104 gesetzt ....
sbr temp1,bit7            ; Bit7 setzen im Sendebyte
or byte_2,temp1           ; Ergebnis in Sendebyte übernehmen
ldi temp1,0b11111111 ;
eor byte_2,temp1          ; ganzes Sendebyte invertieren

rcall p_altzyk            ; zur Senderoutine !

Ein ganz entscheidend wichtige Programmfunktion !!

Die Ansteuerung des Gleis nach SX-Mode besorgt dann der Abschnitt   " o_pdat1: "   wobei
das Steuerbit für die jeweilige Schaltrichtung Register 25 Bit 0 ist.

;****************************************************************************
; SX1 PROG Datenausgabe auf Gleis Steuerung der Endstufe
; Impulszeiten: Takt 8 uSek. Daten 12 uSek.
;****************************************************************************

o_pd1:                   ; Data=1:
ldi temp1,0b00000001     ; = bit.0
eor r25,temp1            ; invertieren Bit 0;
rjmp o_pdat1             ;

o_pd0:                   ; Data=0:
nop
nop
rjmp o_pdat1

o_pdat:                  ; Data aus carry:
ldi temp1,0b00000001     ; = bit.0
brcc o_pdat1             ; von lsr byte_1 ist carry wie b0 vorher
eor r25,temp1            ;

o_pdat1:                 ; Ansteuerung Gleis:
rcall t_10us             ; Angepasst nach Scopemessung für 12 uSek
cbi PORTC,enable         ; Enable AUS 2 Takte
cbi PORTC,IN1            ; Sink 1 2 Takte
cbi PORTC,IN2            ; Sink 2 2 Takte
sbi PORTC,enable         ; Brücke EIN
rcall t_07us             ; Angepasst nach Scopemessung für 8 uSek
sbrc r25,0               ;
rjmp o_pdoq              ;

o_pdon:
cbi PORTC,enable         ; Brücke AUS
sbi PORTC,IN1            ; Source 1
cbi PORTC,IN2            ; Sink2
sbi PORTC,enable         ; Brücke EIN
ret ;

o_pdoq:
cbi PORTC,enable         ; Brücke AUS
cbi PORTC,IN1            ; Sink 1
sbi PORTC,IN2            ; Source 2
sbi PORTC,enable         ; Brücke EIN
ret ;

In "  o_pdat1 " wir zuerst der akt. Schaltzustand als Datensignal weitere 10 Mikrosekunden gehalten, was mit den
Laufzeiten der übrigen Befehle zu einer Impulsbreite von 12 uSek. führt.
Danach werden in jedem Fall beide Gleise an GND gelegt ( Sink1 und Sink2 ) und die Taktzeit 7 bzw. 8uSek
gewartet. Danach entscheidet r25 Bit 0 welches Potential an die Gleise kommt.

Schlussbemerkung:

Ohne das Programm, das mir Herr Haass freundlicherweise überlassen hat, hatte ich keine Chance den
Umkodierungen auf die Schliche zu kommen, da ich nirgends entsprechende Beschreibungen gefunden habe.
Das muss aber nicht heißen, dass es diese Informationen nicht gibt!


Meine Tests habe ich mit kleinen DHL050 Decodern durchgeführt, das Programmiermodul an meine Mini-Zentrale
angeschlossen und den DecoderProgrammer von Henning Voosen verwendet.
Die Fahrtests mit den umprogrammierten Loks fanden auf meinem Selectrix System aus einer CC2000
mit TRIX Handy Control statt.

Über andere Konfigurationen kann ich mangels Testobjekten keine Aussagen machen.

Dankbar wäre ich den "geneigten Lesern" für Fehlermeldungen, Hinweise oder Anregungen!


Winfried Steinhart     im November 2008

Links auf meine Dateien:
Hauptprogramm:    lok_prog.asm
ProgModul:             haassprog.asm
Prinzip, Signale:     deco_progra.htm