Forum: Mikrocontroller und Digitale Elektronik STM32 - ISR während Laufzeit verändern


von ui (Gast)


Lesenswert?

Hallo,

ich möchte gerne eine Interrupt Service Routine während der Laufzeit 
ändern (also die aufgerufene Funktion dafür). Leider finde ich keine 
Beispiele wie das gemacht wird. Ein ehemaliger Arbeitskollege hat mir 
das mal erzählt, dass das bei den STM32F4 kein Problem ist. Kann mir 
jemand helfen was ich dazu machen muss?

von Oliver J. (skriptkiddy)


Lesenswert?

Wenn ich mich recht entsinne, kann die Interrupt-Vector-Table bei den 
Teilen irgendwo im Speicher liegen und man gibt beim Setup im NVIC an, 
wo die Addresse der Tabelle liegt. Wenn man also dafür sorgt, dass die 
Tabeele im Ram liegt, dann müsste man auch die Vektoren zur Laufzeit 
anpassen können.

Spontan hab ich zum legen der Tabelle in den RAM folgendes Beispiel 
gefunden:
Beitrag "Re: STM32 -> NVIC-Setup -> Vector Table".

Grüße Oliver

von ui (Gast)


Lesenswert?

Danke erstmal für die Info
1
#define VECTORTABLE_SIZE            (256)
2
#define VECTORTABLE_ALIGN           (0x100ul)
3
uint32_t *vectorTable_ROM = (uint32_t)0x00000000;
4
static uint32_t vectorTable_RAM[VECTORTABLE_SIZE] __attribute__(( aligned (VECTORTABLE_ALIGN)));
5
6
    for(uint32_t i = 0; i < VECTORTABLE_SIZE; i++){
7
        vectorTable_RAM[i] = *vectorTable_ROM;
8
        vectorTable_ROM++;
9
    }
10
    vectorTable_RAM[16] = (uint32_t)myotherisr;
11
    vectorTable_RAM[15] = (uint32_t)donothing;
12
    vectorTable_RAM[11] = (uint32_t)donothing;
13
    __disable_irq();
14
    __DSB();
15
    SCB->VTOR = (uint32_t)&vectorTable_RAM;
16
    __enable_irq();

Das ist mein aktueller Code, die Idee hab ich von hier 
https://www.keil.com/pack/doc/CMSIS/Core/html/using_VTOR_pg.html.
Problem: Es geht nicht. Ich ändere zwar die Tabellenaddresse, aber es 
scheint als hätte irgendwas nicht funktioniert.
Ich möchte folgende Interrupts verbiegen:
Systick_handler
PendSV_Handler
SVC_Handler

hat noch jemand nen Tipp?

von Mike (Gast)


Lesenswert?

Warum nicht über die "normale" ROM Isr einfach über function pointer und 
jump table in die jeweilige gewünschte Funktion springen? Sind max. ein 
paar Befehle mehr aber man kann zB Probleme leichter debuggen ;)

von Stefan K. (stefan64)


Lesenswert?

Das sieht alles richtig aus, bis auf die Adresse der ROM Vektortabelle:

uint32_t *vectorTable_ROM = (uint32_t)0x00000000;

Das sollte meiner Meinung nach 0x08000000 sein.

Ach ja, und die RAM-Vektortabelle muss an einer 512-Byte-Grenze liegen, 
weil die unteren 9 Bit von VTOR hardwaremässig 0 sind.

Gruß, Stefan

von Stefan K. (stefan64)


Lesenswert?

Setze mal:

#define VECTORTABLE_ALIGN           (0x100ul)

auf:

#define VECTORTABLE_ALIGN           (0x200ul)

Gruß, Stefan

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Du musst Bit 29 im VTOR setzen, wo codiert ist, dass die Tabelle im SRAM 
ist (sh. ARM docs).

von Nico W. (nico_w)


Lesenswert?

Mal eine ernste Frage. Warum macht man sowas? Lerne ja gerne dazu.

von lame no fame (Gast)


Lesenswert?

ein Switch-Case in der ISR ist wohl zu trival, oder ?
Da müsste man ja nur ne Variable ändern statt einer Sprungadresse.

von Vincent H. (vinci)


Lesenswert?

Ruediger A. schrieb:
> Du musst Bit 29 im VTOR setzen, wo codiert ist, dass die Tabelle
> im SRAM
> ist (sh. ARM docs).

Das geschieht automatisch, da das RAM auf Adresse 0x2000 0000 liegt. 
Wichtig ist auch, dass man das entsprechende Alignment einhält.

"When setting TBLOFF, you must align the offset to the number of 
exception entries in the vector table. The minimum alignment is 32 
words, enough for up to 16 interrupts. For more interrupts, adjust the 
alignment by rounding up to the next power of two. For example, if you 
require 21 interrupts, the alignment must be on a 64-word boundary 
because the required table size is 37 words, and the next power of two 
is 64. See your vendor documentation for the alignment details of your 
device."

Rein rechnerisch entspricht das nötige Alignment somit quasi:
1
pow2(log2(anzahl_an_vektoren)) * 4

Bevor man ins RAM wechselt sollte man sicher stellen, dass entweder
- alle Interrupts global abgedreht sind
oder
- alle potentiellen Vektoren bereits angelegt wurden

Springst du munter ins RAM und es ist etwa der SysTick aktiv, ohne dass 
du einen entsprechenden Vektor gesetzt hast, dann krachts natürlich.

von m.n. (Gast)


Lesenswert?

Nico W. schrieb:
> Mal eine ernste Frage. Warum macht man sowas? Lerne ja gerne dazu.

Man braucht es, wenn man dynamisch andere Programme/Funktionen z.B. von 
einer Speicherkarte nachladen und ausführen möchte. Beim STM32 ist das 
durchaus möglich.

Bei einem älteren µC mit wenig internem RAM hatte ich die Vektoren im 
RAM zu liegen. Bei der Initialisierung packten sich ISRs automatisch ins 
RAM, solange Platz vorhanden war. Der Rest blieb im ROM und konnte daher 
nicht so schnell laufen. Je nach verwendeter Bibliothek wurde das RAM 
unterschiedlich belegt, wobei die 1. installierte ISR mit höchster 
Priorität ins interne RAM kam.

von Dr. Sommer (Gast)


Lesenswert?

Nico W. schrieb:
> Mal eine ernste Frage. Warum macht man sowas? Lerne ja gerne dazu.

Wenn man einen Bootloader programmieren möchte, der komplett im RAM 
laufen soll, um gleichzeitig den Flash beschreiben und andere Dinge (zB 
kommunizieren) tun soll.

von Nico W. (nico_w)


Lesenswert?

Danke für die Antworten. Da muss ich mich mal reinlesen.

von ui (Gast)


Lesenswert?

Danke für die Antworten. Irgendwas scheint noch nicht zu funktionieren, 
aber das krieg ich jetzt auch noch hin...

Zum Einsatz: Ich muss Third-Party Code integrieren (OS). Der nutzt den 
Systicker (inkl. eigener Interruptfunktion), ich habe aber in meinen 
Initialisierungen Delays drinnen. Da ich nicht meinen ganzen Code 
umstellen will und die Timer shcon alle in Benutzung sind, will ich zum 
während des startups den Systick Interrupt umbiegen. Da ich den Third 
Party Code nicht ändern darf/will/kann, ist mir das als Lösung 
eingefallen.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

ui schrieb:
> Danke für die Antworten. Irgendwas scheint noch nicht zu funktionieren,
> aber das krieg ich jetzt auch noch hin...
>
> Zum Einsatz: Ich muss Third-Party Code integrieren (OS). Der nutzt den
> Systicker (inkl. eigener Interruptfunktion), ich habe aber in meinen
> Initialisierungen Delays drinnen. Da ich nicht meinen ganzen Code
> umstellen will und die Timer shcon alle in Benutzung sind, will ich zum
> während des startups den Systick Interrupt umbiegen. Da ich den Third
> Party Code nicht ändern darf/will/kann, ist mir das als Lösung
> eingefallen.

Mit dem Umlegen der IVT ins RAM gibt es eigentlich keine Probleme, und 
der Code ist recht straightforward. Warum es trotzdem nicht klappt, ist 
zweifellos ein Detailproblem. Sieh mal auf 
http://www.springer.com/de/book/9783658148492 - Zusatzmaterial, da sind 
gezippt und für Jedermann/frau kostenlos downloadbar Codebeispiele drauf 
(Kapitel 9/Bootloader benutzt genau diesen Mechanismus).

Für deine Problemstellung kannst Du auch mal zum Stichwort FBP gockeln. 
Der Cortex Core hat nämlich einen Patchmechanismus bereits integriert. 
Wenn Du die Möglichkeit hast, direkt an der main() anzusetzen, kannst Du 
da ansetzen und den Code patchen, bevor der SysTick Handler anfängt zu 
laufen.

von Felix F. (wiesel8)


Lesenswert?

ui schrieb:
> Danke für die Antworten. Irgendwas scheint noch nicht zu funktionieren,
> aber das krieg ich jetzt auch noch hin...
>
> Zum Einsatz: Ich muss Third-Party Code integrieren (OS). Der nutzt den
> Systicker (inkl. eigener Interruptfunktion), ich habe aber in meinen
> Initialisierungen Delays drinnen. Da ich nicht meinen ganzen Code
> umstellen will und die Timer shcon alle in Benutzung sind, will ich zum
> während des startups den Systick Interrupt umbiegen. Da ich den Third
> Party Code nicht ändern darf/will/kann, ist mir das als Lösung
> eingefallen.

Der SysTick(ISR) des OS muss in deiner Vektortabelle festgelegt. D.H. du 
könntest auch weiterhin deinen SysTick aufrufen und von dort auch 
entsprechend steuern, was wann und wie aufgerufen wird. Das wäre die 
quick & dirty Lösung.

Alternativ könntest du es auch sauber machen und das OS zuerst 
hochstarten und die ganzen Initialisierungen dort in Tasks durchführen, 
wodurch die Delays vom OS sauber gemanaged werden ohne das System zu 
blockieren.

Aber Softwaredesign scheint heute niemanden mehr zu interessieren, da 
sucht man sich lieber grässliche Workarounds die nicht mal wie gewünscht 
funktionieren und nur Probleme machen...

mfg

von Steffen R. (steffen_rose)


Lesenswert?

> #define VECTORTABLE_ALIGN           (0x100ul)

Tendenziell würde ich auf 0x200 tippen. Kommt natürlich af das jeweilige 
Derivat drauf an.

> Das ist mein aktueller Code, die Idee hab ich von hier
> https://www.keil.com/pack/doc/CMSIS/Core/html/using_VTOR_pg.html.
> Problem: Es geht nicht. Ich ändere zwar die Tabellenaddresse, aber es
> scheint als hätte irgendwas nicht funktioniert.
> Ich möchte folgende Interrupts verbiegen:
> Systick_handler
> PendSV_Handler
> SVC_Handler

Falls du die CMSIS nutzt, prüfe am besten, ob sie tut, was du erwartest. 
Hier wird teilweise zwischen Trap und Interrupt unterschieden.

Teilweise wird im startup code speziell OS Thrd Party Code auch an der 
vector table Adresse herumgeschraubt. Insofern wäre zu prüfen, ob deine 
Änderungen erhalten bleiben.

> hat noch jemand nen Tipp?
Wenn du konkreter beschreiben würdest, was nicht geht...

von ui (Gast)


Lesenswert?

Hatte gestern keine Zeit mehr zu antworten:
Es funktioniert jetzt alles, ich hatte gestern noch ein paar krude 
Probleme mit dem Debugger...
Aber jetzt macht er genau das was ich will :)
Danke an alle hilfreichen Antworten, man kriegt ja doch (wenn es auch 
immer nur ein Teil der Antworten ist) vernünftige Antworten.

Felix F. schrieb:
> Der SysTick(ISR) des OS muss in deiner Vektortabelle festgelegt. D.H. du
> könntest auch weiterhin deinen SysTick aufrufen und von dort auch
> entsprechend steuern, was wann und wie aufgerufen wird. Das wäre die
> quick & dirty Lösung.
>
> Alternativ könntest du es auch sauber machen und das OS zuerst
> hochstarten und die ganzen Initialisierungen dort in Tasks durchführen,
> wodurch die Delays vom OS sauber gemanaged werden ohne das System zu
> blockieren.
>
> Aber Softwaredesign scheint heute niemanden mehr zu interessieren, da
> sucht man sich lieber grässliche Workarounds die nicht mal wie gewünscht
> funktionieren und nur Probleme machen...

Ich finde es vom Softwaredesign überhaupt nicht schön das OS zu starten 
bevor die Hardware (alles) richtig funktioniert. Auch ist die 
Fehlerbehandlung dann einfacher.
Ich finde den Workaround überhaupt nicht grässlich. Auch Kollegen von 
mir finden das nicht grässlich, und die müssen das pflegen wenn ich 
nicht mehr da bin.
Zu guter letzt ist es auch so, dass Softwaredesign im gesamten Kontext 
betrachtet werden muss. Da ich den aber nicht offenlegen kann/darf, 
kannst du überhaupt nicht beurteilen ob das in diesem Szenario gut so 
ist. (Das war einer der Kommentare, auf die man getrost verzichten 
kann!)

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.