PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Cortex M3 unerklärliches Interrupt Verhalten



Siro
01.07.2011, 15:17
Ich habe ein Problem mit dem LPC1768 Timer generell:
Ich habe den Timer so initialisiert, daß er jede milli Sekunde aufgerufen wird.
Im Timerinterrupt drehe ich lediglich ein Portbit um, damit ich mit dem Ossi messen kann ob das Timing stimmt.
Das Timiung stimmt absolut. Da ich das Portbit bei jedem Interrupt umdrehe XOR müste aber ein symetrisches Rechteck herauskommen.
Aber, es kommt eine 650 nano Sekunden Flanke gefolgt von dem Rest der gewünschten einen milli Sekunde heruas.
Ähnlich einer extrem schmalen PWM. Wenn ich die letzte blödsinnige Zeile x-- mit reinkompiliere geht es einwandfrei.
Wo ist denn da der Zusammenhang. Ich suche schon den ganzen Tag.
Erstaunlich aber auch, wenn ich zuerst das Interrupt Bit MR0INT lösche und dann das Portbit umdrehe geht es auch ohne das
blödsinnige x--. Der Zusammenhang ist mir bisher nicht erklärlich.
ich kann aber statt x-- auch for (x=0; x < 100; x++) ; benutzen, dann geht es auch wieder richtig.
Der eigentliche Code scheint also keine Rolle zu speilen, Hauptsache da kommt noch was.
Ich kann das Interruptbit auch 2 mal löschen dann geht es auch wieder richtig.
Es sieht so aus, als wenn der Prozossor es nicht mag, wenn als letzte Aktion in der Interrupt Routine das entsprechende
Interruptbit gelöscht wird. Ich habe es auch mit den Timern 1 2 und 3 probiert, die verhalten sich alle gleich "falsch"
Steht ein Stück Progrmmcode hinter dem Löschen des Interruptbits ist alles in Ordnung.



int x;

void TMR3_IRQHandler (void)
{

LPC_FIO1PIN.value ^= 2; /* Portbit umdrehen (Oszilloskope Signal) */
LPC_T3IR.bits.MR0INT = 1; /* Interrupt Bit loeschen */

x--; /* voelliger Blödsinn, aber ohne geht es nicht richtg ??????? */
}


Ein bischen Google und das Problem wurde mir tatsächlich exakt so bestätigt.
Ganz egal ob NXP oder Analog Devices, der Cortex M3 Kern ist schuld. Das ist jetzt aber nicht negtiv gemeint.
Ein "DSB" Befehl "Data Synchronization Barrier" als letzter Befehl wirkt Wunder.
Hiermit wird sichergestellt, daß alle Speicherzugriffe komplett erledigt sind bevor ein neuer Befehl eingeleitet wird.
Also entweder das Interruptbit NICHT als LETZTES löschen dann z.B. mittels "DSB" Befehl dafür sorgen, das alles reibungslos abläuft.
Ich hätt mal vorher googlen sollen, aber dafür bin ich stolz es selbst gefunden zu haben.

Bei IAR Embedded Workbench kann ich den DSB Befehl in der C-Source-Datei so eingeben:

__asm("DSB"); /* Data Synchronization Barrier */


ein schönes Wochenende wünsche ich allen.
Siro

richie1234
06.07.2011, 07:56
Tja, ich hole Dich nur ungern aus Deinen Träumen, aber...

RTFM gilt leider auch hier.
Ich weiß, daß es mühselig ist, wenn man sich die diversen Datenblätter und Handbücher zum M3 und dann auch noch zum jeweils ausgesuchten Hersteller und Derivat durchlesen muss. Das ist immerhin eine vierstellige Anzahl von Seiten.
Viele unterlassen das dann und wundern sich dann, wenn solche Effekte wie bei Dir auftreten.
Dabei sind diese Effekte keine "Probleme", sondern schlicht gewollte Features.
Und Dein Lösungsvorschlag funktioniert auch nur zufällig, Du hast nämlich die eigentliche Ursache nicht verstanden...

Hier also die Lösung von einem, der die Handbücher gelesen hat:
NXP (aber auch andere Anbieter) baut bei seinen LPCs einen Puffer in die APB Bridges. Das machen die, damit die CPU (und DMA) auf APB Devices schreiben können, ohne darauf zu warten, bis der Schreibvorgang zu Ende ist. Das erhöht die durchschnittliche Performance des MCs.
In Deinem Fall entsteht dadurch das Problem, daß die CPU den Interrupt bereits beendet hat, bevor der Schreibvorgang auf das Register beendet wurde. Durch den DSB-Befehl reicht dann die Zeit zufällig aus, den Schreibvorgang zu beenden.
Problematisch dabei ist, daß der Schreibpuffer außerhalb des M3-Cores ist. Dadurch bekommt der Core nicht mit, wann der Schreibvorgang abgeschlossen ist und der DSB-Befehl nutzt rein gar nichts. Bei anderer, langsamerer Peripherie ist es also durchaus möglich, daß die Zeit für die Ausführung des DSB-Befehls nicht ausreicht um den Schreibvorgang zu beenden und wieder für einen "unbedarften" Nutzer Seiteneffekte entstehen.

Also nochmal mein Tip an alle M3-Nutzer:
Lest Euch die Handbücher und Datenblätter durch!
Der Cortex-M3 - so einfach der einem beim ersten Ansehen auch erscheinen mag - ist ein komplexes Stück Hardware, welches durchaus so seine Eigenheiten hat. Und die erkennt man nur durchs Datenblatt-Lesen.

Siro
11.07.2011, 13:14
Habe ich da etwas falsch verstanden ? Kann ja sein, ich beziehe mich mal auf folgenden Link:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDDGICF.html

#DSB acts as a special data synchronization memory barrier. Instructions that come after the DSB, in program order, do not execute until the DSB instruction completes. The DSB instruction completes when all explicit memory accesses before it complete.

oder hier: CortexM3_TRM.pdf Kapitel 14.9 Write Buffer:
DMB and DSB instructions wait for the write buffer to drain before completing

Ich habe es so verstanden: Es werden erst alle vorigen Schreibzugriffe erledigt, dann gehts weiter.
Wenn ich hier tatsächlich falsch liege, bitte ich um nähere Erklärung.

mfg. Siro

richie1234
11.07.2011, 14:49
Habe ich da etwas falsch verstanden ? Kann ja sein, ich beziehe mich mal auf folgenden Link:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDDGICF.html

#DSB acts as a special data synchronization memory barrier. Instructions that come after the DSB, in program order, do not execute until the DSB instruction completes. The DSB instruction completes when all explicit memory accesses before it complete.

oder hier: CortexM3_TRM.pdf Kapitel 14.9 Write Buffer:
DMB and DSB instructions wait for the write buffer to drain before completing

Ich habe es so verstanden: Es werden erst alle vorigen Schreibzugriffe erledigt, dann gehts weiter.
Wenn ich hier tatsächlich falsch liege, bitte ich um nähere Erklärung.

mfg. Siro


Den Teil hast Du richtig verstanden.
Was Du nicht verstanden hast, ist, daß NXP (und andere) in ihre Peripherie auch Schreibpuffer einbauen.
Und diese sind dem M3-Kern nicht bekannt. Insofern kann ein DSB-Befehl auch nicht wissen, wann diese Puffer weggeschrieben sind. Und darum ist Dein Vorschlag hier falsch.
Der DSB-Befehl nutzt nur bei Operationen im Kern etwas. Beispiele finden sich in der ARM-Literatur ja zu Hauf.

Joseph Yiu, der Autor vom Buch "The Definitive Guide to the ARM Cortex-M3" schreibt zu dem Thema übrigens folgendes:

Normally the Cortex-M3 wait until the previous write is completed before the interrupt return. However, some microcontrollers has a write buffer in the peripheral bridge. The write buffer accelerates single write transfers to peripherals so that the processor don't have to wait until the transfer is done (peripheral bus might be running at slower clock speed).

However, for clearing an interrupt request, the write buffer reply to the processor that transfer is done, while the actual write transfer actually haven't been completed in the peripheral. So the processor executed interrupt return, and found that the interrupt request from the peripheral is still high and think that it is a new interrupt request.

Adding memory barrier instruction (e.g. DSB) doesn't always help because the buffer is outside the processor. But it might introduce just enough delay to allow the interrupt to be cleared.
Calling a function to clear the interrupt pending register NVIC also introduce some extra clock cycles of delay. So the interrupt request is deasserted when interrupt return is executed.

Another way to solve this problem is to carry out a dummy access to the peripheral, e.g. a read access to the same peripheral, to ensure that the previous write is completed before executing the interrupt return.

Siro
11.07.2011, 16:06
Ersteinmal vielen Dank für deine Informationen.
Das leuchtet mir jetzt ein. Ich habe nicht damit gerechnet, daß die Peripherie, welche um den Kern gebaut wurde, ebenfalls Buffer beinhalten könnte. Das kann der eigentliche M3 Kern natürlich nicht wissen und damit nützt mir der DSB Befehl eigentlich nur insofern, daß etwas Zeit vergeht und lediglich sichergestellt ist, daß der Write Buffer der CPU fertig ist. Super, bin ich doch gleich wieder ein bischen schlauer geworden.

"The Definitive Guide to the ARM Cortex-M3" scheint ein sehr gutes Buch zu sein, werde ich mir gleich besorgen. Das sind ja ganz wichtige Informationen, die man dem NXP Datenblatt nicht entnehmen kann.

dankend Siro

Renegr
21.12.2011, 20:39
Hallo Siro,
sorry, wenn ich das Thema (auch) nochmal aufgreife. Wie hast du dein Problem denn gelöst?
Der Timer-IRQ Request ist ja noch nicht gelöscht, wenn die Funktion zurückkehrt. Laut dem letzten Satz "Another way to solve this problem is to carry out a dummy access to the peripheral, e.g. a read access to the same peripheral, to ensure that the previous write is completed before executing the interrupt return. " müsste also das gleiche Register hinterher nochmal ausgelesen werden, um wirklich sicher zu gehen, dass der IRQ-Request auch gelöscht ist. Ich habe jetzt schon viel Beispielcode gesehn, aber sowas nicht.

Gruß
René

Siro
25.12.2011, 14:00
Hallo Renegr,
vorab ein frohes Weihnachtsfest.

ich habe es so gelassen, wie im ersten Eintrag also

__asm("DSB"); /* Data Synchronization Barrier, !!! Write Buffer */

Dies stellt zumindest eine gewisse Zeit sicher, damit das Interrupt Flag wirklich gelöscht sein müste.
Ein erneutes Löschen des Interrupt-Flags geht aber auch, das habe ich ausprobiert.
also:

LPC_T3IR.bits.MR0INT = 1; /* Interrupt Bit loeschen */


gefallen tut mir so etwas aber nicht. Der Grund: Je nach Einstellungen des Compilers (Optimierung)
wird nämlich mehr oder weniger Code erzeugt, was sich natürlich in einer veränderten Laufzeit wiederspiegelt.


Ein wirklich "GUTE" Lösung habe ich somit noch nicht gefunden. Aber es funktioniert bei mir, auch mit verschiedenen Optimierungsstufen.

Ich find das schon sehr Schade, daß man sich nicht mehr hundertprozentig auf den Code verlassen kann, so schön und gut das mit den Write Puffern ja sein mag,
aber man hat keine hundertprozentige Kontrolle. Isser fertig oder noch nich ?? Vermutlich eine Zeile später schon.....oder doch nich......

Wenn es da andere Möglichkeiten gibt, bin ich für jede Info dankbar.
bis dann
Siro

Renegr
17.01.2012, 22:58
Hi,
naja wie richie bzw Joseph Yiu schreibt scheint die einzig sichere Variant wirklich zu sein, das Register nochmals auszulesen. Möglicherweise willst du deinen M3 mal hochtakten, er verträgt wohl bis 120MHz, dann könnte das "DSB" Timing doch wieder nicht mehr ausreichen.
Aber egal, welche Workarounds man braucht, ich find den M3 super. Das einzig traurige an meinem LPC1768 auf dem mbed ist, dass einfach zu wenige Pins nach draussen geführt sind und somit Port 3 und 4 gar nicht zur Verfügung stehen :(

Gruß
René

Siro
18.01.2012, 17:20
Hallo Rene,

Wenn ich den Prozesor hochtakte, vermute (hoffe) ich eigentlich nicht, dass es eine Änderung des Timings zur Folge hätte.
Ich vermute, dass die Read/Write Buffer irgendwie an den Takt gekoppelt sind. Aber das ist reine Spekulation,
zudem habe ich nicht vor den hochzutakten, der LPC1769 kann wohl von Hause aus 120 MHz.

Aber wenn "Joseph Yiu schreibt" lieber 2 mal "zugreifen" sagt, werd ich aus Sicherheitsgründen meine Software auch dahin gehend ändern.
Ich habe es leider noch nicht gefunden im "Definitive Guide" Wo steht denn das auf den 380 Seiten ? ich hab noch die erste Auflage von 2007.
Die Frage muss ich wohl an Richie1234 stellen.

Das ist ja Schade, daß sie beim "mbed" nicht alle Pins herausgeführt haben. Die RXD3+TXD3 kannst Du ja an Port 0 abgreifen und die beiden PWM1.2+PWM1.3 am Port 1,
aber wie ich eben sehe sind ja noch mehr Pins garnicht dran. 14 Pins mit RSTOUT fehlen wenn ich mich nicht verzählt habe.
Inzwischen habe ich aber eine eigene Hardware. Und Ja, ich bin auch begeistert vom CORTEX M3. Hab jahrelang mit den 18er PICs gearbeitet (gefummelt,gebastelt,optimiert).
Das sind "unbeschreibliche" Leistungsunterschiede, die ich nicht mehr missen möchte. Plötzlich habe ich Rechenzeit übrig und das ohne Optimierungen der Software .... :-)
Viel Spass wünsche ich Dir noch

Siro