Vor ein paar Jahren habe ich im RC-Line Forum einen Thread gefunden, der sich mit der Programmierung von Microcontrollern, hier speziell die von Atmel, befasst.
Als Beispiel hatte der Auto Torsten Gietenbruch praktischerweise einen Decoder für Graupner Schaltmodule programmiert. Diesen Decoder habe ich damals erstmal nach Vorlage nachgebaut um zu schauen, ob das Dingen auch funktioniert. Hat er, sogar ganz gut!
Ich kann mich wohl erinnern, dass der Decoder ziemlich widerwillig beim programmieren war. Es hat lange gedauert, bis ich das Teil zum laufen bekam, aber das lag im Endeffekt nur an den sogenannten Fuses. Diese "Schalter" sind wichtig für die richtige Funktion des Atmels als solches, eine Falschprogrammierung wird gnadenlos mit Fehlfunktion quittiert.
Zwischendurch habe ich im Laufe der Jahre bei meinen PICAXE Experimenten mit selbstgebauten Schaltern experimentiert, aber diesen Decoder hier nie so ganz aus den Augen verloren.
Nach langer Zeit habe ich mich jetzt nun wieder daran gemacht diese Elektronik an meine Bedürfnisse anzupassen und zu ändern. Als erstes sollte die Setup Funktion raus. Diese war als zusätzliches Feature vom Autor hinzuprogrammiert worden um sich vom Original Decoder abzuheben, ich hingegen brauchte das nicht und wollte Code und Hardware verschlanken.
Also wurde die alte Hardware wieder hervorgekramt, der MC19 Sender mit dem Sendemodul ausgestattet und am Originalcode in meiner gewohnt stümperhaften Art herumgepfuscht.
Da ich kein Programmierer bin und auch nur wenig Talent für Programmierung oder sogar Programmperfektionierung habe, muss ich da auf die bewährte Try and Error Methode zurückgreifen.
Die alte Hardware lief noch bestens, alle Ausgänge funktionierten korrespondierend zu den Schaltern am Sender. Eine gute Ausgangsposition. Nach den Modifikationen an der Software musste das Programm in den Atmel überspielt werden. Ich konnte mich noch daran erinnern, dass ich das früher mit Ponyprog über die serielle Schnittstelle meines alten IBM 600x gemacht habe. Das muss besser gehen!
Die Software wurde in BASIC mit einem Programm namens BASCOM geschrieben. Die Software kann gratis heruntergeladen werden und funktioniert als Demoversion bis zu einer Codegrösse von 4kB. Das reicht für viele Programme und auch für den Decoder. Innerhalb von BASCOM gibt es die Möglichkeit, den Code mit verschiedensten Programmieradaptern auf den Zielprozessor zu spielen. Eine Möglichkeit ist das sog. USBASP Interface. Dieses ist recht preiswert, und ich hatte aus diversen Quellen im Laufe der Jahre ein paar Programmer zusammengetragen. Die sollten es werden!
Also wurde eine kleine Platine zusammengelötet die den Prozessor und ein Flachbandkabel zur Konnektierung an den Programmer aufnahm.
Der Code wurde nun auf die überflüssigen Programmteile untersucht. Durch die hervorragende Dokumentierung des Autors konnte ich schnell den entsprechenden Programmteil ausmachen. Dieser wurde zusammen mit ein paar anderen Zeilen gelöscht welche sich beim weiteren Studium als obsolet herausstellten. Dieser Code wurde nun in einen frischen ATMega8 überspielt. Nachdem der Chip in die Hardware gesteckt wurde funktionierte die Software...
... so ziemlich garnicht...
Und nicht nur das, sie funktionierte überhaupt nicht! Auch nachdem ich den originalen Code wieder in den Chip gespielt hatte funktionierte immer noch nichts. Auf der alten Hardware waren einige Tasten und der Drehschalter für die das Setup verbaut, mit dem alten Chip gingen beim Drücken eines Taster eine LED an die die Zustand anzeigte. Hier tat sich garnichts.
Verdammt!
Ich habe die nächsten Abende damit zugebracht, die verschiedensten Programmierszenarien herzustellen. Gestartet habe ich unter Linux mit einer virtuellen Win10 Maschine für diese Zwecke, mein normales Arbeitsumfeld. Dem Chip war kein Lebenszeichen zu entlocken. Weiter gings mit Win7. Hier wurde BASCOM installiert um den Chip zu programmieren, aber auch hier funktionierte der Chip nach der Programmierung nicht. Zwischendurch habe ich verschiedene ATMega8 ausprobiert, kann ja sein, dass der erste Chip ne Macke hat.
Als auch hier nichts ging habe ich einen alten IBM X40 mit einem frischen WindowsXP aufgesetzt. Der noch ältere 600x existierte noch, war aber auch mir unerfindlichen Gründen unglaublich langsam und machte keinen Spass. Als auch hier der Chip nicht zur Funktion zu überreden war habe ich das alte Ponyprog aufgespielt. Die Docking Station, die zum x40 gehört besitzt einen seriellen Ausgang. Den hab ich sonst abgesehen als USB Dongle nirgends mehr ausser am 600x.
Auch hier war es zum verzweifeln. Die Software wurde kompiliert und als .hex Datei abgespeichert sodass sie vom Ponyprog gelesen werden konnte. Sie wurde auch ohne irgendwelche Fehlermeldungen in den ATMega8 übertragen, funktionierte aber dennoch nicht. Nur dieser alte Chip mit dem ich vor ein paar Tage wieder gestartet war ging. Was war anders? Die Chips waren identisch und wenn ich mich recht erinnerte, sogar aus der gleichen Bestellung da ich damals mehr Decoder bauen wollte und immer auf Vorrat kaufe.
Nach einiger Zeit dämmerte es mir, es mussten diese verdammten Fuses sein. Die Dinger, welche ich eingangs nicht ohne Hintergedanken erwähnte, hatte ich praktischerweise VÖLLIG vergessen. Nachdem der alte Chip ausgelesen war, konnte ich in der Tat eine andere Konfiguration zum Lieferzustand erkennen. Diese wurde sofort in einen neuen Chip einprogrammiert und den originalen Code von T. Gietenbruch hinterher geschoben.
Bingo!
Der Chip lief auf Anhieb! Als nächstes folgte der modifizierte Code. Auch jetzt hatte ich auf Anhieb Erfolg. Die Ausgänge schalteten nur noch im Tastbetrieb, so wie es der Schalter im Sender vorgibt und ich es haben wollte.
Eine Erweiterungsplatine für mein 212 steht schon in den Startlöchern. Dort gibt es einige Dinge zu schalten, u.A. soll die Ballastverschiebung mit Motor anstatt Servo gelöst werden um einen Proportionalkanal zu sparen.
'******************************************************
'Projekt: Atmel-Programmierung für Einsteiger
'
'Prozessor: ATMega 8-16
'Bascom-Version: 1.11.8.1
'
'Auswertung für Graupner Nautic Expert Baustein
'
'Version: 1.0
'Version: 1.1
'Programm verschlankt auf das Nötigste. Drehschalter und Setup entfernt. SS
'
'Hardware:
'R/C-Kanal an D.2 (INT0)
'
'18.08.2006 T. Gietenbruch
'16.12.2017 S. Schmitz
'
'******************************************************
'======================================================
'System-Einstellungen
'======================================================
'Definition für Mega 8
$regfile "m8adef.dat"
'Angabe der Taktfrequenz (4Mhz)
$crystal = 4000000
'======================================================
'Konfigurationen
'======================================================
'Konfiguration der I/O-PortsŽs
Ddrb = &B11111111
Ddrc = &B11111111
Ddrd = &B00000011
'Timer 1 für R/C-Signal
Config Timer1 = Timer , Prescale = 1
'Konfiguration des INT0
'Interrupt bei jedem Flankenwechsel (0->1 und 1->0)
Config Int0 = Change
'======================================================
'Deklarationen
'======================================================
Dim N As Byte
Dim N_old As Byte
Dim Signals As Byte
Dim Reading As Bit
Dim Rc_value(10) As Word
Dim Error As Bit
Dim Sync_detect As Bit
Dim X As Word
Dim Switch_up As Byte
Dim Switch_dn As Byte
Dim Sync_ok As Bit
Dim Cycle_done As Bit
Dim Switchhold As Byte
Dim Number As Byte
Dim Watch_dog As Word
Dim Code_raw As Byte
Dim Code_value As Byte
Dim Code_old As Byte
Dim Memory_up As Byte
Dim Memory_down As Byte
Dim Row_up As Bit
Dim Flash As Bit
Dim Flash_delay As Byte
Dim Bit_adr As Byte
'======================================================
'Konstanten
'======================================================
Const Sync_low = 8000
Const Sync_high = 9000
Const Switch_dn_low = 4000
Const Switch_dn_high = 5500
Const Switch_up_low = 7000
Const Switch_up_high = 7900
'======================================================
'Initialisierungen
'======================================================
'Zuweisung der Interrupt-Service-Routinen
On Timer1 Rc_error
On Int0 Rc_read
'Interrupt-Freigaben
Enable Timer1
Stop Timer1
Enable Int0
'Ports initialisieren
Portb = &B00000000
Portc = &B00000000
Portd = &B00000000
'Rücklesen der EEPROM-Variablen
Memory_up = 0
Memory_down = 0
'Freigabe aller Interrupt-Routinen
Enable Interrupts
'Etwas warten, falls die Signale den Watchdog auslösen
X = 0
While X < 10000 And Error = 0
Incr X
Wend
'Konfiguration des internen Watchdogs
Config Watchdog = 512
'======================================================
'Synchronisationsroutine
'======================================================
Syncronize:
Signals = 1
N = 1
Sync_detect = 0
X = 0
'Rücksetzen aller Schaltersignale
For X = 0 To 7
Switch_up.x = 0
Switch_dn.x = 0
Next X
'Rücksetzen der Ports
Portb = 0
Portc = 0
'Warten auf ersten Synchronisationswert
While Sync_detect = 0
Wend
N = 2
Sync_detect = 0
'Warten auf zweiten Synchronisationswert
'Begrenzt durch Zählschleife
X = 0
While X < 5000 And Sync_detect = 0
Incr X
Wend
'Auswertung des Synchronisationsergebnisses
If X < 5000 And Rc_value(1) > Sync_low And Rc_value(2) > Sync_low Then
N = 3
Signals = 10
Else
Goto Syncronize
End If
Watch_dog = 0
'Wartezeit, falls Watchdog doch noch zubeisst
Waitms 2000
'======================================================
'Hauptprogramm-Schleife
'======================================================
Do
'Auswertung der gelesenen Werte (im Block)
If Cycle_done = 1 And Reading = 0 And Error = 0 Then
Cycle_done = 0
'Überprüfung der Synchronisationssignale
If Rc_value(1) > Sync_low And Rc_value(2) > Sync_low And Error = 0 Then
Sync_ok = 1
Else
Sync_ok = 0
Goto Syncronize
End If
'Aktualisierung der Schaltersignale
If Sync_ok = 1 Then
For X = 3 To Signals
Number = X - 3
'Schalter nach oben betätigt
If Rc_value(x) > Switch_up_low And Rc_value(x) < Switch_up_high Then
If Switchhold.number = 0 Then
Switchhold.number = 1
Toggle Switch_up.number
End If
'Schalter nach unten betätigt
Elseif Rc_value(x) > Switch_dn_low And Rc_value(x) < Switch_dn_high Then
If Switchhold.number = 0 Then
Switchhold.number = 1
Toggle Switch_dn.number
End If
'Schalter in Mittelstellung
Else
Switchhold.number = 0
'Schaltersignal rücksetzen, wenn nicht remanent
If Memory_up.number = 0 Then Switch_up.number = 0
If Memory_down.number = 0 Then Switch_dn.number = 0
End If
Next X
'Zuweisung der Hardwareports
Portc.0 = Switch_up.0
Portc.1 = Switch_up.1
Portc.2 = Switch_up.2
Portc.3 = Switch_up.3
Portc.4 = Switch_up.4
Portc.5 = Switch_up.5
Portd.0 = Switch_up.6
Portd.1 = Switch_up.7
Portb.0 = Switch_dn.0
Portb.1 = Switch_dn.1
Portb.2 = Switch_dn.2
Portb.3 = Switch_dn.3
Portb.4 = Switch_dn.4
Portb.5 = Switch_dn.5
Portb.6 = Switch_dn.6
Portb.7 = Switch_dn.7
End If
End If
'Soft-Watchdog
If N = N_old Then
Incr Watch_dog
If Watch_dog > 5000 Then Goto Syncronize
Else
N_old = N
Watch_dog = 0
End If
Loop
'Programmende (nur formal)
End
'======================================================
'ISR für INT0 - Signalfolge lesen
'======================================================
Rc_read:
'Den Timer starten mit steigender Flanke
If Reading = 0 And Pind.2 = 1 Then
Start Timer1
Reading = 1
'Den Timer stoppen mit fallender Flanke
Else
Stop Timer1
Rc_value(n) = Timer1
Timer1 = 0
Reading = 0
'Validierung des gelesenen Wertes
If Rc_value(n) < Switch_dn_low Or Rc_value(n) > Sync_high Then Goto Rc_error
'Prüfung auf Sync-Signal
If N < 3 And Rc_value(n) > Sync_low And Rc_value(n) < Sync_high Then
Sync_detect = 1
End If
'...wenn die Synchronisation fertig ist
If Signals > 2 Then
Incr N
End If
If N > Signals Then
N = 1
Cycle_done = 1
End If
End If
'Error-Bit rücksetzen
Error = 0
Return
'======================================================
'ISR für Timer1 - Fehlerhandling
'======================================================
Rc_error:
'Error-Bit setzen
Error = 1
Reading = 0
Stop Timer1
'Reset erzwingen
Disable Interrupts
Start Watchdog
Waitms 10000
Return
Nachdem ich einige Zeit mit dem Decoder herumgespielt hatte, wurmte mich die Sache mit der nicht funktionierenden ISP Programmierung doch sehr. Es konnte doch nicht sein, dass es mit BASCOM bzw dem USBASP Programmer nicht läuft. Also wurde der Sache nochmal mit etwas Abstand auf den Grund gegangen.
Dabei fiel auf, dass die Belegung des 6pol Steckers für das Flachbandkabel falsch war. Ich hatte im Internet nur nach einem Bild mit einer Belegung gesucht und das Erstbeste genommen. Das dieses Bild aus einem Thread in einem Forum war, in welchem sich der Threadersteller über eine nicht funktionierende Programmierschnittstelle ausließ habe ich nicht völlig übersehen.
Ich Depp!
Naja, man ist ja noch jung und hat viel Zeit...
Nachdem ich die Belegung zum Turnigy USBASP Adapter genommen hatte funktionierte die Programmierung des Chips einwandfrei. Die Programmierung der Fuses konnte ich leider nicht mehr testen, da ich keinen jungfräulichen Atmega8 mehr hatte, wird aber noch getestet sobald ich neue Prozessoren habe.
Ich hatte auch auf die Schnelle ein Layout erstellt. Damit die Verbindungen vom Atmel zu den Treibern kurz sind habe ich im Schaltplan einige Änderungen machen müssen. Das sieht nun nicht mehr so aufgeräumt aus, aber ein einfaches Layout ist mir lieber.
Hier mal die neue Version der Pläne:
Auf dem letzten Bild ist der Decoder auf eine meiner Platinen im 212 aufgebaut. Hier werden (noch) die drei A123 Akkupacks angeschlossen. Der BTS oben links steuert den hier noch nicht aufgebauten Fahrregler des Bugstrahlruders.
Zu einem 16K Decoder gehört auch der passende Encoder. Basierend auf der originalen Graupner Senderplatine habe ich einen Schaltplan und ein Layout erstellt. Natürlich ungetestet und ohne Gewähr.
Demnächst gehts weiter