Forum: Mikrocontroller und Digitale Elektronik Asssembleprogramm für Mega16 auf Mega8535 anpassen, Sprungweite "call" und "jmp"


von Christian S. (roehrenvorheizer)


Angehängte Dateien:

Lesenswert?

Hallo,


ich habe kürzlich diesen Akkulader (für 4 Zellen, Strom- u 
Spannungsanzeige, umfangreiche Einstellmöglichkeiten mit geregelter und
vorbestimmbarer Stomabgabe, RS232-Anschluß) mit ATMega16 nachgebaut und 
mich an dessen Funktion erfreut.

http://www.avr-asm-tutorial.net/akkuload/de/

Die originalen Programm-Dateien findet man hier:
http://www.avr-asm-tutorial.net/akkuload/de/akkuload.zip

Beim Assemblieren fiel mir auf, daß die Programm-Datei noch in einen 
ATMega8535 passen müßte. Deshalb kam ich auf die Idee, den Quelltext mal 
eben so für den ATMega8535 anzupassen. Die Fehlermeldungen beim 
assemblieren rührten alle von den verwendeten Befehlen call und jmp her, 
die der ATMega8535 nicht kennt. Die Sprungweiten sind größer als 2 K 
-Worte, so daß es keine direkte Lösung gibt.Als Lösung erschien mir die 
Möglichkeit sinnvoll, die Sprünge auf jeweils zwei kürzere Sprünge für 
jeden einzelnen Aufruf umzuschreiben.

Nun erhalte ich ein fehlerfrei assembliertes Programm, das aber kurz 
nach der ersten Ausgabe aufs LCD und aufs UART stehen bleibt und keine 
Befehle vom Terminal annnimmt. Also klemmt wieder irgendein Sprung oder 
Unterprogramm-Aufruf. Hat jemand eine Idee, wie man das richtig macht?

In den Anhang habe ich mal die von mir geänderten Dateien hochgeladen.

mit freundlichem Gruß

_________

Alle Labels geändert, die einen call-Befehl hatten. Sie bekamen ein Tr 
vor den Namen. call nach rcall geändert.

Jmp-Befehl zum Sprung auf Programmanfang auch geändert, allerdings in 
Sprung zu main über die Treppe. rjmp Trmain.


;Binde die selbstgemachte Treppe für Sprünge > 2K-Worte ein
;
TrEpRead:
  rcall EpRead
  ret


TrEpWrite:
  rcall EpWrite
  ret

TrEpStore:
  rcall EpStore
  ret

TrClearCap:
  rcall ClearCap
  ret

TrIdSetPar:
  rcall IdSetPar
  ret

TrUartInit:
  rcall UartInit
  ret

TrUartSendOpenText:
  rcall UartSendOpenText
  ret


TrUartSendCursor:
  rcall UartSendCursor
  ret


Trmain:
  rjmp main


TrUartRxLine:
  rjmp UartRxLine

von spess53 (Gast)


Lesenswert?

Hi

>Hat jemand eine Idee, wie man das richtig macht?

Deine NOPs nach den rjmp/reti in der Interruptvektortabelle am 
Programmanfang sind falsch und müssen raus.

MfG Spess

von Christian S. (roehrenvorheizer)


Angehängte Dateien:

Lesenswert?

Hallo,

danke für die Hilfe!!!

Ja, also das Programm läuft nun tatsächlich ohne diese nops im m8535.

Und die Interrupttabelle habe ich zwar betrachtet, aber natürlich mir 
nichts dabei gedacht oder auch nicht oben drüber die Schrift gelesen:

; Reset- und Interrupt-Vektoren
; (Vektoren beim ATmega16 sind Doppelworte!)

Mal wieder eine Unachtsamkeit. Analyse: Ich habe noch nie mit dem Mega16 
zu tun gehabt und deshalb auch nichts von dessen doppelt breiten 
Interruptvektoren gewußt.


Vielen Dank fürs Drüber schauen!

....es läuft und läuft...


Im Anhang die korrigierte Datei, falls es jemand nachbauen will.

mit freundlichem Gruß

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Christian S. schrieb:
> Analyse: Ich habe noch nie mit dem Mega16
> zu tun gehabt und deshalb auch nichts von dessen doppelt breiten
> Interruptvektoren gewußt.
Wenn man die vordefinierten Adressen nutzt kann man sich den ganzen 
quatsch mit nops etc. übrigens wunderbar sparen...

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,


hmm, welche meinst Du genau? Welche gibt es da vordefiniert? Die 
Interrupttabelle aus dem Datasheet des 8535?

Stehen die irgendwo geschrieben?

Das Programm war im Bauvorschlag bereis fertig angeboten. Da habe ich 
mir weiter keine Gedanken gemacht, irgendwelche Bestandteile zu ändern.


mfG

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Schau mal in die m8535def.inc da sollten Namen für alle Interuptvektoren 
drin stehen mit den Daten aus dem Datenblatt.

von spess53 (Gast)


Lesenswert?

Hi

>Wenn man die vordefinierten Adressen nutzt kann man sich den ganzen
>quatsch mit nops etc. übrigens wunderbar sparen...

NOPs braucht man eh nicht, wenn man die passenden Sprungbefehle nutzt.

Mir ist eine vollst. Interruptvektortabelle wesentlich sympatischer als 
dieses .org-Gedödel.

MfG Spess

von Christian S. (roehrenvorheizer)


Lesenswert?

Hallo,

ja, klar, diese inc-Dateien sind generell sehr aufschlußreich, wenn es 
um die Existenz oder die genauen Namen der verschiedenen Register geht.

Ganz am Ende der Datei erkennt man, daß beim m8535 alle 
Interruptvektoren auf geraden und ungeraden Adressen liegen, während 
beim Mega 16 die Interruptvektoren NUR auf geraden Adressen liegen.

Auszug aus m8535def.inc:
; ***** INTERRUPT VECTORS 
************************************************
.equ  INT0addr  = 0x0001  ; External Interrupt 0
.equ  INT1addr  = 0x0002  ; External Interrupt 1
.equ  OC2addr  = 0x0003  ; Timer/Counter2 Compare Match
.equ  OVF2addr  = 0x0004  ; Timer/Counter2 Overflow
.equ  ICP1addr  = 0x0005  ; Timer/Counter1 Capture Event
.equ  OC1Aaddr  = 0x0006  ; Timer/Counter1 Compare Match A
.equ  OC1Baddr  = 0x0007  ; Timer/Counter1 Compare Match B
.equ  OVF1addr  = 0x0008  ; Timer/Counter1 Overflow
.equ  OVF0addr  = 0x0009  ; Timer/Counter0 Overflow
.equ  SPIaddr  = 0x000a  ; SPI Serial Transfer Complete
.equ  URXCaddr  = 0x000b  ; USART, RX Complete
.equ  UDREaddr  = 0x000c  ; USART Data Register Empty
.equ  UTXCaddr  = 0x000d  ; USART, TX Complete
.equ  ADCCaddr  = 0x000e  ; ADC Conversion Complete
.equ  ERDYaddr  = 0x000f  ; EEPROM Ready
.equ  ACIaddr  = 0x0010  ; Analog Comparator
.equ  TWIaddr  = 0x0011  ; Two-wire Serial Interface
.equ  INT2addr  = 0x0012  ; External Interrupt Request 2
.equ  OC0addr  = 0x0013  ; TimerCounter0 Compare Match
.equ  SPMRaddr  = 0x0014  ; Store Program Memory Read

Auszug aus m16def.inc:
; ***** INTERRUPT VECTORS 
************************************************
.equ  INT0addr  = 0x0002  ; External Interrupt Request 0
.equ  INT1addr  = 0x0004  ; External Interrupt Request 1
.equ  OC2addr  = 0x0006  ; Timer/Counter2 Compare Match
.equ  OVF2addr  = 0x0008  ; Timer/Counter2 Overflow
.equ  ICP1addr  = 0x000a  ; Timer/Counter1 Capture Event
.equ  OC1Aaddr  = 0x000c  ; Timer/Counter1 Compare Match A
.equ  OC1Baddr  = 0x000e  ; Timer/Counter1 Compare Match B
.equ  OVF1addr  = 0x0010  ; Timer/Counter1 Overflow
.equ  OVF0addr  = 0x0012  ; Timer/Counter0 Overflow
.equ  SPIaddr  = 0x0014  ; Serial Transfer Complete
.equ  URXCaddr  = 0x0016  ; USART, Rx Complete
.equ  UDREaddr  = 0x0018  ; USART Data Register Empty
.equ  UTXCaddr  = 0x001a  ; USART, Tx Complete
.equ  ADCCaddr  = 0x001c  ; ADC Conversion Complete
.equ  ERDYaddr  = 0x001e  ; EEPROM Ready
.equ  ACIaddr  = 0x0020  ; Analog Comparator
.equ  TWIaddr  = 0x0022  ; 2-wire Serial Interface
.equ  INT2addr  = 0x0024  ; External Interrupt Request 2
.equ  OC0addr  = 0x0026  ; Timer/Counter0 Compare Match
.equ  SPMRaddr  = 0x0028  ; Store Program Memory Ready



mfG

von Peter D. (peda)


Lesenswert?

Christian S. schrieb:
> Die Sprungweiten sind größer als 2 K
> -Worte, so daß es keine direkte Lösung gibt.

Doch, er springt einfach rückwärts.
Dazu mußt Du nur das M8535-Include einbinden.
Es ist also jede Adresse durch rjmp/rcall erreichbar und deshalb gibt es 
kein jmp/call.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

spess53 schrieb:
> Mir ist eine vollst. Interruptvektortabelle wesentlich
> sympatischer als dieses .org-Gedödel.
Das mag ja sein, trotzdem ist das weder lesbar noch gut wartbar, wie man 
in diesem Beispiel sieht. Und wie oft braucht man denn wirklich alle 
Interrupts?

von Peter D. (peda)


Lesenswert?

Hier mal ein Grundgerüst für AVR-Assembler Programme:
1
.include "m8535def.inc"
2
;
3
.macro  INTERRUPT
4
        .set    current_pc = PC
5
        .org    @0                      ; vector address
6
        .if FLASHEND > 0x0fff
7
                jmp     current_pc
8
        .else
9
                rjmp    current_pc      ; jump to handler
10
        .endif
11
        .org    current_pc              ; restore PC
12
.endmacro
13
;---------------------------------------------------------------
14
        rjmp    init
15
.org    INT_VECTORS_SIZE                ; behind vector table
16
init:
17
        nop                             ; insert init stuff here
18
main:
19
        nop                             ; insert main stuff here
20
        rjmp    main
21
;---------------------------------------------------------------
22
        INTERRUPT OVF0addr
23
        nop                             ; insert handler here
24
        reti
25
;---------------------------------------------------------------
26
        INTERRUPT INT0addr
27
        nop                             ; insert handler here
28
        reti
29
;---------------------------------------------------------------

von gerd (Gast)


Lesenswert?

Hallo.

Für meine Lösung, RJMPs und NOPs zu verwenden, spricht, dass JMP drei, 
RJMP aber nur zwei Takte braucht. Also warum Takte verschwenden, wenn es 
nur "unschön" aussieht, was auch immer für ein Schönheitsbegriff da 
dahinter stecken mag.

Das mit dem Gerödel mit ORG-Orgien teile ich, das ist ziemlich krank und 
nur scheinbar unproblematisch. Beim Umstellen auf einen anderen Chip ist 
das Allererste sich zu versichern, dass alle nötige Hardware drin ist 
und die Interrupts exakt so funktionieren wie im alten Chip. Aufgrund 
der langen Entwicklungsgeschichte haben die Vektoren alles andere als 
eine systematische Struktur und Reihenfolge.

mfg
gerd

von Christian S. (roehrenvorheizer)


Angehängte Dateien:

Lesenswert?

Hallo,

nochmals habe ich mich mit dieser Portierung des Programms befasst, um 
die "perfekte" Lösung nun zu haben:         (...es läuft und läuft...)

was war zu tun:

-in akkuload.asm und in akkuuart.asm alle jmp Befehle in rjmp umbenannt 
und alle call-Befehle in rcall umbenannt.

-in akkuload.asm alle nop-Befehle aus der Interrupttabelle 
auskommentiert

-in akkuload.asm die include-Datei geändert: .INCLUDE "m8535def.inc"

Das macht mit Übung ca 20 Minuten Aufwand, wenn man weiß was zu tun ist.

Anbei die beiden Dateien, die geändert wurden, falls es irgendwann mal 
jemand nachbauen möchte.

Vielen Dank für die hilfreichen Zuschriften. Das Grundgerüst probiere 
ich bei Gelegenheit mal aus.

mit freundlichem Gruß


AVRASM: AVR macro assembler 2.1.42 (build 1796 Sep 15 2009 10:48:36)
ATmega8535 memory use summary [bytes]:
Segment   Begin    End      Code   Data   Used    Size   Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x001e86   5402   2412   7814    8192  95.4%
[.dseg] 0x000060 0x000060      0      0      0     512   0.0%
[.eseg] 0x000000 0x0000c0      0    192    192     512  37.5%
Assembly complete, 0 errors. 0 warnings

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.