Forum: Mikrocontroller und Digitale Elektronik xmega: Bit in Ram schreiben [ASM]


von Christian (dragony)


Lesenswert?

Hallo zusammen,

ich habe eine race condition im xmega USB Modul. Im Ram muss ich jetzt 
bei einem EP ein Bit vom Status Byte auf 1 setzen. Das Bit daneben darf 
aber nicht verändert werden. Ich habe es via lds geladen, dann mit andi 
geändert und dann via sts wieder weggespeichert. Leider kommt es alle 
paar Mio Pakete mal vor, dass zufällig das USB Modul das Bit daneben 
ändert, während ich das andi ausführe. Dann überschreibe ich mit dem 
folgenden sts natürlich unwissend das vom USB-Modul geänderte Bit. Der 
USB Stack läuft im ping-pong Modus. Während ich Bank0 bearbeite, wird 
also Bank1 empfangen.

Weiss jemand, wie und ob ich im Ram ein Bit setzen kann, ohne die 
anderen zu beeinflussen?

Im Handbuch habe ich leider nichts gefunden. Da steht nur This flag is 
cleared by writing a one to its location. Bei solchen Sätzen denke ich 
immer an sbi und cbi, aber das geht nunmal nicht im RAM.

von Falk B. (falk)


Lesenswert?

@ Christian S. (dragony)

>ich habe eine race condition im xmega USB Modul. Im Ram muss ich jetzt

Schon mal über das Thema atomare Operationen nachgedacht?

https://www.mikrocontroller.net/articles/Interrupt#Atomarer_Datenzugriff

>Weiss jemand, wie und ob ich im Ram ein Bit setzen kann, ohne die
>anderen zu beeinflussen?

cli
blub
sei

Alternativ kann man speziell beim Xmega die GPIOR0-15 nutzen, dort kann 
man jedes Bit atomar mit einem Befehl sbi/cbi setzen und löschen. Genau 
dafür sind die Dinger nämlich da.

von Christian (dragony)


Lesenswert?

Hallo Falk,

es geht nicht um Interrupts. Die Dinger vermeide ich so gut es geht. Zu 
viel gepushe und gepoppe.

Ich weiss, dass r0-r15 mit sbi/cbi geht, nur was nützt mir das, wenn das 
Byte im RAM liegt? Oder gibt es eine Möglichkeit, eine bestimmte Adresse 
im Ram auf ein GPIOR zu mappen? Wär natürlich richtig cool.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Christian S. (dragony)

>es geht nicht um Interrupts. Die Dinger vermeide ich so gut es geht. Zu
>viel gepushe und gepoppe.

Unsinn. Ausserdem reicht EIN Interrupt aus, um den Effekt zu erzeugen.

>Ich weiss, dass r0-r15 mit sbi/cbi geht, nur was nützt mir das,

Ohren waschen! Ich sprach nicht von den CPU-Register r0-r15, sondern den 
GPIOs! Das sind 16 Register im IO-Bereich, wo beim Xmega KEINERLEI 
Hardware dahinter hängt!

RTFM!

Und den Artikel Interrupt WIRKLICH in RUHE lesen und verstehen. Dann 
klappt es auch mit jeder x-beliebigen Ram-Variable.

von Christian (dragony)


Lesenswert?

Anscheinend kannst du mir intellektuell nicht folgen, wenn ich sage, 
dass ich keine Interrupts einsetze. Das tut mir leid für dich. Aber 
solche Menschen, die direkt mit geistreichen Sprüchen wie "RTFM" und 
"Ohren waschen" um sich werfen, können generell gerne sterben gehen. 
Davon gibts auf der Welt eh genug.

Es ist also weiterhin die unbeantwortete Frage im Raum, ob man beim 
xmega eine Speicheradresse im RAM bitweise verändern kann.
Es geht, um es genau zu sagen, um das STATUS Register im xmega AU 
Handbuch Kapitel 20.15.1. Dieses Byte ist leider nicht isolierbar.
Ich habe jetzt einen funktionierenden workaround, der seit 15 MRd 
Paketen stabil läuft, aber es scheint mir einfach unelegant zu sein. 
Vielleicht gibt es ja eine elegante Möglichkeit, bitweise auf dieses 
eine Byte zuzugreifen. Bei mir liegt das Byte an der Adresse 0x2274, 
also wirklich im SRAM.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Christian S. schrieb:

> Anscheinend kannst du mir intellektuell nicht folgen, wenn ich sage,
> dass ich keine Interrupts einsetze.

Wenn das wirklich so ist, kann nur noch ein Hardwarefehler oder DMA ein 
Bit im RAM umsetzen, während du mit der MCU eine 
ReadModifyWrite-Operation auf das Byte vornimmst, in dem das Bit liegt.

> Es ist also weiterhin die unbeantwortete Frage im Raum, ob man beim
> xmega eine Speicheradresse im RAM bitweise verändern kann.

Natürlich, hast du ja auch gemacht. Allerdings gibt es keine von Haus 
aus atomare Operation dafür und das ist das eigentliche Problem.

> Es geht, um es genau zu sagen, um das STATUS Register im xmega AU
> Handbuch Kapitel 20.15.1.

Das kein SRAM, sondern ein Hardware-Register, welches auf eine 
SRAM-Adresse gemapped ist! Das cli/sei-Pattern nützt hier tatsächlich 
garnichts, um den RMW-Zugriff der MCU darauf atomar zu machen.

Tatsächlich gibt es nur eine 100% sichere Methode, das zu erreichen: die 
USB-Hardware anzuhalten. Das ist allerdings keine Option, wenn man USB 
tatsächlich benutzen will.

> Ich habe jetzt einen funktionierenden workaround

Wenn du die USB-Einheit so nutzen würdest, wie sie von ihren Entwicklern 
gedacht war, dann würde sich überhaupt nie die Notwendigkeit ergeben, zu 
einem Zeitpunkt schreibend auf das Register zuzugreifen, wo auch die 
USB-Hardware es ändert.

Und ja: Die Nutzung der von der USB-Einheit generierten Interrupts ist 
ein wichtiges Mittel, um das zu erreichen. Es bleibt nur noch, dafür zu 
sorgen, daß die variable Interuptlatenz immer klein genug bleibt, so 
dass diese Interrupts immer rechzeitig bearbeitet werden können. Die 
einzuhaltenden Maximalzeiten ergeben sich aus den USB-Specs und der 
Arbeitsweise der USB-Einheit des XMega.

Und nein: Interrupts sind auf einem XMega nicht zwingend eine 
push/pop-Orgie, von allein wird da außer der Rücksprungadresse nämlich 
überhaupt nichts gepusht oder gepopt.

von Christian (dragony)


Lesenswert?

c-hater schrieb:
>> Es geht, um es genau zu sagen, um das STATUS Register im xmega AU
>> Handbuch Kapitel 20.15.1.
>
> Das kein SRAM, sondern ein Hardware-Register, welches auf eine
> SRAM-Adresse gemapped ist!

Woher willst du denn diese Info genommen haben? Ich sehe das so, dass es 
ganz normaler SRAM ist, der vom Hardwaremodul auch so angesprochen wird. 
Der Pointer steht in EPPTR drin. Wenn es ein mapping wäre, könnte ich 
dort ja vorher einen Wert speichern, "mappen", neuen Wert speichern, 
"demappen" und könnte dann den alten Wert wieder lesen, was ich nicht 
glaube. Ausserdem steht in 20.2 "internal SRAM is used".

> Tatsächlich gibt es nur eine 100% sichere Methode, das zu erreichen: die
> USB-Hardware anzuhalten. Das ist allerdings keine Option, wenn man USB
> tatsächlich benutzen will.

hm ok, das ist nun wirklich nicht die ideale Lösung...

> Wenn du die USB-Einheit so nutzen würdest, wie sie von ihren Entwicklern
> gedacht war, dann würde sich überhaupt nie die Notwendigkeit ergeben, zu
> einem Zeitpunkt schreibend auf das Register zuzugreifen, wo auch die
> USB-Hardware es ändert.

Leider schreiben Sie nirgendwo, was sie sich dabei gedacht haben ^^ Der 
Fehler tritt auch nur in Kombination mit Ping-Pong und Multipacket-Modus 
auf. Leider nehmen die nämlich für den Status das gleiche Byte und nicht 
den Flag des Registers des anderen EPs. Vielleicht ist es ja nicht so 
gedacht, beides gleichzeitig zu nutzen.

> Und nein: Interrupts sind auf einem XMega nicht zwingend eine
> push/pop-Orgie, von allein wird da außer der Rücksprungadresse nämlich
> überhaupt nichts gepusht oder gepopt.

Von allein wird (ausser die Rücksprungadresse) auf keinem AVR was 
gepushpopt. Der einzige Unterschied ist, dass der xmega nur 1 Takt für 
ein push braucht, während die anderen 2 brauchen. Ein Paar ist also also 
dem xmega um 33% schneller. Dennoch muss man auch auf dem xmega sreg,r0 
und r1 sichern, wenn man in eine ISR springt, was auf normalem AVRs 
immerhin 12 Takte sind. Deshalb nutze ich ISRs nur, wenn es wirklich 
SEIN muss, z.B. bei Software-UART ohne Flow Control.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Christian S. (dragony)

>>> Es geht, um es genau zu sagen, um das STATUS Register im xmega AU
>>> Handbuch Kapitel 20.15.1.

> Ich sehe das so, dass es
>ganz normaler SRAM ist, der vom Hardwaremodul auch so angesprochen wird.

Hmm, in der Tat. Hier werden eine handvoll "Register" in den SRAM 
gelegt, welche über einen Pointer in einem echten IO-Register vom 
USB-Nodul angesprochen werden können.

>Der Pointer steht in EPPTR drin.

Sieht so aus.

>> Wenn du die USB-Einheit so nutzen würdest, wie sie von ihren Entwicklern
>> gedacht war, dann würde sich überhaupt nie die Notwendigkeit ergeben, zu
>> einem Zeitpunkt schreibend auf das Register zuzugreifen, wo auch die
>> USB-Hardware es ändert.

>Leider schreiben Sie nirgendwo, was sie sich dabei gedacht haben

Das ist wohl der Punkt. Trotzdem muss man es herausfinden.

>den Flag des Registers des anderen EPs. Vielleicht ist es ja nicht so
>gedacht, beides gleichzeitig zu nutzen.

Kann sein.

>immerhin 12 Takte sind. Deshalb nutze ich ISRs nur, wenn es wirklich
>SEIN muss, z.B. bei Software-UART ohne Flow Control.

Ach herje, ein neuer Fetisch. ISR-Phobie und Taktspareritis? Dr. House, 
ein neuer Fall für Sie!

Der Witz bei ISR- ist u.a. dass man damit genau weiß, was gerade 
passiert ist und demzufolge auch auf Register zugreifen kann, von denen 
man GENAU weiß, dass dort in den nächste Mikrosekunden keine Gefahr 
besteht, eine Crash zwischen CPU Zugriff und USB-Hardwarezugriff auf 
eine SRAM-zelle zu zerstören. So läuft das möglicherweise auch beim 
Xmgea mit USB.

von Christian (dragony)


Lesenswert?

Falk Brunner schrieb:
> Ach herje, ein neuer Fetisch. ISR-Phobie und Taktspareritis? Dr. House,
> ein neuer Fall für Sie!

Weisst du, ohne Leute wie UNS, die noch die Takte zählen, um ein 
schnelles Back-End abzuliefern, würden so Leute wie DU gar nicht in der 
Lage sein, ein noch einigermassen brauchbares Produkt abzuliefern. WIR 
sorgen dafür, dass es für DICH genug Takte zum verbrennen gibt, damit du 
vor deinem Chef immernoch als Programmierer durch gehst.

von Georg (Gast)


Lesenswert?

Christian S. schrieb:
> Weisst du, ohne Leute wie UNS

Leute, die zuerst Fragen stellen und dann unverschämt werden, sind hier 
ausserordentlich beliebt. Und mit deinen Angaben zu deinen 
Programmiergrundsätzen hast du dich als weitgehend unqualifiziert 
geoutet - wie sollte man von jemandem profitieren, der panische Angst 
vor Interrupts hat?

Georg

von Bastler (Gast)


Lesenswert?

Wenn Takte zählen hinreichende Fähigkeit wäre, um das GCC-AVR-Backend zu 
überarbeiten, dann wären da sicher Hunderte beteiligt. Leider ist deren 
Anzahl aber überschaubar. (manche Namen habe da noch nie gesehen)
Für ISR/PushPop-Hasser mit Assempholie gibt es übrigens was Tolles 
(ernst gemeint): Parallax Propeller. Keine ISR, kein Stack, kein CALL 
und jede Menge Register, in denen sogar die Maschinenbefehle liegen. 
32bit!! 8 Cores!!
BTW, erst vor kurzen gemessen: ATtiny24, Tastenabfrage per PeDa-Methode 
in ISR alle 20ms keine 10μs bis der Kleine in der Hauptschleife wieder 
schläft. Und keine Sekunde bis der C++ Code (Mcucpp-Lib) zu einem 
Hex-File wurde. Aber damit hätten wir ja gleich mehrere 
Wochenend-Flammenherde ;-)

von Stephan B. (matrixstorm)


Lesenswert?

Hallo

Auf vielen XMegas gibt es Test-and-Set Instruktionen die atomar laufen.
Damit sparst du dir das langsame Interrupt an/aus gefummel:

XCH (S.149 / Exchanges one byte indirect between register and data 
space.)
LAS (S. 81 / Load and Set)
LAC (S. 80 / Load and Clear)
LAT (S. 82 / Load and Toggle)

http://matrixstorm.com/avr/files/doc0856.pdf

MfG

btw.:

Christian S. schrieb:
> Weisst du, ohne Leute wie UNS, die noch die Takte zählen, um ein
> schnelles Back-End abzuliefern, würden so Leute wie DU gar nicht in der
> Lage sein, ein noch einigermassen brauchbares Produkt abzuliefern. WIR
> sorgen dafür, dass es für DICH genug Takte zum verbrennen gibt, damit du
> vor deinem Chef immernoch als Programmierer durch gehst.

FULL ACK (was sich heute alles Programmierer nennen darf, frueher nannte 
man sowas Pfuscher und schlimmeres)

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Christian S. schrieb:
> Anscheinend kannst du mir intellektuell nicht folgen, wenn ich sage,
> dass ich keine Interrupts einsetze.

Uns was haben atomare Operationen wie LAT, LAS oder LAC mit Interupts zu 
tun?  Diese Instruktionen können im ganzen Code verwendet werden.

von Stephan B. (matrixstorm)


Lesenswert?

Johann L. schrieb:
> Uns was haben atomare Operationen wie LAT, LAS oder LAC mit Interupts zu
> tun?  Diese Instruktionen können im ganzen Code verwendet werden.

Man kann damit Semaphoren erzeugen, ohne cli nutzen zu muessen.
Damit blockiert man nicht unnoetig Interrupts.

Also statt quasi
1
//...
2
in r0, SREG
3
cli
4
ldd r16, Z
5
std Z, r1 //zero reg
6
out SREG, r0
7
//...

einfach
1
//...
2
lac Z, r16
3
//...


Das ist kuerzer, schneller und Interrupts sind auch verfuegbarer (sollte 
man welche benutzen)...

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Atomare Instruktionen sind dort sinnvoll oder unabdingbar, wo atomare 
Operationen notwendig sing.  Interrupts sind ein Anwendungsfeld, aber 
lediglich eines wo man meist auch ohne atomare Instruktonen auskommen 
könnte.

Bei Parallelität in Hardware -- etwa bei Multicore -- oder bei Core + 
I/O wie hier kommt man aber schlecht ohne aus.  Um ohne atomare 
Instruktionen Atomarität zu erreichen müsste man alle parallel laufende 
Hardware anhalten, z.b. USB-Modul oder andere Cores...

Christian S. schrieb:
> Weisst du, ohne Leute wie UNS, die noch die Takte zählen,

Dazu solltest du aber schon den Instruktionssatz deines µC kennen ... um 
als Programmierer durchzugehen ;-)

: Bearbeitet durch User
von Marcus O. (marcus6100)


Lesenswert?

Christian S. schrieb:
> bei einem EP ein Bit vom Status Byte auf 1 setzen. Das Bit daneben darf
> aber nicht verändert werden. Ich habe es via lds geladen, dann mit andi
> geändert und dann via sts wieder weggespeichert.

Mir ist unklar warum du andi benutzt um ein bit auf 1 zu setzen.

Mit dem xmega kenne ich mich nicht aus, aber du kannst das atomare 
setzen eines bits im speicher im prinzip so realisieren:

again:
lds R1, mem
mov R2, R1
ori R2, 0x01
ldi R30, addr
ldi R31, addr
xch R2, Z
cmp R1,R2
jne again

von Christian (dragony)


Lesenswert?

Stephan B. schrieb:
> Hallo
>
> Auf vielen XMegas gibt es Test-and-Set Instruktionen die atomar laufen.
> Damit sparst du dir das langsame Interrupt an/aus gefummel:
>
> XCH (S.149 / Exchanges one byte indirect between register and data
> space.)
> LAS (S. 81 / Load and Set)
> LAC (S. 80 / Load and Clear)
> LAT (S. 82 / Load and Toggle)
>
> http://matrixstorm.com/avr/files/doc0856.pdf

VIELEN DANK!!!!! Vor allem der Link. Ich habe hier eine Befehlsreferenz 
von Atmel, die vom Layout her ziemlich alt aussieht. Die Befehle dort 
waren sogar nicht richtig dokumentiert. In deinem Link ist die Doku 
vollständig und es ist GENAU WAS ICH GESUCHT HABE :)

Problem gelöst. Danke!

von spess53 (Gast)


Lesenswert?


von Stephan B. (matrixstorm)


Lesenswert?

spess53 schrieb:
> Warum nicht die originale Quelle
>
> http://www.atmel.com/Images/Atmel-0856-AVR-Instruction-Set-Manual.pdf
>
> benutzen?

Kann man natuerlich auch - die hatte ich aber nicht zur Hand als ich den 
Beitrag schrieb.
Und von meinem tinyUSBboard Projekt war der Link schneller beschafft:

http://matrixstorm.com/avr/tinyusbboard/datasheets.html

MfG Stephan

von spess53 (Gast)


Lesenswert?

Hi

>Und von meinem tinyUSBboard Projekt war der Link schneller beschafft:

>http://matrixstorm.com/avr/tinyusbboard/datasheets.html

Hautsache du hältst den Link auch immer aktuell.

MfG Spess

von Stephan B. (matrixstorm)


Lesenswert?

spess53 schrieb:
> Hautsache du hältst den Link auch immer aktuell.

Ich geb' mir Muehe.

MfG

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.