Forum: Mikrocontroller und Digitale Elektronik ATmega16: Problem mit serieller schnittstelle


von Bernhard Mayer (Gast)


Lesenswert?

Hallo!

Hab mit meinem ATmega16 ein Problem mit der seriellen schnittstelle.
Und zwar hab ich ein Programm vom AT90S4433 auf den mega angepasst nur
läufts jetzt nicht. d.h. sobald der mega was über die serielle
schnittstelle empfängt und ein entsprechender interrupt ausgelöst wird
macht er nen neustart.
allerdings hab ich auch noch festgestellt, dass die gleichen routinen
und einstellungen funktionieren, wenn das programm ein bisschen kürzer
ist.

Was kann das jetzt sein? ist doch irgendwas an den einstellungen
falsch? ist das Flash vom mega kaputt und es wird nicht richtig
beschrieben? Hab es aber bis jetzt nur etwa 30 mal beschrieben. oder
liegts vielleicht an irgendwelchen fuse bits?

Danke
Bernhard

von Michael (Gast)


Lesenswert?

>>Und zwar hab ich ein Programm vom AT90S4433 auf den mega angepasst
>>nur läufts jetzt nicht.

Das ist normal. Du mußt die geänderten Interrupt-Vektoren beachten und
anpassen (richtige Include-Dateien) und nochmals genau kontrollieren.

von Bernhard Mayer (Gast)


Lesenswert?

das hab ich schon gemacht. wie gesagt, ein kleines testprogramm mit den
selben interrupt-vektoren, include-datei und port-initialisierung läuft
ja.

von Michi (Gast)


Lesenswert?

Na dann poste mal Dein Programm.

von Bernhard Mayer (Gast)


Lesenswert?

werd ich heute abend gleich machen

von leo (Gast)


Lesenswert?

Hallo Bernhard,

dein Problem liegt zu 99% an den Interruptvektoren:

Vektor - adress (z.B.Mega8) - address (Mega16)
1 - 0x0000 - 0x0000
2 - 0x0001 - 0x0002
3 - 0x0002 - 0x0004
4 - 0x0003 - 0x0006 usw.

d.h. beim Mega16 (und vermutlich allen größeren avrs) geht z.B. TX
complete auf address 0x001A, bei den kleinen (z.B. Mega8) auf 0x000D,
obwohl TX complete in beiden Fällen der Vektor No. 14 ist.

Grüße leo

von Bernhard Mayer (Gast)


Lesenswert?

Hallo Leo!

Das kann durchaus sein!
Wie macht man dann am vernünftigsten für nen Mega16 die
Interrupt-Vektor-Sprung-Tabelle. Ich habs bisher so:

.org 0x00
rjmp anfang    ; Reset
reti           ; Int0
reti           ; Int1
usw.

und so hauts ja anscheinend ned hin.
also was ist besser?

Danke
Bernhard

von Michael (Gast)


Lesenswert?

>>Du mußt die geänderten Interrupt-Vektoren beachten und
>>anpassen (richtige Include-Dateien) und nochmals genau
>>kontrollieren.

Mach es doch einfach einmal ! (Datenblatt)

von Thomas Burkhardt (Gast)


Lesenswert?

Hi


.org 0x00
rjmp anfang    ; Reset
reti           ; Int0
reti

Genau das ist das Problem. Das RETI ist ein Wort breit, der Abstand der
Interruptvektoren ist aber zwei Worte, da dort gegebenenfalls ein CALL
stehen muss, welches zwei Worte breit ist.

So ist die ganze Interruptvektorentabelle Murks.

von Bernhard Mayer (Gast)


Lesenswert?

dann ist mir das auch klar. aber wie schreibt man dann jetzt die
Interruptvektorentabelle auch formal richtig, dass da alles drin ist?

von Bernhard Mayer (Gast)


Lesenswert?

Danke an alle, jetz funktionierts so wie es soll!

Ich hab die Tabelle jetz so gemacht:
  *** Sprungtabelle ***
.org 0x00
  rjmp anfang    ; RESET
.org 0x02
  reti      ; INT0
.org 0x04
  reti      ; INT1
.org 0x06
  reti      ; TIMER2 COMP
usw.

is zwar jetz ein bisschen unübersichtlich aber hauptsache es geht. oder
hat jemand nen besseren vorschlag?

Bernhard

von dave (Gast)


Lesenswert?

Das kommt ganz einfach daher, dass man mit nem RJMP nicht mehr in den
ganzen Speicher kommt, folglich muss in den Vektor ein JMP reinpassen.
Wie wärs mit
RETI + NOP
oder einfach die Definitionen ausser Include nehmen?
.org URXC0addr
 rjmp irgendwohin

(aus der m161def.inc)
.equ  INT0addr  =$002  ;External  Interrupt0 Vector Address
.equ  INT1addr  =$004  ;External Interrupt1 Vector Address
.equ  INT2addr  =$006  ;External Interrupt1 Vector Address
.equ  CMP2addr  =$008  ;Input Capture1 Interrupt Vector Address
.equ  OVF2addr  =$00a  ;Overflow1 Interrupt Vector Address
.equ  ICP1addr  =$00c  ;Input Capture1 Interrupt Vector Address
.equ  OC1Aaddr  =$00e  ;Output Compare1A Interrupt Vector Address
.equ  OC1Baddr  =$010  ;Output Compare1B Interrupt Vector Address
.equ  OVF1addr  =$012  ;Overflow1 Interrupt Vector Address
.equ  CMP0addr  =$014  ;Overflow1 Interrupt Vector Address
.equ  OVF0addr  =$016  ;Overflow0 Interrupt Vector Address
.equ  SPIaddr    =$018  ;SPI Interrupt Vector Address
.equ  URXC0addr  =$01a  ;UART Receive Complete Interrupt Vector Address
.equ  URXC1addr  =$01c  ;UART Receive Complete Interrupt Vector Address
.equ  UDRE0addr  =$01e  ;UART Data Register Empty Interrupt Vector
Address
.equ  UDRE1addr  =$020  ;UART Data Register Empty Interrupt Vector
Address
.equ  UTXC0addr  =$022  ;UART Transmit Complete Interrupt Vector Address
.equ  UTXC1addr  =$024  ;UART Transmit Complete Interrupt Vector Address
.equ  EERDYaddr  =$026  ;UART Transmit Complete Interrupt Vector Address
.equ  ACIaddr    =$028  ;Analog Comparator Interrupt Vector Address

von Dirk (Gast)


Lesenswert?

Hi,

schau mal ins AVR Tutorial unter Interrupts befindet sich die Mega8
Tabelle. Ich nutze diese und passe Sie nachdem Datenblatt an.

Dirk

von Bernhard Mayer (Gast)


Lesenswert?

@dave:
Danke! Hab leider die Include nicht, da ich gavrasm benutze. aber so
schauts ganz gut aus. wie hat man das dann früher gemacht? da gabs ja
auch schon avr mit großem speicher und da is ja dann auch nicht mit
rjmp gegangen oder?

@Dirk:
die vom mega8 passt ja nicht und da is ja dann überhaupt erst mit den
problemen angegangen.

mfg
Bernhard

von leo (Gast)


Lesenswert?

Hallo Bernhard,

im Prinzip hast du ja bereits eine Lösung. Ich füge halt für jedes
"Sicherheits-reti" ein nop dazu: (hat auch den Vorteil dass
undefinierte Int-Ansprünge (0x01,0x03,0x05 usw) einen definierten
Programablauf haben. Wobei dieser Vorteil möglicherweise nur
theoretischer Natur ist; ich habe keine Ahnung ob solche Sprünge in der
Praxis durch irgendetwas ausgelöst werden. Und wenns nichts nutzt
schaden tuts auf keinen Fall ;-)

.org 0x00
  rjmp reset.org 0x02
  reti      ; nicht benötigt
  nop
  reti      ; auch unbenutzt
  nop
  rjmp int_prg      ; INT1
  reti      ; und wieder unbenutzt
  nop       ; usw.

grüße leo

von dave (Gast)


Lesenswert?

.org 0x00
  rjmp reset   ; 0
.org 0x02
  reti      ; 2
  nop       ; 3
  reti      ; 4
  nop       ; 5
  rjmp int_prg      ; 6
  reti      ; 7
  nop       ; 8

Bei der Methode würde ich aufpassen... hier wäre z.B. schon ein Vektor
etwas verrutscht (wers nich sieht: nach der 6 fehlt ein NOP, denn 7
müsste ja auf die 8).

von leo (Gast)


Lesenswert?

@dave:

hast war, rjmps ( 1 word Speicherbedarf) durch calls ( 2 word breit)
ersetzen und es passt oder halt besser aufpassen, in assembler sollte
man sowieso immer wissen was man tut ;-)

grüße leo9

von thkais (Gast)


Lesenswert?

@leo: In der Tat, bei Assembler sollte man wissen, was man tut ;)

Mit nem call anstelle rjmp krachts garantiert. Die richtige Lösung gabs
doch oben schon.

von Thomas Burkhardt (Gast)


Lesenswert?

Hi thkais,

stimmt natürlich. Da sollte nicht CALL stehen, sondern JMP (muss
geträumt haben). Wichtig bleibt, dass der der Abstand zwei Worte ist,
weil ein RJMP nicht den ganzen Speicher erreicht.

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.