Hallo
Ich habe einen STM32F072RB auf einem Nucleo-Board und möchte damit einen
I2C-Bus belauschen.
Ich verwende die aktuelle Cube IDE.
Da die I2C Hardware kein Sniffing kann, wollte ich die Funktion mit
externen IRQs realisieren. Leider ist die Reaktionszeit sehr schlecht.
Die Clock-Config ist Standard, 48MHz für HCLK und APB1.
PB3 ist als GPIO_EXTI3, fallende Flanke, eingestellt.
Das ist mein IRQ Handler:
1
void EXTI2_3_IRQHandler(void)
2
{
3
/* USER CODE BEGIN EXTI2_3_IRQn 0 */
4
GPIOC->BSRR = GPIO_PIN_3;
5
[...]
6
}
Die Funktion wird direkt im Startup-Code ausgeführt. Der Debugpin wird
sofort ohne HAL gesetzt. Viel schneller sollte es eigentlich nicht mehr
gehen.
Wenn ich die Zeit zwischen fallender Flanke und der Rekation des
Debugpins mit einem Logic 16 ausmesse, beträgt die Rekationszeit 3us.
Erwartet hätte ich <1us.
Es ist leider schon eine Weile her, dass ich programmiert habe.
Hat jemand noch ein paar Tips, was die Verzögerung auslösen könnte?
Vielen Dank,
Tilo L. schrieb:> die Rekationszeit 3us.> Erwartet hätte ich <1us.
Nö. Die 3µs sind ungefähr richtig für einen 48MHz Cortex-M0 Core.
Ich habe die Zahen nicht komplett im Kopf, aber ein Cortex-M3 braucht
min 12 Takte für Interrupt Entry. Cortex-M0 kann dabei nicht den Stack
Frame geleichzeitig zum Code Fetch aufsetzen und brauch daher deutlich
mehr Takte.
Falls nach dem BSRR Schreibzugriff noch Code folgt, wird der Compiler
vorher noch ein paar Register am Funktionsanfang pushen. Das ist dann
der Rest der 3µs.
Tilo L. schrieb:> Es ist leider schon eine Weile her, dass ich programmiert habe.
Es ist leider schon eine Weile her dass Mikrocontroller mit
48 MHz Core Takt zu den schnellsten ihrer Art gehören.
Ein STMF030 würde selbst mit Debug-Kompilat (gcc) unter 1µs bleiben.
Läuft dein STM32 wirklich mit 48MHz? Bei 8MHz-Standardfrequenz und einem
Release-Kompilat wären nämlich deine 3µs realistisch.
Danke für den Hinweis.
Ich hab nochmal nachgeschaut.
Es wird die HSI48 verwendet, welche mit 48MHz läuft. Die Prescaler sind
alle auf /1 gesetzt.
Ich habe die Einstellungen von Cube MX im Code geprüft, das scheint zu
passen.
Zum Compilieren verwende ich die Standard-Debugeinstellungen, -g3 und
-O0.
Die Interrupt-Latency bei M0 bzw. M0+ beträgt (*inkl.* Stacking) 16 bzw.
15 Takte. Dazu kommen noch Wait-Zyklen beim Flash. Bei asynchronen
Eingängen
muss man noch einige Takte für die Synchronisationslogik einkalkulieren,
aber insgesamt kommt man wohl kaum über 30 Takte hinaus, selbst bei
vielen Wait-Zyklen. Das ist die interne Reaktionszeit.
Bis das Setzen des GPIO-Pins aber außen ankommt, kann es ein ganzes
Weilchen dauern, einfach nach dem Setzen noch ein Rücksetzen hinterher
und mal messen ... Das hat ARM wohl selbst gemerkt und deshalb beim M0+
den IOPORT-Bus drangestrickt.
Tilo L. schrieb:> Zum Compilieren verwende ich die Standard-Debugeinstellungen, -g3 und> -O0.
-O0 heißt, der MC läuft mit Bremse und Wurfanker.
Als Standard nimmt man -Os.
Du hast schon recht, mit -O0 wird nichts optimiert. Das sollte hier aber
nicht das Problem sein.
Ich habe heute überprüft, ob die Taktrate stimmt.
Dafür habe ich einfach einen GPIO Wackeln in main() lassen:
1
Trigger_GPIO_Port->BSRR = Trigger_Pin; // Set debug pin
Der Flash läuft bei 48MHz mit einem Waitstate. Damit komme ich auf
6Zyklen. Bei 48MHZ komme ich damit auf 125ns.
Das passt genau zu dem, was ich mit dem Logicanalyzer messe.
Wenn ich den Code in den IRQ kopiere, bleibt das Disassembly gleich. Die
gemessene Zeit vergrößert sich aber auf 750ns.
Es sieht so aus, also ob der IRQ um Faktor 6 langsamer ist, also nur
noch mit 8MHz läuft. Das würde zu dem passen, was Daniel geschrieben
hat.
Ich habe das Register RCC_CFGR geprüft. Beim Start ist HSI48 ausgewählt,
im IRQ plötzlich HSI.
So richtig erklären kann ich mir das leider noch nicht.
Ich habe das Board auch und das mal nachgebaut. PB3 für den EXTI, PB4 um
den auszulösen und PB5 als Ack Signal. Das kommt 0,66 µs nach dem
Triggersignal.
https://github.com/JojoS62/NucleoG071RB-Test/tree/master
Ich denke das hat nicht mit dem ISR Code zu tun. Wie wird das Signal bei
dir generiert? Flanke steil genug? Ich habe PB4 auf OutputSpeed 'Very
High' gestellt.
Wenn I2C Signale triggern sollen, dann können die Flanken schon
langsamer sein. Dann sind Port C Pins teilweise etwas anders, könnte
auch einen Unterschied machen.
Release und Debug Build machte auch keinen Unterschied.
Bei 64 MHz Clock sind es 578 ns.
Und nochmal PC3 als Ack Signal:
Output freq low: 688 ns
Output freq very high: 664 ns
Also einen Tick schneller durch die steilere Flanke, aber nicht im µs
Bereich. Auch PC3 verhält sich da nicht anders.
Trigger und Ack auf freq. low: 700 ns
PB3 ohne Pullup: 702 ns
Ich schaffe die µs einfach nicht...
Tilo schrieb:> Du hast schon recht, mit -O0 wird nichts optimiert. Das sollte hier aber> nicht das Problem sein.
Trotzdem schadet es nicht, das mal kurz mit -Os zu compilieren und
gegenzuprüfen.
Hinweise, die gegen die eigene Überzeugung laufen, einfach rauszufiltern
und abzutun, wäre hier falsch. Du suchst Hilfe im Forum, um eine andere
Meinung zu hören. Bringt aber nichts, wenn Du diese nicht wenigstens
testest.
Frank M. schrieb:> Trotzdem schadet es nicht, das mal kurz mit -Os zu compilieren und> gegenzuprüfen.
das ist richtig, zumal das Umschalten in der IDE nur ein Klick ist.
Release kompiliert als Voreinstellung mit -Os, Debug mit -O0.
Ich hatte das ja gemacht und es gab keinen Unterschied. Es war zu
erwarten, aber testen ist immer besser.
EXTI2_3_IRQHandler ist der echte nackte IRQ Handler, kein HAL Code
dazwischen der einen Callback aufruft.
Tilo schrieb:> Ich habe heute überprüft, ob die Taktrate stimmt.> Dafür habe ich einfach einen GPIO Wackeln in main() lassen:
Das geht noch einfacher und eleganter: Der Controller hat einen Ausgang
MCO auf den der Sysclk gelegt werden kann, incl. einstellbaren Teiler.
MCO wird in CubeMX in RCC aktiviert, in den Clockeinstellungen kann
ausgewählt werden welcher Takt da ausgegeben werden soll. Default ist
allerdings PF2 was auch NRST ist, das kann aber auf PA8 oder PA9
umkonfiguriert werden.
Der TO scheint beschäftigt zu sein und außerdem hat er die Ursache
(praktisch) schon gefunden:
Tilo schrieb:> Ich habe das Register RCC_CFGR geprüft. Beim Start ist HSI48 ausgewählt,> im IRQ plötzlich HSI.
Ich erlaube mir deshalb mal eine Zwischenfrage an jojos:
Wo gibt es bei deinen Meßwerten ein Problem? Deine 702ns entsprächen
0.94µs bei f=48MHz und damit wäre das Ziel erreicht. Ich stehe da auf
dem Schlauch.
Daniel V. schrieb:> Wo gibt es bei deinen Meßwerten ein Problem?
ich sehe kein Problem, die Zeiten sind auch alle bei 48 MHz gemessen,
bis auf den einen Wert bei 64 MHz.
Das es beim TO langsamer läuft muss eine andere Ursache haben,
möglicherweise schlappe Signalflanken wenn da noch seine I2C Hardware
mitspielt.
Ich hatte ein minimales CubeMX generiertes Projekt das ich für den Test
genommen habe.
Oder der TO hat einen Sleep Mode aktiv? Die Taktquelle verstellt sich
doch auch nicht von alleine, da muss doch etwas im Code sein was das
macht.
Bei einem STM32F042 Nucleo Board mit 48 MHz Systemtakt ohne Benutzung
der HAL und dem EXTI0_1 Interrupt Handler im SRAM ist die Reaktionszeit
ca. 626 ns (30 Taktzyklen).
Das externe Signal liegt an PB0 (10 Hz Rechteck), im Interrupt Handler
wird ein kurzer Impuls an PB4 erzeugt, das Ausmessen des Timing erfolgt
mit einem Oszilloskop.
Die gemesse Impulsbreite ist ca. 148 ns (7 Taktzyklen), der Code ist
nicht optimiert, der Anfang des Interrupt Handler sieht so aus:
1
isr_EXTI0_1
2
3
PUSH {R7,LR}
4
ADD R7, SP, #0
5
6
LDR R3, =0x48000418 ; PB4 High
7
MOVS R2, #0x10
8
STR R2, [R3]
9
10
NOP
11
12
LDR R3, =0x48000418 ; PB4 Low
13
MOVS R2, #0x100000
14
STR R2, [R3]
Der "NOP" ist bewusst per Inline-Assembler eingefügt.
Vielen Dank für eure Antworten.
Wie bereits geschrieben hab ich bereits etwas gefunden, nämlich das vom
HSI48 auf HSI umgeschaltet wird.
Das Projekt wurde nur per Cube MX erzeugt. Eigenen Code bis aufs
Portwackeln hab ich bisher keinen drin.
Das komplette Projekt wollte ich hier nicht posten, weil die Sachen
einfach zu groß sind.
Es ist in Cube MX einfach was zusammenzuklicken aber schwer
herauszufinden, wenn dann etwas schief läuft.
Was ich bereits herausgefunden habe ist, dass wenn USB nicht aktiv ist,
der Takt nicht auf HSI gewechselt wird. Für mehr hatte ich bisher keine
Zeit.
An den USB Pins ist bisher nichts angeschlossen. Eines der Features
dieses uC ist, dass USB ohne Quarz funktioniert. Dafür wird der SOF mit
1ms Periode verwendet.
Mein Verdacht ist, dass dies nicht funktioniert, weil USB nicht
verbunden ist. Da ich im Code nichts gefunden habe das absichtlich
umschaltet vermute ich, dass das Clock Recovery System hier die Finger
mit drin hat.
Im Reference Manual habe ich bisher nichts gefunden, dass auf so etwas
schließen lässt.
Das wollte ich als nächstes untersuchen und die Ergebnisse mitteilen.
Tilo schrieb:> Es ist in Cube MX einfach was zusammenzuklicken aber schwer> herauszufinden, wenn dann etwas schief läuft.
Das war auch mein erster Eindruck.
Da ich nicht die Zeit und Lust habe, mich ernsthaft in die HAL
einzuarbeiten, habe ich für mich beschlossen, sie lieber nicht zu
verwenden. Mir reicht das Reference-Manual, das ist schon komplex genug.
Die Nutzung der HAL entbindet einen ja nicht davon, das Reference-Manual
zu lesen und zu verstehen - auch wenn das einige gerne so hätten.
Würde ich in dem Bereich beruflich tätig sein, dann würde ich mir die
nötige Zeit nehmen.
Tilo schrieb:> Was ich bereits herausgefunden habe ist, dass wenn USB nicht aktiv ist,> der Takt nicht auf HSI gewechselt wird. Für mehr hatte ich bisher keine> Zeit.>> An den USB Pins ist bisher nichts angeschlossen. Eines der Features> dieses uC ist, dass USB ohne Quarz funktioniert. Dafür wird der SOF mit> 1ms Periode verwendet.> Mein Verdacht ist, dass dies nicht funktioniert, weil USB nicht> verbunden ist. Da ich im Code nichts gefunden habe das absichtlich> umschaltet vermute ich, dass das Clock Recovery System hier die Finger> mit drin hat.>> Im Reference Manual habe ich bisher nichts gefunden, dass auf so etwas> schließen lässt.> Das wollte ich als nächstes untersuchen und die Ergebnisse mitteilen.
Naja, schon, da steht ausdrücklich in 6.2.3, dass der HSI48 primär für
USB vorgesehen ist. Wenn also USB vorgesehen, aber nicht angeschlossen
ist, überrascht es kaum, das der HSI48 aus dem Takt kommt. Und dass die
nette, aber stellenweise undurchsichtige HAL da "überschlau" ist, und
auf das Abdriften hin einfach die Reißleine zieht.
Vmtl. wird da AUTOTRIMEN im CRS_CR gesetzt und einer der Interrupts
scharf gemacht. Da müsste man im Map-File den Interrupt-Handler für
RCC_CRS finden können, wahrscheinlich setzt der auf HSI zurück.
Tilo schrieb:>> Wie bereits geschrieben hab ich bereits etwas gefunden, nämlich das vom> HSI48 auf HSI umgeschaltet wird.
Der STM32F042 hat ebenfalls den HSI48. Wenn ich bei mir die 48 MHz
anstelle aus dem HSI und der PLL direkt mit dem HSI48 erzeuge
funktioniert das genauso, die Zeiten beim EXTI sind wie weiter oben
beschrieben.
Kann es sein dass bei Dir die CPU in den Standby geht? Nach dem
Aufwachen, z.B. durch den EXTI, läuft die CPU mit 8 MHz weil beim
Standby die Clock abgeschalten wurde. Das hat aber nichts mit dem HSI48
zu tun, bei HSI und PLL ist das genauso.