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?
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
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?
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 ;)
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
Setze mal: #define VECTORTABLE_ALIGN (0x100ul) auf: #define VECTORTABLE_ALIGN (0x200ul) Gruß, Stefan
Mal eine ernste Frage. Warum macht man sowas? Lerne ja gerne dazu.
ein Switch-Case in der ISR ist wohl zu trival, oder ? Da müsste man ja nur ne Variable ändern statt einer Sprungadresse.
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.
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.
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.
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.
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.
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
> #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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.