Forum: Mikrocontroller und Digitale Elektronik Cortex M3 Port Pin wird nicht auf 0 gesetzt


von Justus (Gast)


Lesenswert?

Hallo,
Ich nutze einen NXP Cortex Controller LPC1764.
Sporadisch kommt es vor das aus einer Interrupt-Routine Port-Pins an P0
nicht gelöscht werden, obwohl der Befehl (LPC_GPIO0->FIOPIN &= ~0x01) in 
der Firmware korrekt aufgerufen wird.
Was kann das Problem sein?
Würde mich über Antworten sehr freuen.
Gruß
Justus

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Justus schrieb:
> Sporadisch kommt es vor das aus einer Interrupt-Routine Port-Pins an P0
> nicht gelöscht werden, obwohl der Befehl (LPC_GPIO0->FIOPIN &= ~0x01) in
> der Firmware korrekt aufgerufen wird.

Wenn im Vordergrundprogramm oder einem anderen Interrupt-Handler 
ebenfalls auf dieses Register schreibend zugegriffen wird, können sich 
die Zugriffe gegenseitig unterbrechen. Z.B. liest das Programm den alten 
Inhalt aus, wird dann durch den Interrupt-Handler unterbrochen, der P0 
zurücksetzt, und arbeitet nach Beendigung des Interrupt-Handlers auf 
seinem alten Registerinhalt mit noch gesetztem P0 weiter. Also werden 
solche Peripherie- und/oder Registeroperationen nicht atomar ausgeführt.

Viele aktuelle Microcontroller haben daher separate Periherieregister, 
mit denen einzelne (oder mehrere) Bits gesetzt werden können, und 
solche, mit denen die entsprechenden Bits zurückgesetzt werden können. 
Dies vermeidet zum einen auf Programmseite viel Aufwand durch 
Lesen->verunden->verodern->schreiben, und zum anderen sind die 
Schreibzugriffe atomar. Der einzige Nachteil besteht darin, dass man 
nicht gleichzeitig Bits setzen und zurücksetzen kann.

Ansonsten besteht noch die Möglichkeit, die Peripheriezugriffe durch 
Interruptsperren o.ä. zu schützen.

<glaskugelmodus>
In Deinem Programm befindet sich der Fehler übrigens in Zeile 42.
</glaskugelmodus>

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Justus schrieb:
> Was kann das Problem sein?
Vermutlich ist es das übliche Semaphorenproblem: du greifst von 2 
Stellen nicht atomar auf das LPC_GPIO0->FIOPIN Register zu.
Dein Interupt unterbricht dabei einen solchen Zugriff auf das 
LPC_GPIO0->FIOPIN, der gerade in der Hauptschleife am Laufen ist.

Das passiert natürlich während der Testphase nur 1 einziges Mal, laut 
Murphy beim Kunden dann aber zuverlässig jede Viertelstunde. Bis der 
Techniker kommt.

EDIT: hoppla, Absenden vergessen... ;-)

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Andreas S. schrieb:
> Der einzige Nachteil besteht darin, dass man nicht gleichzeitig Bits
> setzen und zurücksetzen kann.

Doch, das geht durchaus - z.B. beim STM32F4 mit dem BSRR-Register.

von Peter D. (peda)


Lesenswert?

Justus schrieb:
> obwohl der Befehl (LPC_GPIO0->FIOPIN &= ~0x01) in
> der Firmware korrekt aufgerufen wird.

Um einen Pin zu löschen, nimmt man besser die passende Lib-Funktion, die 
kann das dann atomar.
1
Chip_GPIO_SetPinState(LPC_GPIO_PORT, 0, 0, false);

von A. B. (Gast)


Lesenswert?

Lothar M. schrieb:
> Dein Interupt unterbricht dabei einen solchen Zugriff auf das
> LPC_GPIO0->FIOPIN, der gerade in der Hauptschleife am Laufen ist.

Auch NXP hat sich dafür Set/Reset-Register ausgedacht: FIOxSET, FIOxCLR
Damit geht's nicht nur atomar, sondern auch noch einfacher/schneller.
Man muss sie halt nur verwenden ...

von Justus (Gast)


Lesenswert?

Vielen Dank für die Antworten!

habe den Befehl
LPC_GPIO0->FIOPIN &= ~0x01;

durch die neue Anweisung
LPC_GPIO0->FIOCLR |= 0x01;

ersetzt.

Gruß
Justus

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Justus schrieb:
> durch die neue Anweisung
> LPC_GPIO0->FIOCLR |= 0x01;
1
LPC_GPIO0->FIOCLR = 0x01;

wäre strenggenommen korrekt.

von A. B. (Gast)


Lesenswert?

Andreas S. schrieb:
>
1
> LPC_GPIO0->FIOCLR = 0x01;
2
>
>
> wäre strenggenommen korrekt.

Nicht nur strenggenommen, sondern einfach 'korrekt'. Zwar sind FIOxSET 
und FIOxCLR lt. UM R/W, allerdings steht nicht ausdrücklich da, dass 
beim Lesen  0 herauskommt: "Reading the FIOxSET register returns the 
value of this register, as determined by previous writes to FIOxSET and 
FIOxCLR (or FIOxPIN as noted above). This value does not reflect the 
effect of any outside world influence on the I/O pins."
Diese Beschreibung ist reichlich obskur, ich verstehe sie jedenfalls 
nicht.

Und erst das Register lesen, ein Bit auf '1' setzen und dann das zurück 
schreiben ist doch etwas sonderbar und höchst ineffizient - sowohl für 
den Compiler als auch für den uC.

von Uwe (Gast)


Lesenswert?

>> LPC_GPIO0->FIOCLR |= 0x01;
Nicht atomic

>> LPC_GPIO0->FIOCLR = 0x01;
atomic

von Justus (Gast)


Lesenswert?

Nochmals vielen Dank für die ergäzenden Hinweise.
Werde morgen im Labor die Firmware daraufhin ändern und den Port Pin mit 
dem Oszilloskop überwachen. Bin gespannt auf das Ergebnis.
Viele Grüße
Justus

von Justus (Gast)


Lesenswert?

Habe die Befehle von

LPC_GPIO0->FIOPIN |= 0x01;

nach

LPC_GPIO0->FIOCLR = 0x01;

geändert.

Jetzt funktioniert der Port-Pin zuverlässig.

Vielen Dank für den guten Support!

Gruß
Justus

von Jürgen S. (starblue) Benutzerseite


Lesenswert?

A. B. schrieb:
> Andreas S. schrieb:
>>> LPC_GPIO0->FIOCLR = 0x01;
>>
>>
>> wäre strenggenommen korrekt.
>
> Nicht nur strenggenommen, sondern einfach 'korrekt'. Zwar sind FIOxSET
> und FIOxCLR lt. UM R/W, allerdings steht nicht ausdrücklich da, dass
> beim Lesen  0 herauskommt: "Reading the FIOxSET register returns the
> value of this register, as determined by previous writes to FIOxSET and
> FIOxCLR (or FIOxPIN as noted above). This value does not reflect the
> effect of any outside world influence on the I/O pins."
> Diese Beschreibung ist reichlich obskur, ich verstehe sie jedenfalls
> nicht.

Ich würde mal vermuten, dass der Wert des Ausgaberegisters gelesen wird 
(nicht des Pins, das wäre dann "outside influence"). Ausprobiere tu 
ich's jetzt aber nicht.

Das hieße dann, mit LPC_GPIO0->FIOCLR|= werden ALLE gesetzten Bits 
zurückgesetzt, was definitiv falsch ist.

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.