Forum: Mikrocontroller und Digitale Elektronik Mega88: Mehrere Interupts? (NOP funktioniert nicht)


von Silver69 (Gast)


Lesenswert?

Hallo!

Frohes Neues an alle ;-)

Nachdem der UART nun läuft wollt ich (eigentlich noch vor dem essen :P) 
den Timer0 zum laufen bringen.

Hier mein Code:
1
.include "m88def.inc"
2
 
3
.org 0x0000
4
        rjmp main
5
 
6
.org URXCaddr                     ; Interruptvektor für UART-Empfang
7
        rjmp int_rxc
8
 
9
.org OVF0addr
10
       rjmp timer0_overflow       ; Timer Overflow Handler
11
12
 
13
; Hauptprogramm
14
 
15
main:
16
      nop
17
      nop
18
int_rxc:
19
reti
20
timer0_overflow:
21
reti



Die Fehlermeldung, beim compilieren lautet:

D:\Eigene Dateien\Mega88\Mega88ROMTest.asm(33): error: Overlap in .cseg: 
addr=0x12 conflicts with 0x12:0x13

Diese tritt übrigens beim zweiten NOP Befehl auf

Was mache ich nun schon wieder falsch?

von Marius W. (mw1987)


Lesenswert?

So wird das ja auch nix.

Das ist kein lauffähiges Programm.

Füge mal nach dem zweiten nop nen rjmp main ein.

MfG
Marius

von Michael U. (amiga)


Lesenswert?

Hallo,

einmal siehe Marius Wensing (mw1987), ist aber nicht die Ursache für die 
Fehlermeldung.

Geh doch den Ablauf für den Assembler einfach mal "zu Fuß" durch:

.org 0x0000 -> assembliere an Adresse 0x0000
       rjmp main

.org URXCaddr -> assembliere ab Adresse 0x0012 ***
  rjmp int_rxc

.org OVF0addr -> asssembliere ab Adresse 0x0010
  rjmp timer0_overflow

-> der Assembler ist jetzt bei Adresse 0x0012 ***

ab hier soll er jetzt aber Deine main übersetzen, kann er aber nicht, 
weil Du ihm schon gesagt hast, daß dort der rjmp int_rxc hinsoll...

Siehe Vectorliste im Datenblatt.

Entweder die Vektoren in der Reihenfolge ihres Auftretens zuweisen, also
die Reihenfolge von

.org URXCaddr -> assembliere ab Adresse 0x0012 ***
  rjmp int_rxc
und
.org OVF0addr -> asssembliere ab Adresse 0x0010
  rjmp timer0_overflow

vertauschen oder
alle Vektoren in ihrer Reihenfolge eintragen

oder aber per .org vor der main festlegen, wo der Assembler weitermachen 
soll. Geht am Besten mit

.org INT_VECTORS_SIZE

vor main.

Ist in den AVR-includes definert auf die Länge der Vector-Liste.

Gruß aus Berlin
Michael

von spess53 (Gast)


Lesenswert?

Hi

>So wird das ja auch nix.
>Das ist kein lauffähiges Programm.

Quatsch. Das interessiert des Assembler herzlich wenig.

>.org URXCaddr                     ; Interruptvektor für UART-Empfang
>        rjmp int_rxc

>.org OVF0addr
>       rjmp timer0_overflow       ; Timer Overflow Handler

Du kannst die .org nichr beliebig mischen

.org OVF0addr
       rjmp timer0_overflow       ; Timer Overflow Handler

.org URXCaddr                     ; Interruptvektor für UART-Empfang
        rjmp int_rxc

OVF0addr ist kleiner als org URXCaddr. Damit platzierst du dein Main 
zwischen den beiden Adressen und dein Code überschneidet sich mit 'rjmp 
int_rxc'

Die Reihenfolge muss den Interruptvektoren entsprechen.

MfG Spess

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

spess53 wrote:
> Die Reihenfolge muss den Interruptvektoren entsprechen.
>
> MfG Spess
um dich mal zu zitieren:
> Quatsch. Das interessiert des Assembler herzlich wenig.
;)

Das einzige was man tun muß ist den Einsteigspunkt für die Main an die 
richtige stelle setzen nämlich INT_VECTORS_SIZE...

1
.org 0x0
2
        rjmp main
3
 
4
.org URXCaddr                     ; Interruptvektor für UART-Empfang
5
        rjmp int_rxc
6
 
7
.org OVF0addr
8
       rjmp timer0_overflow       ; Timer Overflow Handler
9
10
 
11
; Hauptprogramm
12
.org INT_VECTORS_SIZE
13
main:
14
rjmp main
15
int_rxc:
16
reti
17
timer0_overflow:
18
reti
Man kann die Vektoren dann belibig anordnen...

von spess53 (Gast)


Lesenswert?

Hi

> MfG Spess
um dich mal zu zitieren:
> Quatsch. Das interessiert des Assembler herzlich wenig.

Dann sieh dir mal an, worauf sich das bezogen hat.

Ich weiss nicht, wer dieses .org-Gedödel erfunden hat (wahrscheinlich 
der Gleiche mit den 'tempxy'). Die Datenblattvariante wäre weniger 
irreführend gewesen.

MfG Spess

von Michael U. (amiga)


Lesenswert?

Hallo,

@spess53: ich finde das .org-Gedödel durchaus praktisch, auch die 
tempxy, allerdings heißen die bei mir TEMP_0 usw. ;-)
Warum soll ich x IRQ-Vectoren reinschreiben, wenn ich nur einen brauche?
Ja, man kann die kopieren, aber ich finde es lesbarer, wenn eben dann 
nur einer oder zwei dastehen.

Und seit Atmel netterweise INT_VECTORS_SIZE in den includes hat, erspart 
es selbst bei Änderungen auf eine andere CPU dann dort unnötige 
Korrekturen.

Gruß aus Berlin
Michael

von spess53 (Gast)


Lesenswert?

Hi

>Warum soll ich x IRQ-Vectoren reinschreiben, wenn ich nur einen brauche?

Muss ich nicht. Ich kann mein Programmgerüst aus den XML-Dateien des 
AVR-Studios erzeugen.

> auch die tempxy, allerdings heißen die bei mir TEMP_0 usw. ;-)

Registerdefinitionen sind vielleicht bei kleinen Programmen hilfreich. 
Bei grösseren empfinde ich sie als störend. Wenn ein Register in einem 
Programm zig verschiedene Inhalte haben kann, muss ich entweder dauernd 
umdefinieren oder mit irrführenden Bezeichnungen leben. Beides ist für 
mich inakzeptabel.

MfG Spess

von Peter D. (peda)


Lesenswert?

Läubi Mail@laeubi.de wrote:

> Das einzige was man tun muß ist den Einsteigspunkt für die Main an die
> richtige stelle setzen nämlich INT_VECTORS_SIZE...

> Man kann die Vektoren dann beliebig anordnen...

Es geht sogar noch einfacher und übersichtlicher.
Man muß nicht umständlich alle Vektoren in ein File eintragen, sondern 
kann das auch erst direkt dort machen, wo man den Interrupthandler 
definiert.
Das geht am besten mit einem kleinen Macro:
1
.nolist
2
.include "m88def.inc"
3
.listmac
4
.list
5
6
.macro  INTHAND
7
        .set    _curr_addr = pc
8
        .org    @0
9
        rjmp    _curr_addr
10
        .org    _curr_addr
11
.endmacro
12
13
14
.org    0x0000
15
        rjmp main
16
.org    INT_VECTORS_SIZE
17
main:
18
;...
19
        rjmp    main
20
;...
21
        INTHAND URXCaddr
22
; handler code
23
        reti
24
;...
25
        INTHAND OVF0addr
26
; handler code
27
        reti

Das spart dann auch das Ausdenken eines Labels für den Handler.


Peter

von spes53 (Gast)


Lesenswert?

Hi

Langsam dämmert es mir. Man muss also Assembler nur so unverständlich 
wie möglich zu machen, um den Einsatz sog. Hochsprachen zu 
rechtfertigen. Interessante Strategie.

MfG Spess

von Sinusgeek (Gast)


Lesenswert?

Xundes Neues...

> Man muss also Assembler nur so unverständlich
> wie möglich zu machen, um den Einsatz sog. Hochsprachen zu
> rechtfertigen.

Hmmm... Da scheint was dran zu sein.

Das ist dann für mich ein Grund mehr, bei einfachem verständlichem 
überschaubarem Hobbybastler-ASM zu bleiben und wie bisher die komplette 
Interrupt-Vektorliste zu kopieren.

~

von Peter D. (peda)


Lesenswert?

spes53 wrote:
> Langsam dämmert es mir. Man muss also Assembler nur so unverständlich
> wie möglich zu machen, um den Einsatz sog. Hochsprachen zu
> rechtfertigen. Interessante Strategie.

Ich vermute mal, Du bist ein Einzelkämpfer und hast daher weder die 
Notwendigkeit noch das Interesse, Deine Programme für andere besser 
lesbar und verstehbar zu machen.

Defines und Macros helfen aber nicht nur anderen, sondern auch einem 
selber, ältere Programme wieder schnell verstehen zu können.

Du hast natürlich recht, daß diese Hilfen ihren Ursprung in Hochsprachen 
haben.
Aber warum soll man denn nicht auch nützliche Dinge bei der 
Assemblerprogrammierung verwenden?

Assembler muß nicht automatisch spartsanisch und unübersichtlich sein.

Insbesondere, da ja neuere AVRs einige IO-Register im SRAM haben, ist 
ein Zugriffsmacro sinnvoll, welches automatisch IN/OUT bzw. LDS/STS 
benutzt.


Peter

von Hmm... (Gast)


Lesenswert?

@Peter:

Interessanter Ansatz. Einfach (wenn man den Preprozessor verstanden hat 
;) ) und effektiv. Das Makro dürfte vor allem wenn man für ein neues 
Feature in der Anwendung plötzlich doch noch ein paar Interrupts mehr 
benutzen möchte praktisch sein.

Danke für den Tip!


Für den Anfang bzw. zum lernen dürfte allerdings der Datenblatt-Ansatz 
günstiger sein, da man hier den Aufbau der Interrupt-Vektortabelle 
ständig vor Augen hat und sich nicht mit vom verwendeten Assembler 
abhängigen Konstrukten beschäftigen muss.
1
.org 0x00
2
    rjmp RESET        ; Reset Handler
3
    rjmp INT0         ; External Interrupt0 Handler
4
    rjmp INT1         ; External Interrupt1 Handler
5
    rjmp TIM1_CAPT    ; Timer1 Capture Handler
6
    rjmp TIM1_COMPA   ; Timer1 CompareA Handler
7
    rjmp TIM1_OVF     ; Timer1 Overflow Handler
8
    rjmp TIM0_OVF     ; Timer0 Overflow Handler
9
    rjmp USART0_RXC   ; USART0 RX Complete Handler
10
    rjmp USART0_DRE   ; USART0,UDR Empty Handler
11
    rjmp USART0_TXC   ; USART0 TX Complete Handler
12
    rjmp ANA_COMP     ; Analog Comparator Handler
13
    rjmp PCINT        ; Pin Change Interrupt
14
    rjmp TIMER1_COMPB ; Timer1 Compare B Handler
15
    rjmp TIMER0_COMPA ; Timer0 Compare A Handler
16
    rjmp TIMER0_COMPB ; Timer0 Compare B Handler
17
    rjmp USI_START    ; USI Start Handler
18
    rjmp USI_OVERFLOW ; USI Overflow Handler
19
    rjmp EE_READY     ; EEPROM Ready Handler
20
    rjmp WDT_OVERFLOW ; Watchdog Overflow Handler
21
22
main:
23
..
24
25
  rjmp main

von Silver69 (Gast)


Lesenswert?

Hallo!

Also es tut mir leid dass ich mich nicht für die Makro-Variante sondern 
für die einfache, die Adressen nach der Vektortabelle zu sortieren, 
entschieden habe... vielleicht später mal mit Makro ;-)

Eigentlich wollte ich jetzt nach so einer Interrupt-Vektortabelle 
fragen, ich habe die zwar irgendwo schon einmal gesehen, wusste aber 
nicht mehr wo. Nun, da ihr ja aber entweder Gedanken lesen könnt oder in 
die Zukunft sehen, habt ihr die Tabelle ja schon geposted bevor ich die 
Frage stellen konnte :-)

Der Timer läuft nun, Interrupt wird ausgelöst, trotzdem noch eine Frage:

Ich habe am Mega88 ein Quarzoszillator angeschlossen, 1.8 GHZ für RS232.
Der Timer0 läuft ohne Prescale. In der Interrupt Routine zähle ich dann 
noch ein Register hoch. Wenn dieses kleiner als 128 ist, schalte ich die 
LED an , andernfalls aus.

So etwa:
1
...
2
          ldi     r16, 0b00000001      ; Timer enable - Kein Prescale
3
          sts     TCCR0B, r16
4
5
          ldi     r16, 0b00000001      ; TOIE0: Interrupt bei Timer Overflow
6
          sts     TIMSK0, r16
7
 
8
          sei
9
10
11
...
12
13
14
timer0_overflow:
15
      lds r17, PWM
16
17
      lds R16, LED1
18
      cp r16, r17
19
20
      BRLO Led1AUS
21
      sbi PORTC,0    ;LED1 AN
22
      rjmp LED2Test
23
LED1AUS:  cbi PortC,0   ;LED1 AUS
24
25
26
LED2Test:
27
28
      inc R17
29
      sts PWM, R17
30
    
31
32
reti
33
34
...


OK, die "..." bedeuten, dass da noch mehr Code steht :-)
Das ich auch die Register R16 und R17 nicht sichere, ist mir auch 
bewusst (mach ich jetzt gleich).


Zur Frage:
Die LED sollte doch jetzt so schnell blinken, dass ich es mit dem Auge 
nicht sehen kann, oder? Aber aus irgendeinem Grund ist die Frequenz so 
niedrig, dass ich sie flackern sehe? Wieso?

von Silver69 (Gast)


Lesenswert?

out     TCCR0B, r16

nicht

STS     TCCR0B, r16

muss es heißen ;-)

von Silver69 (Gast)


Lesenswert?

Meine letztes Posting könnte zur Verwirrung sorgen:

"out     TCCR0B, r16

nicht

STS     TCCR0B, r16

muss es heißen ;-)"

Bezieht sich auf einen COPY/Paste Fehler, der mir passiert ist, als ich 
den Code oben eingefügt habe. Soll aber NICHT heißen, dass das Problem 
"flackern" mit dieser Änderung gelöst ist....

von holger (Gast)


Lesenswert?

>Aber aus irgendeinem Grund ist die Frequenz so
>niedrig, dass ich sie flackern sehe? Wieso?

CKDIV8 Fuse auf 1 gesetzt?

von Gast (Gast)


Angehängte Dateien:

Lesenswert?

>Die LED sollte doch jetzt so schnell blinken, dass ich es mit dem Auge
>nicht sehen kann, oder?

Was für ein Ergebnis spuckt denn Deine Berechnung der Blinkfrequenz aus?

Ich komme auf 1843200 Hz : 256 : 256 = 28.125 Hz.

Eine mit dieser Frequenz bestromte LED wird nicht mehr als blinkend, 
sondern als dauerleuchtend, aber mit deutlichem Flimmern empfunden.

>Aber aus irgendeinem Grund ist die Frequenz so
>niedrig, dass ich sie flackern sehe? Wieso?

Wenn sich Deine LED eher schnell blinkend präsentiert, dann ist 
höchstwahrscheinlich die CKDIV8-Fuse enabled. Dann läuft Dein Controller 
nur mit 1843200/8 Hz und die LED mit ca. 3.5 Hz.

Hast Du eine Digitalkamera? Dann kannst Du die Frequenz leicht messen. 
Dazu darfst Du keinen Automatik-Modus verwenden, sondern musst die 
Verschlusszeit von Hand z. B. auf 1 Sekunde festsetzen. Dann die Kamera 
gleichmäßig während das Bild aufgenommen wird in größerem Abstand über 
die blinkende LED hinwegziehen. Sozusagen eine Luftaufnahme machen, mit 
Deinen Händen als "Flugzeug". Ergibt ein Bild wie im Anhang. Hier war 
die Verschlusszeit 1 s, und um die Blinkfrequenz der untersten LED zu 
bestimmen, musst Du nur die gelben Streifchen zählen. Sie hat mit 20 Hz 
geblinkt.

von Simon K. (simon) Benutzerseite


Lesenswert?

Silver69 wrote:
> Ich habe am Mega88 ein Quarzoszillator angeschlossen, 1.8 GHZ für RS232.

1,8GHz Quarzoszillator?

von Silver69 (Gast)


Lesenswert?

Hallo!

Das mit der Kamara ist eine gute Idee... das werde ich mal testen.
CKDIV8-Fuse ist nicht gesetzt. Wenn ich es setze, blinken die LEDs 
wirklich...

Zur Frequenzberechnung:

Ich dachte es wäre: 1843200 Hz : 256 : 2 =3600 HZ ?
Mit meinem Zähler (PWM = R17) teile ich doch nicht mehr durch 256 
sondern lediglich durch 2, oder?

Oder habe ich da einen Denkfehler drin?

von Silver69 (Gast)


Lesenswert?

Ist natürlich Quatsch... du hast Recht!
War ein Denkfehler von mir.
Ich muss den Zähler dann ja nur bis zb 128 zählen lassen, dann 
verdoppelt sich die Frequenz.

56 Hz müsste man dann nicht mehr blinken sehen können, denke ich mal...

von Gast (Gast)


Lesenswert?

>56 Hz müsste man dann nicht mehr blinken sehen können

Nein, bei 40 Hz flirrt es noch ein ganz kleines bisschen, aber oberhalb 
ca. 50 Hz wirst Du das Leuchten als flimmerfrei wahrnehmen.

Die Kameramethode ist übrigens bis ca. 1 kHz praktikabel. Wenns mehr 
sein soll, braucht man dann doch einen Frequenzzähler ;-)

von Peter D. (peda)


Lesenswert?

Silver69 wrote:
> Also es tut mir leid dass ich mich nicht für die Makro-Variante sondern
> für die einfache, die Adressen nach der Vektortabelle zu sortieren,
> entschieden habe... vielleicht später mal mit Makro ;-)

Braucht Dir nicht leid zu tun, es gibt ja viele Wege, etwas zu tun.
Man sollte bloß nicht wie manch anderer sagen: "Alles was ich nicht 
benutzte, ist Mist", sondern auch mal andere Meinungen zulassen.

Der Grund, warum ich Macros bevorzuge, ist auch, daß ich viele 
verschiedene AVRs benutze und dann sind die Vektortabellen 
unterschiedlich.

Wenn Dir z.B. der Flash ausgeht und Du schnell mal auf den ATmega168 
upgraden willst, zeigt Deine Vektortabelle in den Wald.
Die .ORG-Anweisungen stimmen dagegen immer noch.


Peter

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.