PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : STM32 - Interrupts



White_Fox
30.10.2016, 19:35
Ave

Ich bin grad dabei, mich mal mit richtig mit Interrupts beim STm32 auseinander zu setzen.

Der STm32 hat ja keine interrupt-Vektoren mehr wie der AVR (wo der Interrupt zu einem Sprungbefehl führt, sondern springt die jeweilige Adresse direkt an.

Jetzt wollte ich mal gerne wissen wie ich das in C umsetze. Ich kann ja schlecht eine Adresse irgendwo in meinen Code reinknallen. Im Netz finde ich nur Beispiele mit der Standard-Bibliothek (die mir zudem auch nicht gerade einleuchten), ich arbeite aber nur mit den Registern. Hat da jemand vielleicht irgendein Beispiel?

RoboHolIC
30.10.2016, 20:21
Der STm32 hat ja keine interrupt-Vektoren mehr wie der AVR (wo der Interrupt zu einem Sprungbefehl führt, sondern springt die jeweilige Adresse direkt an.

Irgendwo muss doch der Ort der Service Routine bzw. deren Startadresse fix hinterlegt sein oder vom Programm bestimmt werden. Wie ist das denn im STm32 technisch gelöst? Ohne Adresssprung geht das doch irgendwie nicht, oder? Gibt es dort evtl. Register für die Sprungadressen anstelle der gewohnten im Code eingebetteten Sprungtabelle ?

Counterfeiter
30.10.2016, 21:13
Hallo,

um genau zu sein, möchtest du dich mit den Interrupts des CortexM auseinander setzen. Vielleicht hilft die Erkenntnis weiter?

Sehr nützlich ist es auch sich das startup file des CortexM anzuschauen:
https://github.com/Counterfeiter/ANN-QLearning-CortexM4/blob/master/Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc/startup_stm32f407xx.s

Oben mal ein Beispiel aus einem beliebigen Projekt. Die Datei ist ein Template und fast bei jedem Projekt gleich aufgebaut.

VG

Basti

Klebwax
31.10.2016, 10:47
Ich kenne den STM nicht, aber eine kurze Google-Suche bringt follgendes zu Tage


Derartige Funktionen sind als extern „C“ void zu deklarieren und besitzen fest vorgegebene Namen, die es dem Compiler ermöglichen, die ISR dem richtigen Interrupt zuzuordnen. Die Namen der Eventhandler folgen immer dem Muster Gerät_IRQHandler.

Und als Beispiel:

extern "C" void TIM7_IRQHandler() {

Thats it. Das entspricht dem, was ich von anderen CPUs so kenne. In einem der Systemheader steht dann mehr zum jeweiligen Symbol (hier xxx_IRQHandler) und in einem Linkerfile etwas zu den absoluten Adressen. Den realen Mechanismus der jeweiligen CPU muß man eigentlich nicht kennen, C ist ja nicht Assembler.

MfG Klebwax

White_Fox
31.10.2016, 18:03
@Klebwax:
Ich glaube, das von dir zitierte Beispiel kenne ich. Da wird mit der STL gearbeitet...das war der Grund, warum ich das nicht versucht habe nachzubauen.

Ich hab in der stm32f446xx.h nichts gefunden, was irgendwie nach Interrupthandler aussieht.

Counterfeiter
31.10.2016, 19:05
Wie gesagt, steht alles im startup-asm-file... Std-Perif. oder HAL-lib spielt keine Rolle.
Die Einsprungadressen sind dann im Linker-File absolut definiert.

botty
01.11.2016, 09:07
White_fox, deinen Interrupthandler zu definieren geht so:

Nehmen wir an du möchtest für dem TIM7 einen Handler schreiben.
In deinem Projektordner befindet sich die Datei "startup_stm32f44axx.s", ja genau "*.s", eine Assembler Datei.
In dieser Datei wird die Interrupt-Vektor-Tabelle definiert. Das ist eine Tabelle mit 96 Funktionszeigern vom Typ


void (*handler)(void);

Also kein Rückgabewert und keine Parameter.

Diese Namen, die in dieser Datei stehen, sind die Symbole die du suchst, für die du eine C-Funktion mit genau dem Namen einmal in deinem Code definieren mußt.
Für Timer 7 schreibst du z.B. in deine "main.c"


void TIM7_IRQHandler(void) {
/* dein Code */
}


Wie wird das jetzt aufgelößt beim Build?

Zuerst macht der Assembler aus der startup Datei eine Objekt-Datei. In dieser *.o steht jetzt in der Symboltabelle das Symbol "TIM7_IRQHandler". Das Besondere ist, dass dieses Symbol als schwach (weak) markiert ist.
Der Compiler übersetzt nun deine "main.c" und macht daraus "main.o". In der Symboltabelle dieser Datei befindet sich ebenfalls das Symbol "TIM7_IRQHandler" - aber - dieses ist _nicht_ als schwach makiert.
Jetzt baut der Linker aus beiden "*.o"-Dateien eine Datei zusammen und muss die Symbole auflösen. Dabei stösst er auf die Tatsache, dass es zweimal das Symbol "TIM7_IRQHandler" gibt. Normalerweise ist das ein Konflikt, der zu einem Fehler führt. Hier aber kommt die schwache Markierung aus der ersten Objektdatei ins Spiel: Das erste Symbol aus "startup_stm32f446xx.o" wird durch das Symbol aus deiner "main.o" ersetzt. Sprich deine Funktion überschreibt die schwächere Definition aus der "startup_stm32f446xx.s".

Für andere Handler schaust du in Zukunft in die Tabelle von "startup_stm32f446xx.s" rein, nimmst den Symbolnamen und schreibst dafür eine C-Funktion mit genau diesem Namen.

Gruss botty

White_Fox
05.11.2016, 20:43
Vielen Dank für die ausführliche Erklärung, botty. Das hat mir letzte Woche doch ein wenig was klarer werden lassen. .)