Pfad: home => avr DE => how-to => Konversion Quellcode    (This page in English: Flag EN) Logo

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:
  1. 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.
  2. 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.
  3. 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

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.

2.1 Basisinformationen sammeln

2.1.1 Alle verwendete Hardware zusammenstellen

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 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.

2.1.2 Taktfrequenzen prüfen

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 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.

2.3 Ändern der Interruptvektor-Tabelle

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