pendsv_isr,// 14 38 Pendable request for system service
34
systick_isr,// 15 3c System tick timer
35
{
36
[__extension__0...111]=crash,
37
[PVD_PVM_IRQn]=pvd_isr,// PVD thru EXTI line detection
38
[UART0_IRQn]=uart0_isr,
39
[UART1_IRQn]=uart1_isr,
40
[UART2_IRQn]=uart2_isr,
41
[UART3_IRQn]=uart3_isr,
42
[UART4_IRQn]=uart4_isr
43
}
44
};
Also so geht es schon mal nicht. Und ohne die #pragma geht es noch
schlechter. Aber wirklich übel ist die Warnung, obwohl ich _extension_
dazu schreibe:
1
warning: ISO C forbids specifying range of elements to initialize
ISO C meint also, ich sollte über 100 mal crash schreiben? Damit man
dann die uart_isr mittendrin nicht wiederfindet?
Wie macht ihr das?
Das Linker Skript ist der entscheidende Teil, und den haste natürlich
nicht gepostet. So kann das nicht tun.
Bauform B. schrieb:> warning: ISO C forbids specifying range of elements to initialize
Was haste denn als C-Dialekt eingestellt? Ich verwende i.d.R. -std=gnu99
oder -std=gnu11 je nach GCC Version. Ohne das "gnu" sind Extensions
nicht aktiv IMHO (oder erzeugen Warnings).
Jim M. schrieb:> Das Linker Skript ist der entscheidende Teil, und den haste natürlich> nicht gepostet. So kann das nicht tun.
??? Hier geht's doch um C-Syntax oder maximal -Semantik ???
> Was haste denn als C-Dialekt eingestellt? Ich verwende i.d.R. -std=gnu99> oder -std=gnu11 je nach GCC Version.
-std=c2x
> Ohne das "gnu" sind Extensions nicht aktiv IMHO (oder erzeugen Warnings).
Eigentlich logisch, aber für 0b01010101 hat extension funktioniert?
Rätselhaft.
Bernd K. schrieb:> SVC_Handler,> DebugMon_Handler,> 0,> PendSV_Handler,
Die Nuller sind ja äußerst interessant. Dann könnte ich ja die [0...111]
Initialisierung weglassen und es wäre perfekt -- keine Warnungen, auch
ohne #pragma usw.
Aber: führt 0 wirklich zu einem Usage Fault? Ja, weil das T-Bit nicht
gesetzt ist; nein, weil das eine Adresse ist und deshalb die
Stack-Adresse als Befehl ausgeführt würde. Das allerdings mit T-Bit = 0,
hmm.
Also vermutlich ist es definiert aber reicht mir das? Dass irgendjemand
bei ST (oder wer war das?) das so richtig findet heißt ja nun garnichts.
Und wenn das Verhalten mit 0 definiert wäre, könnte man doch die ganzen
weak-Einträge weglassen?
Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch
nicht nutzen kann.
Bauform B. schrieb:> könnte man doch die ganzen weak-Einträge weglassen?
Die welche nicht Null sind existieren, könnten also aufgerufen werden,
also braucht man einen Mechanismus mit dem sich die Anwendung da bei
Bedarf beim Linken einhaken kann, dieser Mechanismus ist weak.
Wenn die Anwendung keinen eigenen Handler mitbringt gilt der weiche
Alias auf den Default Handler und dessen Adresse wird eingesetzt,
andernfalls setzt der Linker die Adresse des starken Handlers aus der
Anwendung ein.
Bauform B. schrieb:> Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch> nicht nutzen kann.
Was laberst Du? Natürlich kannst du es nutzen, deshalb hab ich's doch
geschrieben! Du kannst auch das vom Hersteller nutzen, das ist dann halt
in Assembler, funktioniert aber nach dem exakt selben Prinzip.
Bernd K. schrieb:> Diese Vektoren existieren nicht, die werden nie aufgerufen, also kann da> stehen was will.
Was ist mit dem Software trigger interrupt register (NVIC_STIR)? Darüber
kann man doch jeden Interrupt per Software triggern? ST meint, alle von
0 bis (256-16), das heißt, meine Tabelle muss noch doppelt so groß
werden. Danke für den Tipp.
Bernd K. schrieb:> Die welche nicht Null sind existieren, könnten also aufgerufen werden,> also braucht man einen Mechanismus mit dem sich die Anwendung da bei> Bedarf beim Linken einhaken kann, dieser Mechanismus ist weak.
Genau das mache ich ja auch, nur mit viel weniger Zeilen.
1
[0...(128-16-1)]=crash
trägt überall den Default Handler ein und mit
1
[PVD_PVM_IRQn]=pvd_isr,// PVD thru EXTI line detection
2
[UART0_IRQn]=uart0_isr,
klinkt sich die Anwendung mit ihrem Bedarf da ein.
Als Bonus ist auch bei denen, die nicht existieren, etwas eingetragen.
Leider meint der GCC, dass "array[0 ... n]=foo" auch in C2x noch nicht
erlaubt ist und außerdem warnt er bei den folgenden Zeilen. Letztere
Warnung kann ich einfach abschalten aber die erste nervt; vor allem,
weil extension nichts nützt. Ideal wäre es, wenn 0 statt crash sauber
funktionieren würde. Deswegen:
>> Ich hasse es, wenn es so verlockende Angebote gibt, die man dann doch>> nicht nutzen kann.Bernd K. schrieb:> Komplettes Beispiel hier:> https://github.com/prof7bit/bare_metal_stm32f401xe
Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen.
Solche Konstruktionen braucht man doch nur in IDE, wo möglichst viel vor
dem Benutzer versteckt werden soll.
Bauform B. schrieb:> Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen.
Du redest wirr. Wie soll man es Deiner Meinung nach sonst machen wenn
die Vektortabelle im ROM liegt? Die Tabelle ins RAM zu legen und
kostbares RAM verschwenden auch wenn überhaupt kein zwingender Grund
vorliegt das im RAM zu haben?
Ich glaub Du hast noch nicht recht verstanden was es mit weak auf sich
hat und warum man genau das und nichts anderes an dieser Stelle
verwendet denn genau für solche Sachen wurde das erfunden. Du wirst es
sicherlich irgendwann verstehen wenn Du Dich noch ein wenig länger damit
beschäftigst. Google einfach mit dem Stichwort und lies Dir alles durch,
solange bis es "klick" macht.
> Darüber kann man doch jeden Interrupt per Software triggern?
Dann setz halt dort überall den Default_Handler ein statt 0 wenn Dir
dabei wohler ist. Macht zwar sonst auch keiner aber schaden kanns auch
nicht.
Bauform B. schrieb:>> dieser Mechanismus ist weak.>> Genau das mache ich ja auch, nur mit viel weniger Zeilen.
Ich seh kein einziges weak in Deinem geposteten Code. Wo soll die
Anwendung ihre eigenen Handler einhängen? Willst Du jedesmal von Hand
den Startup anpassen? Das ist doch Käse hoch 3!
Aber im Zusammenhang mit "weak" aufpassen, solltest du einen Handler
über eine separat gebaute Library einführen!
Aber wenn das ganze Thema verstanden ist, ist das auch klar … nur
manchmal denkt man ja nicht direkt an so Dinge.
Bernd K. schrieb:> Bauform B. schrieb:>> Irgendwie passt "bare_metal" und der weak-Mechanismus nicht zusammen.>> Du redest wirr.
Das tut mir leid, es ist nicht böse gemeint.
> Wie soll man es Deiner Meinung nach sonst machen wenn> die Vektortabelle im ROM liegt?
Genau so wie ich es ganz oben geschrieben habe. Warum sollte das im
Flash nicht funktionieren? RAM brauchst du doch nur, wenn du ISRs "im
Flug" austauschen willst. Das kann sehr praktisch sein, keine Frage,
aber meistens geht es doch ohne RAM.
Bernd K. schrieb:> Ich glaub Du hast noch nicht recht verstanden was es mit weak auf sich> hat und warum man genau das und nichts anderes an dieser Stelle> verwendet denn genau für solche Sachen wurde das erfunden.
Den weak-Mechanismus habe ich schon im letzten Jahrtausend gerne
benutzt. Warum man ihn hier verwendet ist mir nicht klar, aber es ist
ja auch Geschmackssache. Es gibt mehrere Möglichkeiten und jede hat ihre
Vor- und Nachteile. Wenn man die Tabelle im RAM haben will, wird man es
evt. anders machen.
Bernd K. schrieb:> Ich seh kein einziges weak in Deinem geposteten Code.
Da soll auch keins drin stehen. Warum soll ich einen spezial-Mechanismus
nutzen, wenn es auch ohne geht?
> Wo soll die Anwendung ihre eigenen Handler einhängen?
1
[UART0_IRQn]=uart0_isr,
> Willst Du jedesmal von Hand den Startup anpassen?
Nicht den Startup, nur diese eine Tabelle, und nur, wenn eine neue ISR
dazu kommt.
> Das ist doch Käse hoch 3!
Das ist ein angenehmer Nebeneffekt für jemand, der wenig Fleisch isst ;)
Squierrel schrieb:> Aber im Zusammenhang mit "weak" aufpassen, solltest du einen> Handler> über eine separat gebaute Library einführen!
Danke, also hatte mein Bauch doch Recht, weak schmeckt uns nicht ;)
Im Ernst, wenn man mit weak aufpassen muss und ohne eine Fehlermeldung
bekommt -- wer würde da freiwillig weak verwenden?
Bauform B. schrieb:> Im Ernst, wenn man mit weak aufpassen muss und ohne eine Fehlermeldung> bekommt -- wer würde da freiwillig weak verwenden?
Hier! ;)
Aber im ernst, ein großer Fan bin ich nicht. Es ist öfters einfach die
beste/praktischste Variante. Bin auch kein Freund von Libs :D …
Bauform B. schrieb:>> Wo soll die Anwendung ihre eigenen Handler einhängen?[UART0_IRQn] = uart0_isr,>> Willst Du jedesmal von Hand den Startup anpassen?>> Nicht den Startup, nur diese eine Tabelle, und nur, wenn eine neue ISR> dazu kommt.
Naja gut, wenn Du das so umständlich haben willst, dann bitte. Niemand
hindert Dich daran.
Aber Du hast ja explizit gefragt wie "man" das macht. Und "man" nimmt
halt normalerweise den weak-Mechanismus der ja genau wie gemacht für
diese Sache ist, sei es in Assembler oder in C, und es keinerlei Sinn
oder Vorteil ergäbe darauf zu verzichten, im Gegenteil, ohne weak wirds
auf jeden Fall unhandlicher, egal wie Du es drehst oder wendest.
Ich nehme dafür auch kein "weak", sondern kopiere N mal den
Default-Handler da hart hin (N wie im zugehörigen Chip-Manual
beschrieben), gruppiere die hübsch in Zehnergruppen und mache Kommentare
dazu, welche Zehnergruppe gerade beginnt.
Bei Bedarf trage ich da an der richtigen Stelle den Interrupt ein, den
das Manual dort vorsieht. Die richtige Dekade sehe ich am Kommentar, und
zählen bis 10 bekomme ich gerade noch so hin.
Dann sehe ich wenigstens schon am Linker-Ergebnis, ob er den richtigen
Handler da jetzt einträgt oder nicht. Außerdem sehe ich direkt an der
Vektortabelle, was für Interrupts überhaupt genutzt werden.
Bernd K. schrieb:> Aber Du hast ja explizit gefragt wie "man" das macht. Und "man" nimmt> halt normalerweise den weak-Mechanismus der ja genau wie gemacht für> diese Sache ist
Ja, stimmt. Natürlich hatte ich gehofft, dass "man" das anders macht.
Aber mit den Nullen in deiner Tabelle hast du den entscheidenden Tipp
geliefert. Man muss keinen Default Handler eintragen, 0 tut es auch. Da
0 automatisch eingetragen wird, reicht es, wenn man nur die benutzten
ISRs hinschreibt.
Nop schrieb:> Ich nehme dafür auch kein "weak", sondern kopiere N mal den> Default-Handler da hart hin (...)> Bei Bedarf trage ich da an der richtigen Stelle den Interrupt ein, den> das Manual dort vorsieht.
Die richtige Stelle sagen einem die IRQn_enum, z.B. SPI1_IRQn. Das Array
der vector_table kann man dann einfach mit
1
[SPI1_IRQn]=spi_isr,
intialisieren. Nix abzählen, nur genau so viele Zeilen wie nötig, keine
magischen Zahlen, keine Mecker vom GCC, bei allen unbenutzten Interrupts
steht automatisch die 0 drin. Das funktioniert so, als ob der Usage
Fault Handler eingetragen wäre. Welcher Eintrag gefehlt hat, steht
hinterher im IPSR.
1
Aus dem ARM v7-M Architecture ® Reference Manual, ARM DDI0403E.d
2
3
B1.5.3 The vector table
4
All [other] entries must have bit[0] set to 1, because this bit
5
defines the EPSR.T bit on exception entry.
6
On exception entry, if bit[0] of the associated vector table entry
7
is set to 0, execution of the first instruction causes an INVSTATE
8
UsageFault, see The special-purpose Program Status Registers, xPSR
9
10
B1.5.6 Exception entry behavior
11
(...)
12
tmp = MemA[VectorTable+4*ExceptionNumber,4];
13
BranchTo(tmp AND 0xFFFFFFFE<31:0>);
14
tbit = tmp<0>;
15
CurrentMode = Mode_Handler;
16
APSR = bits(32) UNKNOWN;
17
IPSR<8:0> = ExceptionNumber<8:0>;
18
EPSR.T = tbit;
19
(...)
20
21
B1.3.3 Execution state
22
Setting EPSR.T to zero in an ARMv7-M processor causes a fault
23
when the next instruction executes, because in this state all
24
instructions are UNDEFINED.
Ich hätte gern noch den Pseudo-Code für die eigentliche
Befehlsausführung gefunden, zwecks wann das T-Bit abgefragt wird. Aber
ich glaube, es ist auch so überzeugend. Immerhin wird der "Befehl" auf
Adresse 0 (nicht) ausgeführt, damit fallen viele andere
Fehlermöglichkeiten weg. Und selbst wenn die Exception im Hard Fault
Handler endet, kann man noch gut debuggen.
Rein theoretisch könnte es auch mit einem Lockup enden. Aber bis die
Dekodierung von dem "Befehl" beginnt ist alles noch völlig normal und
ohne Tricks. Also, was könnte schief gehen?