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