Forum: Mikrocontroller und Digitale Elektronik ATMega644 - wahlfreies Schreiben auf Register


von Uwe (Gast)


Lesenswert?

Hallo,

ich scheitere als ATMega Anfänger folgende Funktion mit Leben zu füllen.

void writeReg(char addr, char data)

Die Funktion soll den Schreibzugriff auf alle Register ermöglichen.
addr = 0...255
data = 0...255

In C kann ich ja sehr einfach einen Lesefunktion implementieren

data = *addr;

aber ein Schreibzugriff funktioniert leider nicht

*addr = data;

Am Inline Assembler bin ich bisher gescheitert, da ich keine Erfahrung 
im Umgang mit Operanden und Constraints habe.

Die Register-Definitionen möchte ich nicht benutzen, da ich einen 
wahlfreien Zugriff haben möchte.

Es wäre prima, wenn mir jemand mit Hinweisen und/oder Code-Beispielen 
helfen könnte.

Danke & Gruß
Uwe

von Εrnst B. (ernst)


Lesenswert?

Auch wenn ich vor der Antwort irgendwie Angst habe:
WARUM?

von Ahem (Gast)


Lesenswert?

>aber ein Schreibzugriff funktioniert leider nicht

>*addr = data;

Was heist "es geht nicht"?

Grundsätzlich sollte es gehen. Du musst allerdings die Spezialitäten bei 
dem Adressmapping von Registern beachten. Ich kenne die Details beim 644 
nicht, aber es gibt einige Register die je nach Adresslage einen Offset 
brauchen, je nachdem welcher Assemblerbefehl verwendet werden soll. 
Evtl. gibt es auch Register die garnicht gemappt sind und nur per I/O 
Befehl erreichbar sind (Ohne Gewähr).

Ob Dein Compiler das schafft, weiss ich nicht, da meine Glaskugel mir 
diesen einfach nicht nennen will.

von jupp (Gast)


Lesenswert?

was willst du damit? was spricht gegen

REG = data

oder besser

REG = ((1 << BIT_NAMEa) | (1 << BIT_NAMEb)) ...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Was für "Register" sind das denn?  Im Adressbereich 0...31 befinden
sich (außer beim Xmega) die CPU-Register, und IO-Register gibt es
(je nach AVR) auch noch jenseits der Adresse 0xff, die du maximal
mit einem "char" (druckbares Zeichen?) adressieren kannst.
1
static inline
2
uint8_t read_addr(uint16_t addr)
3
{
4
  return *(volatile uint8_t *)addr;
5
}
6
7
static inline
8
void write_addr(uint16_t addr, uint8_t data)
9
{
10
  *(volatile uint8_t *)addr = data;
11
}

Use at your own risk.  Avoid shooting into your foot...

von Uwe (Gast)


Lesenswert?

Hallo miteinander,

gene beantworte ich die aufgetauchten Fragen.

- warum?
Ich habe mir ein Monitor-Programm entwickelt, welches zum bring-up 
bisher gute Dienste geleistet hat. All die üblichen Kommandos 
funktionieren schon (flash read, eeprom read/write/fill, register 
read,...). Nur das register write will nicht.

- was geht nicht?
Der Werte [data] landet nicht in dem gewünschten Register. Wenn ich das 
Register mit meiner Funktion wieder auslese, steht nicht der Wert drin, 
bzw. die Ausgänge ändern Ihren Status nicht. Die Lesefunktion ist OK, da 
ich Port-Pins korrekt einlesen kann, wenn ich z.B. das externe Signal 
ändere.

- welche Register?
Eigentlich alle. Die CPU-Register 0x0 - 0x1F sind sicherlich nicht von 
großem Interesse. Jedoch der restliche Bereich schon.
Gerne mache ich auch eine Fallunterscheidung in Abhängigkeit der 
gewünschten Adresse, wenn man unterschiedliche Registerbereiche 
unterschiedlich behandeln muss.

Im Preliminary data-sheet des 644P (Seite 417, Fußnote 4) steht:

When using the I/O specific commands IN and OUT, the I/O addresses $00 - 
$3F must be used. When addressing I/O registers
as data space using LD and ST instructions, $20 must be added to these 
addresses. The ATmega164P/324P/644P is a
complex microcontroller with more peripheral units than can be supported 
within the 64 location reserved in Opcode for the
IN and OUT instructions. For the Extended I/O space from $60 - $FF, only 
the ST/STS/STD and LD/LDS/LDD instructions
can be used.

Daraus entnehme ich, dass ich auf alle Register mit dem asm Befehl ST 
zugreifen kann. Mit in und out nur auf 0x20-0x5F (bzw. 0x0 - 0x3F).

Genau an dem Punkt stehe ich nun.

Gruß
Uwe

(dl4sdx)

von Hannes Lux (Gast)


Lesenswert?

Mit LDS/STS/LD/ST kannst Du auf alle Register und SRAM zugreifen. Beim 
Mega644 wären das:
0..31:   R0..r31
32..95:  I/O-Bereich
96..255: Extended I/O
ab 256:  SRAM

Wie man jetzt dem Compiler sagt, dass er LDS/STS/LD/ST benutzen soll, 
ist einer der vielen Gründe, warum ich C meide und in ASM werkele. ;-)

...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hannes Lux wrote:

> Wie man jetzt dem Compiler sagt, dass er LDS/STS/LD/ST benutzen soll,
> ist einer der vielen Gründe, warum ich C meide und in ASM werkele. ;-)

Dafür habe ich die C-Antwort aber auch schon eine Stunde früher
fertig gehabt...   Scheint den OP ja aber nicht weiter zu
interessieren.

von Uwe (Gast)


Lesenswert?

Hallo,

vielen Dank für eure Antworten. Ich bin nun dazu gekommen die Vorschläge 
auszuprobieren.

Das Beispiel vom Jörg Wunsch funktioniert prima.

Danke für eure schnelle und kompetente Hilfe

Gruß
Uwe

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.