Forum: Mikrocontroller und Digitale Elektronik XMega Port Register Verwirrung


von Ingo (Gast)


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

von XMega user (Gast)


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ß

von Detlev T. (detlevt)


Lesenswert?

Frage dazu: Warum sollte man das überhaupt machen wollen? Der Sinn von 
OUTSET, OUTCLR, OTTGL etc ist es doch gerade, dieses ReadModifyWrite zu 
vermeiden.

von Ingo (Gast)


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

von Fabian O. (xfr)


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.

von XMega user (Gast)


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.

von Detlev T. (detlevt)


Lesenswert?

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

Was ergibt denn überhaupt ein Lesezugriff auf OUTCLR? Vermutlich nicht 
den Wert von OUT. Und selbst wenn: Bei deinem Beispiel wird dann bei den 
anderen Bits jede 1 zur Null. Natürlich ändert das den Wert!

von Ingo (Gast)


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

von Uwe (Gast)


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 ?

von Fabian O. (xfr)


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;

von Ingo (Gast)


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

von Ingo (Gast)


Lesenswert?

OK, hab was gefunden:
1
void WDT_Disable( void )
2
{
3
  uint8_t temp = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
4
5
  CCP = CCP_IOREG_gc;
6
  WDT.CTRL = temp;
7
}

wen's interessiert.


Ingo

von Fabian O. (xfr)


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
}

von Ingo (Gast)


Lesenswert?

Hallo Fabian,

danke für die Info, ich habe deinen Code implementiert!



Ingo

von Mazv (Gast)


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 ?

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.