Pfad:
home =>
avr DE =>
how-to => Konversion Quellcode
(This page in English:
)
Quellcode von einem auf einen anderen AVR-Typ konvertieren
Diese Seite gibt ein paar Hinweise dafür, was zu beachten
ist, wenn man Quellcode von einem AVR-Typ in einen anderen
Zielprozessor konvertieren will.
Die folgenden Fälle sind zu unterscheiden:
- Wenn Du mit Assembler voll vertraut bist, solltest
Du den Arbeitsaufwand abwägen, den Du mit der Konversion
gegenüber dem Neuschreiben haben wirst. Besonders bei
schlecht oder gar nicht dokumentierten Quellcode kann das
Neudesign einfacher sein als den fremden Code zu durchschauen.
- Wenn Du ein wenig mit Assembler vertraut bist, versuche
es. Sei nicht enttäuscht wenn das Ergebnis nicht so arg
zufriedenstellend funktioniert. Beachte auf jeden Fall die
nachfolgenden Hinweise zu Inkompatibilitäten.
- Wenn Du gar kein Assembler kannst, dann breche Dein
Vorhaben gleich ab und lerne zuerst die Basics von Assembler
und des Hardware-Designs. Du holst Dir nur Frust, wenn Du es
trotzdem versuchst. Es wird Dich zahllose schlaflose Nächte
kosten und irgendwann gibst Du es ohnehin auf, weil Du es
nicht zum Laufen bringst.
1 Devicetypen mit unterschiedlichen Suffixen
Wenn sich der ursprüngliche Prozessortyp und der Zieltyp
nur durch unterschiedliche Suffixe unterscheiden (z. B.
beim ATtiny13 und ATtiny13A, dann bist Du fein raus. Ersetze
bloss in der Include-Zeile "tn13def.inc" durch
"tn13Adef.inc" und assembliere neu. Die meisten
Programme dürften sich dabei gar nicht im Hexcode
unterscheiden.
Sicherheitshalber solltest Du dann noch
- die ATMEL homepage
nach den Begriffen "migration [alter AVR-Typ]"
durchsuchen, dort findest Du entsprechende Hinweise, was
in Spezialfällen noch zu beachten sein könnte.
- sicherstellen, dass sich die Länge und Reihenfolge
der Interruptvektoren nicht verändert haben (siehe
in den entsprechenden Device-Handbüchern in der
Abteilung "Interrupts" und unter
Interruptvektoren).
2 Devicetypen mit differierenden Nummern
Wenn sich die Devicenummern unterscheiden ist zuerst zu
prüfen, ob sie zur gleichen Familie gehören.
Beispiele für solche Familien sind ATtiny4-5-9-10,
ATtiny24-44-84, ATtiny1614-1616-1617, ATmega48-88-168
oder ATmega169-329-649-3290-6490.
In solche Fällen ist es einfacher, von kleineren
zu größeren Nummern zu wechseln. Dann muss
kaum etwas geändert werden. Hat der Zieltyp mehr
als 256 Byte SRAM, muss der MSB des Stapelzeigers
zusätzlich zum LSB initiiert werden (Begriff
SPL im Quellcode suchen und SPH hinzufügen.
Selbiges gilt, wenn der Zieltyp mehr als 256 Bytes
EEPROM hat und EEPROM genutzt wird. Dann muss bei
Zeilen, die EEARL enthalten, noch eine Zeile für
das Setzen von EEARH hinzugefügt werden.
Im umgekehrten Fall, von einem größeren zu
einem kleineren Typ, ist der Umfang an genutztem SRAM-
und EEPROM-Platz zu überprüfen. Dazu sucht
man die entsprechenden Segmente .dseg und .eseg ab
und stellt darüber sicher, dass es überhaupt
gehen kann. Wenn die Original-Software mehr Raum nutzt
als im Zieltyp vorhanden ist, ist die Aufgabe schon
beendet: gescheitert.
Eventuell sind dann die Zeiger SPH und EEADRH auf den
kleineren Typ anzupassen. Hat der Original-Programmierer
statt Portnamen fixe Portadressen verwendet: wirf den
Quellcode in den Mülleimer, Du machst Dich nur
unglücklich mit der ganzen Sucherei und
Übersetzerei.
Sind die beiden AVR-Typen aus unterschiedlichen Familien,
ist eine etwas tiefergehende Analyse des Quellcodes
erforderlich. Dann sind Basisinformationen
und Hardware-Informationen
nötig. Wenn das alles erfolgreich verlief, sind
noch die Interruptvektoren
anzupassen.
Suche alle Zeilen, die die Begriffe "OUT",
"IN", "CBI" und "SBI"
enthalten und sammle alle Ports zusammen, die dort
verwendet werden. Diese Zeilen - und diejenigen, die
einem OUT vorausgehen - sollte man in einer Liste mit
genutzten Hardwarekomponenten zusammenstellen und
nach Komponenten ordnen. Für alle identifizierten
Komponenten sollten die eingestellten Modi klar sein,
z. B. für
- Ports und Portbits: Richtung und IN/OUT-Stellungen,
alle alternativen Verwendungen wie z. B. als
PWM-Ausgang,
- Timer: Nummer, 8/16-Bit, Betriebsmodi,
Prescalerwerte, beeinflusste Portpins,
- ADC: Eingangsquellen Portpins/Interne Sensoren,
unipolare und differenziale Messmodi, Left-Adjust,
etc.
- UARTS: Portpins, Baudraten, Modi, etc.
- ...
Mit der Liste kann man prüfen, ob das Target-Device
das alles genauso kann wie das Original-Device. Wenn
nicht: mache Deinen eigenen Quellcode und lasse das
Konvertieren.
Lineare Programme (ohne Interrupts) nutzen fast immer
Verzögerungsroutinen. In interruptgesteuerten
Programmen kontrollieren Timer und/oder andere interne
Komponenten den Programmablauf. In beiden Fällen
ist die Taktfrequenz entscheidend.
Es muss daher festgestellt werden, mit welcher Taktfrequenz
das Originalsystem läuft und ob man das Zielsystem
auf gleichen Takt bringen kann.
Die Defaultwerte der Taktfrequenz gibt es in den Device
Databooks mit Suchen nach "default clock".
Im Quellcode sollten weitere Hinweise zum Takt enthalten
(nach "Takt" und "clock" suchen).
Finden sich die Worte "fuse" im Quellcode,
könnte das ein Hinweis auf geänderte Taktraten
durch Hardwarekonfiguration sein. Wenn "CLKDIV8"
erwähnt wird, ebenfalls.
Die Durchsuchung nach "out CLKPR" ergäbe
Hinweise darauf, dass der Taktvorteiler verwendet wird.
Dann die Teilerrate feststellen.
Kann das Target-Device auf die gleiche Taktfrequenz
gebracht werden, ist dieser Punkt schon mal erledigt.
Wenn nicht, z. B. weil
- die Orinalsoftware den Taktvorteiler nutzt, es den
im Ziel-Device aber gar nicht gibt,
- kein externer Taktgenerator angeschlossen werden
kann, der diesselbe Frequenz bereitstellt (Device
hat keinen Takteingang oder eine zu krumme
Taktfrequenz),
- ...
dann gib die Konvertiererei besser auf.
Ist das Programm linear (keine Interrupts) kann man noch
versuchen, die Verzögerungsschleifen an die
geänderte Taktfrequenz anzupassen. Je nach
Programmierstil des Original-Quellcodes kann das einfach
oder eine Heidenarbeit sein. Werden dabei auch noch
8-/16-Bit-Grenzen überschritten liegt eher der
zweitgenannte Fall vor.
Benutzt das Programm Timer, dann kann bei Umbauten das
8-/16-Bit-Grenzproblem ebenfalls virulent werden und
zum Neudesign zwingen.
Verwendet das Programm Interruptvektoren (nach .cseg
suchen), ist bei fast jeder Konversion eine Umstellung
der Vektor-Tabelle nötig.
Zunächst sind dazu alle verwendeten Vektoren zu
identifizieren. Dann kopiert man sich aus dem Device
Databook die Interruptvektor-Tabelle des Ziel-Device,
z. B. hier für den ATtiny48:
1 0x000 RESET External/Power-on/Brown-out/Watchdog Reset
2 0x001 INT0 External Interrupt Request 0
3 0x002 INT1 External Interrupt Request 1
4 0x003 PCINT0 Pin Change Interrupt Request 0
5 0x004 PCINT1 Pin Change Interrupt Request 1
6 0x005 PCINT2 Pin Change Interrupt Request 2
7 0x006 PCINT3 Pin Change Interrupt Request 3
8 0x007 WDT Watchdog Time-out Interrupt
9 0x008 TIMER1_CAPT Timer/Counter1 Capture Event
10 0x009 TIMER1_COMPA Timer/Counter1 Compare Match A
11 0x00A TIMER1_COMPB Timer/Counter1 Compare Match B
12 0x00B TIMER1_OVF Timer/Counter1 Overflow
13 0x00C TIMER0_COMPA Timer/Counter0 Compare Match A
14 0x00D TIMER0_COMPB Timer/Counter0 Compare Match B
15 0x00E TIMER0_OVF Timer/Counter0 Overflow
16 0x00F SPI_STC SPI Serial Transfer Complete
17 0x010 ADC ADC Conversion Complete
18 0x011 EE_RDY EEPROM Ready
19 0x012 ANA_COMP Analog Comparator
20 0x013 TWI 2-wire Serial Interface
Die Nummern und Adressen zu Beginn der Zeilen sollte
man löschen. Dann sortiert man die verwendeten
Interruptvektoren in diese Tabelle an die korrekte
Position, fügt ein RJMP Label (bei Zielsystemen
mit viel Flash und wenn die Vektoradressen um zwei
ansteigen: ein JMP Label) davor. Alle ungenutzten
Vektoren kriegen ein RETI davor (bei großen
Flashes gefolgt von einem NOP).
Der erste Vektor sollte mit RJMP (bzw. JMP) zur
Init-Routine führen.
Abschließend: viel Glück bei der
Lösung der Konversionsaufgabe.
An den Seitenanfang, zur Leitseite
©2017 by http://www.avr-asm-tutorial.net