ATMega4809 externer Interrupt

Gast #7400661
Lesenswert?

Hallo,

ich versuche mich gerade im Simulator an einem ATMega4809, da ich plane, den Arduino Nano Every für ein Projekt zu verwenden.

Mit den ATMega-Controllern bin ich ganz gut vertraut, aber beim 4809er schaffe ich es nicht, den externen Interrupt korrekt zu programmieren.

; --- main.asm ---

1
#define Value    R16
2
#define Status    R17
3
#define HighByte  R18
4
#define LowByte    R19
5

6
.cseg
7
.org 0x0000 rjmp reset
8
.org 0x000C rjmp setPointAcquisition_Triggered
9

10
reset:
11
  ldi    HighByte, HIGH(RAMEND)
12
  out    CPU_SPH, HighByte
13
  ldi    LowByte, LOW(RAMEND)
14
  out    CPU_SPL, LowByte
15

16
  rcall  setPointAcquisition_Initialize
17

18
  sei
19

20
main:
21
  jmp    main
22

23
.include "m4809def.inc"
24
.include "setPointAcquisition.asm"

; --- setPointAcquisition.asm ---

1
.include "m4809def.inc"
2

3
.equ SetPointInputPort    = PORTA_PIN0CTRL
4
.equ SetPointInputPin    = 0x1
5

6
setPointAcquisition_Initialize:
7
  lds    Value, SetPointInputPort
8
  sbr    Value, SetPointInputPin
9
  sts    SetPointInputPort, Value
10

11
  ret
12

13
setPointAcquisition_Triggered:
14
  push  Value
15
  lds    Status, CPU_SREG_offset
16

17
  sts    CPU_SREG_offset, Status
18
  pop    Value
19

20
  reti

Ich möchte PortA0 als externen Interrupt programmieren, um einen Sollwert zu erfassen (PWM Signal). Wenn ich im Simulator das entsprechende Pin0 auf HIGH setze, springt der Programmzähler korrekt in die ISR hinein und der Controller arbeitet diese ab. Nach dem der Programmzähler die ISR verlassen hat, springt er sofort wieder hinein - obwohl ich nur auf die Flanken triggere.

Gibt es bei diesem Controller irgendwelche Besonderheiten, was den externen Interrupt betrifft?

MfG Torsten

Gast #7400668
Lesenswert?

Hallo,

das habe ich schon versucht, ohne Erolg:

1
setPointAcquisition_Triggered:
2
  push  Value
3
  lds    Status, CPU_SREG_offset
4

5
  lds    Value, PORTA_INTFLAGS
6
  cbr    Value, 0x01
7
  sts    PORTA_INTFLAGS, Value
8

9
  sts    CPU_SREG_offset, Status
10
  pop    Value
11

12
  reti

MfG Torsten

#7400817
Lesenswert?

Hallo,

habe das mal übersetzt in direkte Register... das funktioniert mit echten Every Board. Kabelbrücke zwischen PB0 und PD3, dann takten beide Ausgänge syncron mit "both edges". Solltest du in Assembler übersetzen können. :-)

1
#include <avr/interrupt.h>
2
#include <util/delay.h>
3

4
// PB0 - Arduino Pin  9
5
// PE2 - Arduino Pin 13
6
// PD3 - Arduino Pin 14
7

8
#define F_CPU 3333333UL
9

10
int main (void)
11
{
12
  VPORTB.DIR     &= PIN0_bm;             // Input
13
  PORTB_PIN0CTRL = 0;    // 
14
  PORTB_PIN0CTRL |= PORT_PULLUPEN_bm;    // 
15
  PORTB_PIN0CTRL |= 0x01;                // Interrupt enabled with sense on both edges
16
  VPORTE.INTFLAGS = PIN0_bm;             // delete Interrupt Flag
17
  VPORTE.DIR     |= PIN2_bm;             // Led 13
18
  VPORTD.DIR     |= PIN3_bm;             // Takt 14
19
  sei();
20
  
21
  while(1)
22
  { 
23
    VPORTD.IN = PIN3_bm;                // toggle Taktpin 14
24
    _delay_ms (100);
25
  }
26
}
27

28
ISR (PORTB_PORT_vect)
29
{
30
  VPORTE.IN       = PIN2_bm;   // toggle Led 13
31
  VPORTB.INTFLAGS = PIN0_bm;   // delete Flag
32
}
#7400840
Lesenswert?

Torsten N. schrieb:

Lässt sich der Nano Every mit AVR Studio direkt flashen?

Nein, du kannst aber mit AVR Dude arbeiten, dass funktioniert, ist aber nicht komfortabel. Alternativ, die UPDI Schnittstelle auf dem Board anlöten/kontaktieren und den Mega4809 direkt ansprechen.

1
@echo off
2
setlocal
3

4

5
c:\windows\system32\mode.com com22: baud=1200 dtr=on
6
c:\windows\system32\mode.com com22: dtr=off
7

8
avrdude -C "C:\Users\Admin\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -patmega4809 -cjtag2updi -PCOM22 -b115200 -e -D -Uflash:w:C:\Users\Admin\Desktop\3V1_PSR.hex:i -Ufuse0:w:0x00:m -Ufuse1:w:0xC4:m -Ufuse2:w:0x02:m -Ufuse5:w:0xC9:m -Ufuse6:w:0x07:m -Ufuse7:w:0x00:m -Ufuse8:w:0x00:m {upload.extra_files} 
9

10
PAUSE

AVR Dude installieren und der Path-Variable zufügen, schauen an welchem COM-Port sich der Every anmeldet und dann noch den Pfad zum Hex-File anpassen. Fuses nach bedarf, in diesem Code wird der interne OSC von 16MHz auf 20MHz geschraubt. Achtung, der COM-Port muss 3x geändert werden, ich habe mich noch nicht damit beschäftigt, eine Art #define dafür zu machen.

#7401035
Lesenswert?

das habe ich schon versucht, ohne Erolg ... 'cbr ...'

Wie wäre es mit 'ori Value, 0x01'? Denn: 'Pin interrupt flag n is cleared by writing a ‘1’ to it'.

Korrektur: 'andi Value, ~0x01' ist wohl besser; oder, wenn es dieses (aus meiner Sicht unglückliche) 'cbr' sein muss: 'cbr Value, ~0x01'.

#7401079
Lesenswert?

Veit D. schrieb:

Hallo,

@ Torsten, Ingo Wenn die Kommandozeile für einen passt, kann man diese oder mehrere in AS/MS eintragen. Beitrag "Re: UPDI Programmer bauen - alias "El Tangas"" Vorher kompilieren, logisch. :-) :-)

Die neuere, bessere Variante heißt: pymcuprog

https://pypi.org/project/pymcuprog

Wie vorher braucht man für UPDI auch nur einen USB/seriell-Umsetzer (z.B. CP2102) und eine Diode oder Widerstand.

#7401088
Lesenswert?

Veit D. schrieb:

Wilhelm M. schrieb:

Veit D. schrieb:

VPORTE.INTFLAGS = PIN0_bm

Besser bei PORTB.

Veit D. schrieb:

VPORTE.IN = PIN2_bm; // toggle Led 13

Das geht zwar so ist aber Obsfucation. Dafür gibt es OUTTGL.

Kann man machen, VPORTx ist jedoch einen Takt schneller.

Dann nimmt der C-Programmierer eben:

1
#define VPORTE_OUTTGL VPORTE_IN

(und der C++-Programmierer macht es sich beliebig hübsch - und sicher!)

#7401122
Lesenswert?

Korrektur der Korrektur: Die Zeile in der ISR: entweder 'andi Value, 0x01' oder eben 'cbr Value, ~0x01'.

Was mir sonst auffiel:

  • statt '.org 0x000C' hätte ich '.org PORTA_PORT_vect' geschrieben
  • das Setzen des Stackpointers ist unnötig: 'Reset: Top of stack'
  • die Zuordnung von HighByte und LowByte entspricht nicht dem AVR-Üblichen, passt evtl. später nicht bei z.B. 'movw'.
#7401136
Lesenswert?

S. L. schrieb:

Es reicht ein: sts PORTA_INFLAGS, 0x01

?

Ja sorry, dazu ist der AVR zu doof.

Also statt

lds Value, PORTA_INTFLAGS cbr Value, 0x01 sts PORTA_INTFLAGS, Value

einfach

ldi Value,0x01 out PORTA_INTFLAGS,Value

Die Sequenz des ganz oben lädt alle Flags, löscht dann das 0-te und schreibt zurück. Damit werden alle gesetzten Flags resettet außer dem eigentlich gewünschten.

#7401140
Lesenswert?

Nee, 'out' stimmt auch nicht.

1
 ldi Value,0x01
2
 sts PORTA_INFLAGS,Value

Würde auch das Sichern von SREG ersparen.

Oder vielleicht möchte Torsten etwas Schreibarbeit vermeiden mit:

1
 puti PORTA_INFLAGS,0x01
2

3
.macro put
4
.if @0 < $40
5
 out  @0,@1
6
.else
7
 sts  @0,@1
8
.endif
9
.endmacro
10

11
.macro puti
12
 ldi  tmp0,@1
13
 put @0,tmp0
14
.endmacro
#7401151
Lesenswert?

Hallo,

wegen Interrupt Flag zurücksetzen. Nichts von Hand irgendwie manipulieren. Einfach an die gewünschte Bitposition sturr "1" reinschreiben. Mehr muss nicht beachtet oder gemacht werden.

1
Bits 7:0 – INT[7:0] Pin Interrupt Flag
2
Pin interrupt flag n is cleared by writing a ‘1’ to it.
3
Pin interrupt flag n is set when the change or state of pin n (Pxn) matches the pin's Input/Sense Configuration (ISC)
4
in PORTx.PINnCTRL.
5
Writing a ‘0’ to bit n in this bit field has no effect.
6
Writing a ‘1’ to bit n in this bit field will clear Pin interrupt flag n.
#7401156
Lesenswert?

Wilhelm M. schrieb:

Veit D. schrieb:

Hallo,

@ Torsten, Ingo Wenn die Kommandozeile für einen passt, kann man diese oder mehrere in AS/MS eintragen. Beitrag "Re: UPDI Programmer bauen - alias "El Tangas"" Vorher kompilieren, logisch. :-) :-)

Die neuere, bessere Variante heißt: pymcuprog

https://pypi.org/project/pymcuprog

Wie vorher braucht man für UPDI auch nur einen USB/seriell-Umsetzer (z.B. CP2102) und eine Diode oder Widerstand.

Alles richtig. Es ging mir zu zeigen das man in AS einen eigenen Menüeintrag erstellen kann um die Kommandozeile zu hinterlegen. Für fertige Arduino xyz Boards wird nur ein USB Kabel benötigt. Beim Every ist der UPDI Übersetzer auf dem Board. Wie bei den MC Curiosity Boards.

#7401157
Lesenswert?

Veit D. schrieb:

Hallo,

wegen Interrupt Flag zurücksetzen. Nichts von Hand irgendwie manipulieren. Einfach an die gewünschte Bitposition sturr "1" reinschreiben. Mehr muss nicht beachtet oder gemacht werden.

1
> Bits 7:0 – INT[7:0] Pin Interrupt Flag
2
> Pin interrupt flag n is cleared by writing a ‘1’ to it.
3
> Pin interrupt flag n is set when the change or state of pin n (Pxn) 
4
> matches the pin's Input/Sense Configuration (ISC)
5
> in PORTx.PINnCTRL.
6
> Writing a ‘0’ to bit n in this bit field has no effect.
7
> Writing a ‘1’ to bit n in this bit field will clear Pin interrupt flag 
8
> n.
9
>

Willkommen im Club, oder "Man lernt nur durch Wiederholung". Steht alles schon oben. Die Frage ist, ob der TO das auch liest.

Gast #7401218
Lesenswert?

S. L. schrieb:

das habe ich schon versucht, ohne Erolg ... 'cbr ...'

Wie wäre es mit 'ori Value, 0x01'? Denn: 'Pin interrupt flag n is cleared by writing a ‘1’ to it'.

Korrektur: 'andi Value, ~0x01' ist wohl besser; oder, wenn es dieses (aus meiner Sicht unglückliche) 'cbr' sein muss: 'cbr Value, ~0x01'.

Hallo,

also wer lesen kann, ist klar im Vorteil. Man bin ich blöd, ich habe eine '0' reingeschrieben.

Vielen Dank euch allen für eure Hilfe.

MfG Torsten

#7401226
Lesenswert?

Torsten N. schrieb:

S. L. schrieb:

das habe ich schon versucht, ohne Erolg ... 'cbr ...'

Wie wäre es mit 'ori Value, 0x01'? Denn: 'Pin interrupt flag n is cleared by writing a ‘1’ to it'.

Korrektur: 'andi Value, ~0x01' ist wohl besser; oder, wenn es dieses (aus meiner Sicht unglückliche) 'cbr' sein muss: 'cbr Value, ~0x01'.

Hallo,

also wer lesen kann, ist klar im Vorteil. Man bin ich blöd, ich habe eine '0' reingeschrieben.

Nicht nur das ... s.a.mein Beitrag oben.

#7401236
Lesenswert?

Ja, war leider nicht ganz korrekt, weil damit evtl. weitere Flags gelöscht werden; korrekt ist das direkte, einfache Setzen des Bits im Register (also ohne vorheriges Lesen), wie von Wilhelm M. vorgestellt.

Nochmal zum 'cbr' (wie auch 'sbr'): das ist kein richtiger Befehl, sondern genaugenommen ein Artefakt des Assemblers - erkennbar im 'AVR® Instruction Set Manual', denn dort wird hierfür kein Maschinencode gezeigt. Und stiftet nur Verwirrung, falls man sich an 'sbi' oder 'cbi' orientiert.

#7401335
Lesenswert?

Hi

Nochmal zum 'cbr' (wie auch 'sbr'): das ist kein richtiger Befehl, sondern genaugenommen ein Artefakt des Assemblers - erkennbar im 'AVR® Instruction Set Manual', denn dort wird hierfür kein >Maschinencode gezeigt.

Wieso kein Maschinencode. Bei mir steht da 16-bit Opcode: 1001 1000 AAAA Abbb

mit 0 ≤ A ≤ 31, 0 ≤ b ≤ 7

Ist für mich ein eindeutiger Code.

MfG Spess

#7401551
Lesenswert?

an Spess53:

Da haben Sie sich wohl vertan, Ihre Angaben kann ich nicht nachvollziehen. 'cbr' ist ein im Argument modifiziertes 'andi', aus dem Listfile:

1
000000 7a0a        cbr  r16,~0xAA
2
000001 7a0a        andi r16,0xAA

Der Maschinencode fehlt für 'cbr' im 'AVR® Instruction Set Manual', siehe Anhang.

'sbr' ist identisch zu 'ori', bringt folglich, nach meiner Meinung, keinerlei Mehrwert.

Angehängte Dateien:
#7402298
Lesenswert?

an Uwe K.:

Finden Sie nicht auch, nach näherer Betrachtung, dass Ihr Beitrag zum Thema etwas dürftig ausgefallen ist? Und da gleich zu Beginn offensichtlich war, dass es hier um Assembler geht, frage ich mich, weshalb Sie sich bis hier unten, durch dreißig Beiträge, "gequält" haben.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren