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
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
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
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.
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); |
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 ...
Vielen Dank für die Antworten! habe den Befehl LPC_GPIO0->FIOPIN &= ~0x01; durch die neue Anweisung LPC_GPIO0->FIOCLR |= 0x01; ersetzt. Gruß Justus
Justus schrieb: > durch die neue Anweisung > LPC_GPIO0->FIOCLR |= 0x01;
1 | LPC_GPIO0->FIOCLR = 0x01; |
wäre strenggenommen korrekt.
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.
>> LPC_GPIO0->FIOCLR |= 0x01; Nicht atomic >> LPC_GPIO0->FIOCLR = 0x01; atomic
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.