Atxmega 16bit register lesen/schreiben

Gast #6010649
Lesenswert?

Kenne mich mit ATmega gut aus, versuche gerade ein Atxmega mal unter 
Assembler auszuprobieren.
Port´s usw. habe ich erfolgreich hinter mich gebracht.
Bin gerade am erfolgreichen testen vom ADC und habe festgestellt, das im 
Datenblatt zwar von einem "ADCA_CH0_RESL" und "ADCA_CH0_RESH" als ADC 
Kanal0 Endergebnis - Register die Rede ist. Aber es gibt ja nur ein 
"ADCA_CH0_RES" Register, welches als 16Bit Register fungiert.
Bei einem ATmega hat man immer Werte über 8Bit so eingeladen:
ldi r16, Registername_LOWBYTE
ldi r17, Registername_HIGHBYTE

Im Datenblatt habe ich jetzt gefunden, das bei den 16Bit Register der 
HIGH Wert in ein Register "ADC_TEMP" zwischengespeichert bzw. abgelegt 
wird. Deshalb habe ich es nun so gelöst:
ldi r16, ADCA_CH0_RES
ldi r17, ADCA_TEMP
Das funktioniert auch, jedoch wollte ich hier mal nachfragen, ob das so 
überhaupt richtig gelöst ist, oder ob das Auslesen des ADC-16Bit 
Registers "ADCA_CH0_RES" eigentlich ganz anders, halt professioneller 
gemacht wird? Ist halt für einen alten ATmega Programmierer etwas 
ungewohnt...
Danke
Gast #6010685
Lesenswert?

Tom schrieb:

> Ahh JA, macht der Gewohnheit....
>
> Natürlich beim ATxmega mit LDS! und nicht mit LDI!

Auch bei den Classic-AVRs wäre "ldi" in jedem Fall falsch gewesen. 
Entweder "lds" oder "in", je nachdem ob das Register memory mapped ist 
oder über den IO-Space erreichbar.

Du kannst Assembler nicht wirklich, stimmt's?
Beitrag #6010693 wurde von einem Moderator gelöscht.
Gast #6010724
Lesenswert?

> Aber es gibt ja nur ein "ADCA_CH0_RES" Register

Und welche Adresse sollte dieses haben? Wenn ich mir, als alt gewordener 
ATmega-Programmierer, ein ATxmega-Datenblatt anschaue, finde ich dort 
nur z.B. 'CH0RESL' und 'CH0RESH' mit um 1 verschiedenen Adressen. Also 
ganz naiv hätte ich gesagt, das läuft wie bei den ATmega.
Gast #6010732
Lesenswert?

S. Landolt schrieb:

> Und welche Adresse sollte dieses haben? Wenn ich mir, als alt gewordener
> ATmega-Programmierer, ein ATxmega-Datenblatt anschaue, finde ich dort
> nur z.B. 'CH0RESL' und 'CH0RESH' mit um 1 verschiedenen Adressen. Also
> ganz naiv hätte ich gesagt, das läuft wie bei den ATmega.

Und ganz genau so ist das auch.
Gast #6010768
Lesenswert?

Okay, merkwürdig - bei dem 'def.inc'-File, dass ich mir eben mal 
heruntergeladen habe, steht wirklich nur

.equ ADCA_CH0RES = 528    // Channel 0 Result

nichts mit RESL bzw. RESH. Keine Ahnung, was der Grund hierfür ist. Bei 
der megaAVR-0-series (die ich etwas kenne) sieht es so aus:

.equ ADC0_RES = 1552                     ; ADC Accumulator Result
.equ ADC0_RESL = 1552                    ; ADC Accumulator Result low 
byte
.equ ADC0_RESH = 1553                    ; ADC Accumulator Result hi 
byte
Gast #6011030
Lesenswert?

Das mit dem Temp-Register ist eine Hardware, die für 16Bit-Register
einen atomaren Zugriff ermöglicht. Das ist besonders bei laufenden 
Timern
entscheident. Der richtige Zugriff ist aber NICHT auf das Temp-Register,
sondern zuerst auf LB (latched HB) und dann auf HB!

Aber der Xmega hat doch auch 16Bit-Ladebefehle(?).
Evtl. einfach die benutzen. Ich kenne mich aber in Assembler nicht so 
aus...
#6011042
Lesenswert?

Tom schrieb:
> Deshalb habe ich es nun so gelöst:
> ldi r16, ADCA_CH0_RES
> ldi r17, ADCA_TEMP
> Das funktioniert auch

Schwer vorstellbar. LDI heißt "load immediate", also "lade direkt". Und 
zwar eine Konstante, die du im Header mit der EQU Direktive den Labels 
ADCA_CH0_RES und ADCA_TEMP zugewiesen haben müßtest. Du liest also nicht 
den ADC aus, sondern füllst die Register mit immer denselben Festwerten. 
Wie es richtig geht, wurde schon geschrieben.
Gast #6011353
Lesenswert?

S. Landolt schrieb:
> Das hatten wir doch bereits geklärt: Tom hat sich schlicht verschrieben,
> er meinte lds.
>   Die Frage ist eine andere: weshalb steht im 'def.inc'-File keine
> Definition für _RESH und _RESL.

Genau, so ist es. Die 2 Zeilen habe ich mal schnell zusammengetippt nur 
um zu zeigen, das es beim ATmega immer 2 Register eines LOW das andere 
HIGH gegeben hat. Habe leider nicht auf IN und LDS dabei geachtet. 
Vergebt mir bitte. :-)

S. Landolt schrieb:
> Okay, merkwürdig - bei dem 'def.inc'-File, dass ich mir eben mal
> heruntergeladen habe, steht wirklich nur
>
> .equ ADCA_CH0RES = 528    // Channel 0 Result

UND genau deshalb hatte ich hier auch nachgefragt, ob mein Handling dann 
das richtige ist. Weil ich das eben von den ATmegas so nicht kenne und 
Atxmega ist ja nun erst einmal neu für mich.

Alexxx schrieb:
> Der richtige Zugriff ist aber NICHT auf das Temp-Register,
> sondern zuerst auf LB (latched HB) und dann auf HB!

Auch deshalb habe ich hier nachgefragt, weil mir das mit dem 
TEMP-Register auch etwas merkwürdig vorgekommen ist. Auch das man immer 
das LOW Register als erstes und das HIGH Register als zweites lesen muss 
habe ich schon im Datenblatt gelesen.

Aber hat jemand vielleicht bitte eine Idee, wie ich denn nun das 16Bit 
Register "ADCA_CH0_RES" ganz professionell unter Assembler auslese?
Danke
Wäre sehr dankbar, wenn man bitte 2 Zeilen mal hier eintippen könnte.
#6011422
Lesenswert?

Tom schrieb:
> Genau, so ist es. Die 2 Zeilen habe ich mal schnell zusammengetippt nur
> um zu zeigen, das es beim ATmega immer 2 Register eines LOW das andere
> HIGH gegeben hat. Habe leider nicht auf IN und LDS dabei geachtet.

Nun, oben liest sich das so, als ob es tatsächlich funktioniert hätte:

Tom schrieb:
> Deshalb habe ich es nun so gelöst:
> ldi r16, ADCA_CH0_RES
> ldi r17, ADCA_TEMP
> Das funktioniert auch

So kann es jedoch unmöglich funktionieren.

> Vergebt mir bitte. :-)

Wenn es deinen Seelenfrieden rettet, bitteschön. Um auch zukünftig 
Absolution zu erhalten, solltest du nicht mit Salamitaktik arbeiten, 
sondern den gesamten Code posten. Und dazu schreiben, um welchen ATxmega 
es eigentlich geht, da gibt es nicht nur einen.
Gast #6011517
Lesenswert?

> Aber hat jemand vielleicht bitte eine Idee ...

Tja, solange sich hier kein ATxmega-Spezialist einschaltet, versuche ich 
es mal (aber es gibt hoffentlich bessere Möglichkeiten):
1
  lds  tmp0,ADCA_CH0_RES+0   ; low-byte
2
  lds  tmp0,ADCA_CH0_RES+1   ; high-byte
3
 
4
; oder das 'def.inc'-File ergaenzen, dort steht ja z.B.:
5
; .equ ADCA_CH0_RES = 548    // Channel Result;
6

7
; also:
8

9
.equ ADCA_CH0_RESL  = ADCA_CH0_RES+0
10
.equ ADCA_CH0_RESH  = ADCA_CH0_RES+1
11

12
  lds  tmp0,ADCA_CH0_RESL
13
  lds  tmp1,ADCA_CH0_RESH

Oder eben versuchen, ein "ordentliches" 'def.inc'-File irgendwoher zu 
bekommen.
Gast #6011542
Lesenswert?

Icke ®. schrieb:
> Nun, oben liest sich das so, als ob es tatsächlich funktioniert hätte

Es funktioniert ja auch, aber halt mit LDS. Ich habe halt nicht den 
originalen Code mit copy & past gemacht sondern nur schnell so 
eingetippt... War auch gestern schon sehr geschafft und müde nach 
stundenlangen studieren des Datenblattes.

Es handelt sich übrigens um den ATxmega256A3AU. Wenn jetzt einer sagt, 
den gibt es doch schon lange nicht mehr. Kann sein, habe das Teil auch 
schon ein paar Jährchen hier rum liegen. Es gab bis jetzt noch keine 
Anwendung die einen ATxmega benötigt hätte. Habe bis jetzt alles mit 
ATmega gemacht. Aber irgendwann kommt halt die Zeit...
Habe auch hier im Forum schon die Info zum ADC gelesen, das bei den 
"alten" Dingern das erste ADC Ergebnis nach Reset oder Power on nicht 
stimmt. Konnte ich auch bereits nachvollziehen.

S. Landolt schrieb:
> Tja, solange sich hier kein ATxmega-Spezialist einschaltet, versuche ich
> es mal

Danke, für das Code Beispiel. Werde es auf jeden Fall mal ausprobieren.

Habe aber gerade eben folgendes aus dem Datenblatt "A" gelesen:

For a read operation, the low byte of the 16-bit register must be read 
before the high byte. When the low byte register is
read by the CPU, the high byte of the 16-bit register is copied into the 
temporary register in the same clock cycle as the
low byte is read. When the high byte is read, it is then read from the 
temporary register.

Also sieht es doch so aus, als müsse man das ADC_TEMP Register für das 
HIGH Byte lesen und die Art und Weise wie ich es gemacht habe wäre dann 
ja richtig.

Alexxx schrieb:
> Das mit dem Temp-Register ist eine Hardware, die für 16Bit-Register
> einen atomaren Zugriff ermöglicht.

Somit hatte Alexxx auch mit dem "Atomaren Zugriff" genau das richtige 
angesprochen. Nur was dieser Atomare Zugriff überhaupt ist, hatte ich 
bis jetzt nicht gewusst. Hatte damit noch niemals etwas zu tun...

Also so wie es aussieht muss man dann wohl über das TEMP-Register gehen, 
um ein 16-Bit Register (wo nur ein Register im def.inc File steht) 
einzuladen.

Danke an alle, die dabei mitgeholfen haben.
Gast #6011560
Lesenswert?

nur noch mal zum Codebeispiel von S. Landolt.

Habe es gerade mal ausprobiert und es funktioniert auch!

Ich denke mir aber, das man das zwischenspeichern des HIGH Bytes in dem 
ADC_TEMP Register deshalb macht, damit nichts anderes (weiss der Teufel 
was...) das HIGH Byte Register ADCA_CH0_RESH während des lesen des LOW 
Registers verändert. Eventuell bekommt ein Resultatregister bereits mit 
dem nächsten oder übernächsten Takt schon eine neue AD-Konversion 
eingeschrieben bevor das HIGH Byte der vorherigen Konversion ausgelesen 
wurde. Änderst kann ich mir die Sache mit dem TEMP Register nicht 
erklären.

Aber vielen Dank nochmal an alle, die sich beteiligt haben.
#6011674
Lesenswert?

Tom schrieb:
> Also so wie es aussieht muss man dann wohl über das TEMP-Register gehen,
> um ein 16-Bit Register (wo nur ein Register im def.inc File steht)
> einzuladen.

Nein. Dieses Register wird nur controllerintern benutzt, um das Highbyte 
zwischenzuspeichern. Den Grund hast du schon richtig erkannt.
Ausgelesen wird der ADC über die beiden Register CHnRESL und CHnRESH (n 
steht für die Kanalnummer). DU mußt nur darauf achten, zuerst das 
Lowbyte auszulesen (CHnRESL) und danach das Highbyte (CHnRESH). Siehe 
auch Seite 357 des PDFs:

http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8331-8-and-16-bit-AVR-Microcontroller-XMEGA-AU_Manual.pdf

Beispiel für Kanal 0:

lds tmp_lowbyte,CH0RESL
lds tmp_highbyte,CH0RESH
Gast #6011761
Lesenswert?

>> TEMP-Register
> Dieses Register wird nur controllerintern benutzt

So sehe ich das auch. Bleibt aber die Frage, weshalb es eine (extern 
zugängliche) Adresse bekommen hat und diese auch noch explizit im 
'def.inc'-File steht.
Gast #6011766
Lesenswert?

Icke ®. schrieb:
> Beispiel für Kanal 0:
>
> lds tmp_lowbyte,CH0RESL
> lds tmp_highbyte,CH0RESH

Danke für deine zusätzliche Info.
Also die Register ADCA_CH0RESL oder ADCA_CH0RESH sind im def.inc File 
nicht vorhanden. Kann diese aber wie S. Landolt beschrieben hat anlegen.
Habe jetzt diese 2 Zeilen im Programmcode eingegeben. Es funzt!

lds temp,ADCA_CH0RES
lds temp2,ADCA_CH0RES + 1

Dann verstehe ich auch jetzt was mit dem Satz aus dem Datenblatt "When 
the high byte is read, it is then read from the temporary register." 
gemeint ist.
Es soll nicht bedeuten, das man das HIGH Byte aus dem temp-Register 
holen muss, sondern das bei dem Lesen des HIGH Byte (ADCA_CH0RES + 1) 
der Wert aus dem temp-Register kommt...

Dann ist das Ganze Problem mit meiner Frage nur aufgetreten, weil in dem 
def.inc File des ATxmega256A3AU keine Registernamen für LOW und 
HIGH-Byte existieren, sondern nur ein Registername ADCA_CH0RES. Wenn ich 
da die Namen des LOW und HIGH Registers gefunden hätte, so wie diese 
auch im Datenblatt stehen, wäre alles klar gewesen.

Aber Dank eurer Hilfe ist das jetzt alles ganz klar. Es gibt ja 
wahrscheinlich auch noch andere 16-Bit Register die ähnlich zu bedienen 
sind. Da werde ich in den nächsten Tagen bei meinem ATxmega 
kennenlern-Tests bestimmt noch drauf stoßen.
Danke für all eure Info.
Gast #6011774
Lesenswert?

S. Landolt schrieb:
> Bleibt aber die Frage, weshalb es eine (extern
> zugängliche) Adresse bekommen hat und diese auch noch explizit im
> 'def.inc'-File steht.

Ich denke zum simpleren Debugen. Auch die 0/1-Series haben das TMP 
Register. Und es wurde zwischendurch mal die Reihenfolge der L/H 
Zugriffe re. Lesen/Schreiben veraendert.

leo
#6011884
Lesenswert?

Tom schrieb:
> Also die Register ADCA_CH0RESL oder ADCA_CH0RESH sind im def.inc File
> nicht vorhanden.

Ja, das ist doof.

Tom schrieb:
> Es gibt ja wahrscheinlich auch noch andere 16-Bit Register die ähnlich zu
> bedienen sind.

Richtig, da muß man stets aufpassen. Beliebte Stolperfalle ist auch das 
Mapping der Register (I/O bzw. Memory), das nicht immer logisch 
konsistent ist. So sind bspw. beim ATmega1284 die OCR-Register der 
Timerkanäle 1-3 memory mapped, die des Timerkanals 0 dagegen I/O mapped. 
Ein Blick ins *def.inc lohnt immer.
Gast #6011910
Lesenswert?

Icke ®. schrieb:
> So sind bspw. beim ATmega1284 die OCR-Register der
> Timerkanäle 1-3 memory mapped, die des Timerkanals 0 dagegen I/O mapped.

OCR0A ist auch I/O mapped. OCR1.. offsets sind jenseitig der direkt 
mittels I/O-Befehlen erreichbaren.

s. Handbuch 9.5 usw
"The device is a complex microcontroller with more peripheral units than 
can be supportedwithin the 64 location reserved in Opcode for the IN and 
OUT instructions."

leo

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