XMega Port Register Verwirrung

Gast #3073352
Lesenswert?

Warum kann ich beim XMega nur vernünftig auf die Portregister zugreifen, 
wenn ich die OUTSET, OUTCLR, OUTTGL sowie DIRSET und DIRCLR direkt 
beschreibe, so hier:
1
PORTC.OUTCLR = PIN3_bm;
und nicht über :
1
PORTC.OUTCLR |= (1<<PIN3_bp);
? Wenn ich letzteres mache überschriebt er irgendwie vorhandene 
Konfigurationen anderer Pins, auch im Simulator. In der Errata steht 
dazu nichts bzw. hab ich was übersehen?

Probiert's mal aus. Ich nutze das aktuelle AtmelStudio 6 (nicht die 6.1 
Beta).



Ingo
Gast #3073375
Lesenswert?

Hallo Ingo,

also wenn du OUTSET, OUTCLR und OUTTGL verwenden willst, dann ohne & und 
|, also so:
1
PORTC.OUTCLR = (1<<PIN3_bp);

wenn du mit & und | arbeiten willst, dann direkt mit OUT:
1
PORTC.OUT &= ~(1<<PIN3_bp);

gleiches gilt für DIRSET, DIRCLR und DIR.

Gruß
Gast #3073385
Lesenswert?

Detlev T. schrieb:
> Frage dazu: Warum sollte man das überhaupt machen wollen? Der Sinn von
> OUTSET, OUTCLR, OTTGL etc ist es doch gerade, dieses ReadModifyWrite zu
> vermeiden.
Klar, abfinden kann ich mich damit ja. Auch ist mir den Sinn völlig 
klar. Mich würde halt nur interessieren warum es nicht mit dem ODER 
-oder UND-Zugriff klappt.


Ingo
#3073389
Lesenswert?

Die Register OUTSET, OUTCLR und OUTTGL sind dafür gedacht, dass man 
einzelne Bits bequem Setzen, Löschen oder Togglen kann, indem man eine 1 
an die Stelle schreibt. Sie sind nicht dazu da, gelesen zu werden. Das 
"normale Register" heißt nur OUT. Analog bei DIR.

Diese Anweisungen machen also das gleiche (nur dass die erste jeweils 
schneller ist):
1
PORTC.OUTSET = PIN3_bm;
2
PORTC.OUT |= PIN3_bm;

Ebenso:
1
PORTC.OUTCLR = PIN3_bm;
2
PORTC.OUT &= ~PIN3_bm;

Und:
1
PORTC.OUTTGL = PIN3_bm;
2
PORTC.OUT ^= PIN3_bm;

Außerdem ist es egal, ob Du schreibst
1
PORTC.OUTSET = PIN3_bm;
oder
1
PORTC.OUTSET = (1 << PIN3_bp);

_bp steht für Bitposition, _bm für Bitmaske. In der Bitmaske ist das 
Shiften mit (1 << x) schon mit enthalten.
Gast #3073391
Lesenswert?

ja, schon, nur haben die Atmel-Entwickler diese Möglichkeit wohl 
trotzdem offen gelassen. Ich verwende auch nur OUTSET, OUTCLR und 
OUTTGL. Read-modify-write war bei mir bisher auch nicht notwendig. Ist 
aber trotzdem noch möglich.
Gast #3073398
Lesenswert?

XMega user schrieb:
> Read-modify-write war bei mir bisher auch nicht notwendig
Es klappt auch mit diesen "Spezialregistern" nicht!
Miese Falle wenn man das von den normalen Megas gewohnt ist, zumal im DB 
nichts dazu steht das es nicht geht, da steht sogar drinn das diese 
Register auch gelesen werden können.

Ingo
Gast #3073403
Lesenswert?

> PORTC.OUTCLR |= (1<<PIN3_bp);
ist die verkürzte Form von :
PORTC.OUTCLR = PORTC.OUTCLR | (1<<PIN3_bp);

Kann das Register PORTC.OUTCLR denn gelesen werden und wenn ja werden 
dann immer alle bits als 1er zurückgelesen oder als 0er oder eventuell 
als undefiniert ?
Hab jetzt das Datenblatt nicht gelesen aber was steht denn da drinn über 
dieses Register ?
#3073405
Lesenswert?

Ingo schrieb:
> Mich würde halt nur interessieren warum es nicht mit dem ODER
> -oder UND-Zugriff klappt.

Dazu musst Du ins Datenblatt schauen. Da steht bei OUTSET, OUTCLR und 
OUTTGL:
Reading this register will return the value of the OUT register.

Wenn Du also schreibst
1
PORTC.OUTCLR |= (1<<PIN3_bp);
ist das gleichbedeutend mit:
1
PORTC.OUTCLR = PORTC.OUT | (1<<PIN3_bp);

Es werden also alle aktuell auf 1 gesetzten Pins sowie PIN3 auf 0 
gesetzt. Also letztlich alle Pins. Dann kannst Du auch gleich schreiben:
1
PORTC.OUTCLR = 0xFF;
bzw.
1
PORTC.OUT = 0;
Gast #3073415
Lesenswert?

Fabian O. schrieb:
> PORTC.OUTCLR = PORTC.OUT | (1<<PIN3_bp);
Aua! Das ist der entscheidende Hinweis, darüber habe ich garnicht 
nachgedacht! Vielen Dank, das bring Licht ins Dunkle!

Wo wir gerade dabei sind, hat jemand ne Routine, am Besten in C, wie man 
den WDT wieder aus kriegt (XMega)?



Ingo
#3073452
Lesenswert?

Ingo schrieb:
> Wo wir gerade dabei sind, hat jemand ne Routine, am Besten in C, wie man
> den WDT wieder aus kriegt (XMega)?

Dazu musst Du die "Configuration Change Protection" aufheben. Das geht 
in C nur, wenn der Compiler den Code richtig optimiert, damit es 
innerhalb der vorgeschriebenen Taktzyklen klappt. Deshalb ist es 
sauberer, das als Inline-Assembler zu machen:
1
static inline void write_ccp_io(volatile uint8_t* addr, uint8_t value)
2
{
3
  asm volatile (
4
    "st  %a0, %1; \n\t" // Unlock access by writing signature to CCP
5
    "st  %a2, %3; \n\t" // Write value to addr
6
    : // No output operands
7
    : "e" (&CCP), "r" (CCP_IOREG_gc), "e" (addr), "r" (value)
8
    : "memory"
9
  );
10
}
11

12
void watchdog_disable(void)
13
{
14
  write_ccp_io(&WDT.CTRL, (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm);
15
}
Gast #4793570
Lesenswert?

> static inline void write_ccp_io(volatile uint8_t* addr, uint8_t value)
> {
>   asm volatile (
>     "st  %a0, %1; \n\t" // Unlock access by writing signature to CCP
>     "st  %a2, %3; \n\t" // Write value to addr
>     : // No output operands
>     : "e" (&CCP), "r" (CCP_IOREG_gc), "e" (addr), "r" (value)
>     : "memory"
>   );
> }
>
> void watchdog_disable(void)
> {
>   write_ccp_io(&WDT.CTRL, (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm);
> }

Ich habe den Code implementiert (ATxmega64A3) , aber der Watchdog lässt 
sich dadurch leider nicht deaktivieren. Die in den Fuses ist WDLOCK 
nicht gesetzt und das reseten des Watchdogs funktioniert einwandfrei.
Hat denn jemand eine Idee, wie die Deaktivierung bei diesem uC 
funktionieren könnte ?

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