Forum: Mikrocontroller und Digitale Elektronik STM32: Interrupt zu langsam


von lars (Gast)


Angehängte Dateien:

Lesenswert?

Ich entwickle ein Projekt auf einem Nucleo STM32F722 und möchte auf eine 
fallende Flanke an einem bestimmten Eingangspin reagieren. Dazu habe ich 
einen Interrupt und einen Handler angelegt.
1
static void MX_GPIO_Init(void)
2
{
3
  // ...
4
  GPIO_InitStruct.Pin = GPIO_PIN_1;
5
  GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
6
  GPIO_InitStruct.Pull = GPIO_NOPULL;
7
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
8
}
9
10
void EXTI1_IRQHandler(void)
11
{
12
  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
13
14
  // check something (required)
15
  if ((GPIOA->IDR & 0x00f0) != 0x0070)
16
    return;
17
18
  // signal start of handler (for scope)
19
  GPIOE->BSRR = 0x0001;
20
21
  // ...
22
}

Der STM32F722 läuft mit 128 MHz (siehe Clock Config im Anhang).

Im Oszilloskop sieht man, daß zwischen Flanke und ausgelöstem Signal 0,7 
us vergehen. Das halte ich für viel zu lang - da wäre Pollen ja 
schneller.

Gibt es eine Möglichkeit, den Handler zu beschleunigen? Bspw. spart die 
Verwendung von BSRR gegenüber HAL_GPIO_WritePin 0,2-0,3 us ein.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

lars schrieb:
> Bspw. spart die Verwendung von BSRR gegenüber HAL_GPIO_WritePin 0,2-0,3
> us ein.

Wie siehts mit der Ersetzung von
1
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);

aus?

von (prx) A. K. (prx)


Lesenswert?

lars schrieb:
> Bspw. spart die
> Verwendung von BSRR gegenüber HAL_GPIO_WritePin 0,2-0,3 us ein.

Man kann lange drüber streiten, ob so ein HAL im Normalfall den Job 
vereinfacht oder nicht. Aber in zeitkritischem Code hat sowas nichts 
verloren, wenn es nicht bloss Makros sind, aus denen am Ende der gleiche 
Code rauskommt.

: Bearbeitet durch User
von disasm (Gast)


Lesenswert?

Zeig doch mal den die relevante Ausgaben von objdump..

von lars (Gast)


Lesenswert?

Das __HAL_GPIO_EXTI_CLEAR_IT ist nur ein Makro für (EXTI->PR = 
(_EXTI_LINE_)), also wohl schnell.

Das die HAL langsam ist, ist mir klar, darum verwende ich sie ja auch 
nicht im Handler. Dennoch ist der Interrupt zu langsam.

Welche Ausgaben von objdump sind denn relevant? Oder willst Du letztlich 
den generierten Assembler-Code?

Ist die Clock Config denn korrekt, oder benötigt APB1 einen höheren 
Takt?

von Olli (Gast)


Lesenswert?

lars schrieb:
> Der STM32F722 läuft mit 128 MHz (siehe Clock Config im Anhang).
>
> Im Oszilloskop sieht man, daß zwischen Flanke und ausgelöstem Signal 0,7
> us vergehen. Das halte ich für viel zu lang - da wäre Pollen ja
Das wären ca. 90 Takte. An welchem APB hängt der GPIO?
Die APB können m.E. nicht mit dem Core-Takt laufen. ich weiß aber auch 
nicht über welchen Weg der Interrupt gemeldet wird.

von (prx) A. K. (prx)


Lesenswert?

lars schrieb:
> Welche Ausgaben von objdump sind denn relevant? Oder willst Du letztlich
> den generierten Assembler-Code?

Es geht um den Code des Handlers, zumindest bis zum Messpunkt.

> Ist die Clock Config denn korrekt,

Messen?

: Bearbeitet durch User
von Andreas M. (amesser)


Lesenswert?

- Laut STM erreicht man die 12 Zyklen ISR Latenz nur dann wenn man ITCM 
und DTCM benutzt.
- Gemischte Zugriffe auf Device Memory (also auf Peripherien) können 
extrem teuer werden, weil der vorherige Zugriff zuerst ausgeführt werden 
muss bevor der nächste Zugriff gemacht werden kann, da die CPU 
Seiteneffekte nicht kennt. Hier bringt dich die längere Pipeline um 
deine Takte. Du machst WRITE, READ, WRITE. Ich vermute es wäre besser 
wenn du zuerst GPIOA->IDR in eine lokale variable liest, dann den 
Interrupt bestätigst, dann die if prüfung mit der variable und dann den 
write auf die GPIO. (READ, WRITE, WRITE). Man kann da wohl mit der MPU 
was machen.
- Sind Caches aktiviert?

von lars (Gast)


Lesenswert?

*TCM ist ein sehr guter Hinweis, sonst laufe ich ja mit 4 Wait States 
(wobei 120 MHz geschickter als 128 MHz wären).

Deine Hinweise bzgl. GPIO-Zugriff sind auch sehr praktisch.

Aber selbst im optimalen Fall halte ich 12 Zyklen (das sind ca. 94 ns) 
für mich für etwas zu viel. Mit Polling
1
while (GPIOE->IDR & 0x0002);

schaffe ich das geschätzt in 3-4 Zyklen (und PE1 bleibt hinreichend 
lange aktiv).

von Jim M. (turboj)


Lesenswert?

lars schrieb:
> Mit Polling
> while (GPIOE->IDR & 0x0002);
>
> schaffe ich das geschätzt in 3-4 Zyklen (und PE1 bleibt hinreichend
> lange aktiv).

Aber nur wenn keine Interrupts auftreten. Und wenn der externe Trigger 
ausbleibt, dann hängt das Programm an der Stelle fest.

Das gehört für mich in die Kategorie: "Spätere Kundenwünsche werden von 
der Rechtsabteilung bearbeitet." SCNR ;-)


Welches Problem wolltest Du eigentlich lösen? Eventuell sind 
Capture-Timer oder getriggertes DMA eine bessere Variante. Bei komplexen 
µC lagert man (echt-)zeitkritisches lieber an spezialisierte Hardware 
aus.

von lars (Gast)


Lesenswert?

Jim M. schrieb:
> Aber nur wenn keine Interrupts auftreten. Und wenn der externe Trigger
> ausbleibt, dann hängt das Programm an der Stelle fest.

Das wäre in meinem Fall OK, da das Programm sonst nichts zu tun hat.

> Welches Problem wolltest Du eigentlich lösen?

Ich möchte (zumindest experimentell) einen ca. 2 MHz Bus bedienen, also 
für bestimmte Adressen einen berechneten Wert zurückliefern. Der Read 
Enable löst den Interrupt aus, dann muß ich aber noch auf die Adresse 
prüfen.

Natürlich bietet sich dafür ein FPGA an, ich will aber schauen, ob ein 
STM32 auch dafür geeignet ist. Ein F1/F2 wäre eigentlich ausreichend, 
aber ich benötige den FMC des F7.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Hast Du Dir den FMC angeschaut?

von lars (Gast)


Lesenswert?

Uwe B. schrieb:
> Hast Du Dir den FMC angeschaut?

Nur grob bisher, wieso?

von Olli (Gast)


Lesenswert?

lars schrieb:
> Ich möchte (zumindest experimentell) einen ca. 2 MHz Bus bedienen, also
> für bestimmte Adressen einen berechneten Wert zurückliefern. Der Read
> Enable löst den Interrupt aus, dann muß ich aber noch auf die Adresse
> prüfen.
Das wollte ich auch schonmal machen (Z80-Bus). Ich habe mich dann damit 
begnügt einen Bussniffer zu haben, der blockweise scannt und das 
Ergebnis auf dem Display darstellt.
Möglicherweise wäre was gegangen, wenn mit /WAIT arbeitet.
Hier scheint der FPGA-Einsatz gerechtfertigt.
Ein Controller mit integrierter parametrierbarer PIO wäre was...

von (prx) A. K. (prx)


Lesenswert?

lars schrieb:
> Ich möchte (zumindest experimentell) einen ca. 2 MHz Bus bedienen, also
> für bestimmte Adressen einen berechneten Wert zurückliefern. Der Read
> Enable löst den Interrupt aus, dann muß ich aber noch auf die Adresse
> prüfen.

Da wär ausnahmsweise ein oller ARM7/ARM9 im Verteil (oder ganz andere 
Architekturen). Die Cortex-M haben zwar eine deutliche Optimierung bei 
Interrupts vorzuweisen, aber gegen den separaten halben Registersatz der 
FastIRQs der klassischen ARMs sind sie chancenlos.

: Bearbeitet durch User
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.