Forum: Mikrocontroller und Digitale Elektronik Atxmega 16bit register lesen/schreiben


von Tom (Gast)


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

von S. Landolt (Gast)


Lesenswert?

> Bei einem ATmega hat man immer Werte über 8Bit so eingeladen:
> ldi ...

Wohl eher mit in bzw. lds.

> Das funktioniert auch ...

?

von Tom (Gast)


Lesenswert?

Ahh JA, macht der Gewohnheit....

Natürlich beim ATxmega mit LDS! und nicht mit LDI!

Aber ist das denn so in Ordnung??? mit dem Laden des HIGH wertes aus dem 
"TEMP" Register?
Danke

von S. Landolt (Gast)


Lesenswert?

Dies nun kann ich leider nicht beantworten, da ich die ATxmega nicht 
kenne, hatte mich nur gewundert, dass es dort per ldi funktioniert,

von c-hater (Gast)


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.
von S. Landolt (Gast)


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.

von c-hater (Gast)


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.

von S. Landolt (Gast)


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

von Alexxx (Gast)


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...

von Icke ®. (49636b65)


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.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

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.

von Tom (Gast)


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.

von Icke ®. (49636b65)


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.

von S. Landolt (Gast)


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.

von S. Landolt (Gast)


Lesenswert?

Oder so etwas, ist vielleicht einfacher&flexibler:
1
.macro  getw  ; high,low,source
2
  lds    @1,@2+0
3
  lds    @0,@2+1
4
.endmacro
5
6
  getw  tmpH,tmpL,ADCA_CH0_RES

von Tom (Gast)


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.

von Tom (Gast)


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.

von Icke ®. (49636b65)


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

von S. Landolt (Gast)


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.

von Tom (Gast)


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.

von leo (Gast)


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

von Icke ®. (49636b65)


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.

von leo (Gast)


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

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.