Und wieder ich :) ich wundere mich, dass sich noch keiner beschwert ;) Wie handhabt ihr euren Code im Interrupthandler? Laut (u. A.) Mikrocontroller.net: "... .Prinzipiell sollte man ISRs möglichst kurz halten und schnell beenden. ...", soll man diese ja möglichst kurz halten. In meinem konkreten Fall habe ich einen extern getriggerten Timer, der einen Interrupt nach der Triggerung auslöst. Im einfachsten Fall soll nach der Triggerung eine Variable gelesen werden. OK, das kann ich ja im Interrupt selbst machen. Was ist aber, wenn nach der Triggerung, viel mehr passieren muss? Beispielsweise ADC auslesen und in den Speicher übergeben. Oder viele Rechenoperationen.
Reginald L. schrieb: > Beispielsweise ADC auslesen und in den Speicher > übergeben. Das benötigt schonmal nicht viel, kann also kein Problem sein. Reginald L. schrieb: > Oder viele Rechenoperationen Wofür benötigst du denn die viele Rechenoperationen? Hinweis: Siehe vorige Antwort. Reginald L. schrieb: > Und wieder ich :) ich wundere mich, dass sich noch keiner beschwert ;) Ich sage jetzt mal voraus dass es demnächst Beschwerden geben wird, denn das ist jetzt keine konkrete Frage mehr die du hier stellst. Trotzdem bekommst du eine Pauschale Antwort, kein Problem. Du setzt in der ISR ein globales Flag und das Hauptprogramm übernimmt die entsprechend verknüpfte Aufgabe sobald es dieses Flag auswertet. Zufrieden?
Ach ja, meine Antwort ist nicht STM32-spezifisch. Genau so wenig wie es die Frage war, trotz Thread-Titel.
Durch geschickte Wahl von Interruptprioritäten und Subprioritäten kann man schon eine Menge machen; auch sollte man den DMA-Controller nicht unterschätzen. Nächter Beitrag: "Memory-Memory-Tranfer mit dem DMA-Controller beim STM32?" ;-)
Esam schrieb: > Wofür benötigst du denn die viele Rechenoperationen? Beispielsweise Matrizenberechnungen oder FFTs. Kann man sozusagen alles in den Handler reinscheißen, solange ich meine Interrupts unter Kontrolle habe? Macht man das so? Esam schrieb: > Ich sage jetzt mal voraus dass es demnächst Beschwerden geben wird, denn > das ist jetzt keine konkrete Frage mehr die du hier stellst. Na also, auf Anfrage gehts doch ;) Wobei du mit nicht-STM32-spezifisch natürlich Recht hast. Esam schrieb: > Trotzdem bekommst du eine Pauschale Antwort, kein Problem. Du setzt in > der ISR ein globales Flag und das Hauptprogramm übernimmt die > entsprechend verknüpfte Aufgabe sobald es dieses Flag auswertet. > Zufrieden? Verstehe ich das richtig, dass der InterruptHandler dann nur ein Flag setzt, mein Code im Hauptprogramm abgearbeitet wird, wenn das Flag gesetzt sein sollte und ich danach das Flag wieder resette? m.n. schrieb: > Durch geschickte Wahl von Interruptprioritäten und Subprioritäten kann > man schon eine Menge machen; auch sollte man den DMA-Controller nicht > unterschätzen. Ich bin schon tierisch Stolz, dass ich den Timer per externem Trigger auf nen Interrupt legen konnte, ohne Examples (so langsam frage ich mich, wieviele Schreib-/Lesezyklen ich noch frei habe :>)! Hör mir auf mit Prioritäten, was glaubst du wie mir der Kopf raucht ;) Im Ernst: Das habe ich mir schon angeschaut, bisher brauche ich das noch nicht. Wenn es dann Richtung RS232 geht, nehme ich mal an. Aber soweit bin ich noch lange nicht.
Am einfachsten löst man solche Probleme - geht natürlich nur im entsprechenden Umfeld - indem man in der Interruptroutine nur das nötigste macht und somit die Erkennung von der Reaktion trennt. Also z.B. 1. Einen Wert lesen und Zwischenspeichern, so das Nötig ist. 2. Ein Flag setzen. Das war’s. Dann kann man in der Hauptschleife seine "Runden" drehen und immer mal wieder nachfragen, ob was (Flag) anliegt.
Reginald L. schrieb: > Beispielsweise Matrizenberechnungen oder FFTs. Kann man sozusagen alles > in den Handler reinscheißen, solange ich meine Interrupts unter > Kontrolle habe? Macht man das so? Das kann man nicht allgemeingültig beantworten. Wenn eine Anwendung das erfordert, ist es zumindest schon mal nicht verboten. Ansonsten hoffe ich doch sehr dass du dich nur vertippt hast ;) Reginald L. schrieb: > Verstehe ich das richtig, dass der InterruptHandler dann nur ein Flag > setzt, mein Code im Hauptprogramm abgearbeitet wird, wenn das Flag > gesetzt sein sollte und ich danach das Flag wieder resette? Ja, so ist das gemeint.
> Verstehe ich das richtig, dass der InterruptHandler dann nur ein Flag > setzt, mein Code im Hauptprogramm abgearbeitet wird, wenn das Flag > gesetzt sein sollte und ich danach das Flag wieder resette? Musst Du aber nicht! Setzt Du dieses nicht zurück, so ergibt die darauffolgende Abfrage wieder ein positives Ergebnis. Eine gute Möglichkeit des thermische Verhalten der CPU im Dauerstress zu überprüfen. Eine schlechte Wahl, wenn Du ein folgendes Ereignis separieren willst.
Vielen Dank an alle! Dem entnehme ich, dass es also schonmal nicht "verboten" ist zeitkritische Aufgaben im Handler durchzuführen und alle anderen über ein Flag im normalen Programmablauf. Amateur schrieb: > Musst Du aber nicht! > Setzt Du dieses nicht zurück, so ergibt die darauffolgende Abfrage > wieder ein positives Ergebnis. > Eine gute Möglichkeit des thermische Verhalten der CPU im Dauerstress zu > überprüfen. > Eine schlechte Wahl, wenn Du ein folgendes Ereignis separieren willst. Danke für den Tipp, so weit bin ich noch lange nicht ;) Esam schrieb: > Reginald L. schrieb: >> Beispielsweise Matrizenberechnungen oder FFTs. Kann man sozusagen alles >> in den Handler reinscheißen, solange ich meine Interrupts unter >> Kontrolle habe? Macht man das so? > > Das kann man nicht allgemeingültig beantworten. Wenn eine Anwendung das > erfordert, ist es zumindest schon mal nicht verboten. > Ansonsten hoffe ich doch sehr dass du dich nur vertippt hast ;) Upsa :> Sollte natürlich noch ein "m" reingeschiß.. ähm, ...geschmissen werden :)
Nun kommen wir doch in den CPU spezifischen Bereich. Es gibt Interrupte, die dauerhaft auslösen. Hier muss das Flag zurückgesetzt werden oder der jeweilige Interrupt gesperrt werden. Es gibt aber auch Interrupte, welche nur einmalig auslösen. Es gibt auch Interrupte, die lösen aus, wenn die Peripherie nichts zu tun hat. Und und und. Daher sind die Lösungsansätze auch vielfältig und müssen an die jeweilige CPU und die jeweilige Peripherie anpassen.
In diesem Bereich gibt es die folgende Problematik: Oft werden während der Interruptbearbeitung andere Unterbrechungen gesperrt. Hast Du jetzt eine Unterbrechung, die extrem langsam ist (rechenintensiv), so besteht die Möglichkeit, dass eine andere Unterbrechung zweimal Deine Aufmerksamkeit erhascht. Mit dem Scenario der einfachen Unterbrechung kommen die meisten Rechner klar. Die mehrfache (von einer Quelle) beherrschen nicht alle. Machst Du aber Deine Arbeit in der Hauptschleife, so kann dieser Ablauf ruhig öfter, von einer oder mehreren Quellen, unterbrochen werden. Hier gilt dann: Die gesamte Rechenzeit darf nicht überschritten werden.
Reginald L. schrieb: > Hör mir auf > mit Prioritäten, was glaubst du wie mir der Kopf raucht ;) Im Ernst: Das > habe ich mir schon angeschaut, bisher brauche ich das noch nicht. Mach auch mal einen ganzen Tag Pause - damit löst man manchmal Probleme auf die einfachste Art. Gerade bei Cortex-M4 muß einem der Kopf nicht mehr rauchen. Durch die zahlreichen Prioritäten kann man zeitkritischen, kurzen Routinen Vorrang vor allen anderen Interrupts geben, während ein langsamer (z.B. 1 ms) Timerinterrupt ganz niedrige Priorität bekommt. Das Schöne dabei ist, daß ein höher priorisierter Interrupt die darunterliegenden ISRs unterbrechen kann und nicht blockiert wird. Auch wenn Du es jetzt nicht brauchst, es gibt Auswege, falls das Timing mal zu eng werden sollte.
Ich sollte nächstes mal wirklich spezifischer fragen: Mein Interrupt löst zwischen 1-50Hz aus ;) Mir gings hierbei nur um die Behandlung eines einzigen Interrupts. Aber jetzt weiß ich für die Zukunft, dass ich nur in diesen Thread schauen muss, wenns intensiver wird. Danke nochmals :)
Amateur schrieb: > Oft werden während der Interruptbearbeitung andere Unterbrechungen > gesperrt. > Hast Du jetzt eine Unterbrechung, die extrem langsam ist > (rechenintensiv), so besteht die Möglichkeit, dass eine andere > Unterbrechung zweimal Deine Aufmerksamkeit erhascht. Warum sollte man das tun? Genau dafür wurden schon vor Uhrzeit Interruptprioritäten erfunden. Auch wenn sich das noch nicht bis zu den kleinen AVR herumgesprochen hat (bzw. manche meinen immer noch so programmieren zu müssen), so können viele µC mittlerweile sowas:-)
Amateur schrieb: > indem man in der Interruptroutine nur das > nötigste macht und somit die Erkennung von der Reaktion trennt. > Also z.B. > 1. Einen Wert lesen und Zwischenspeichern, so das Nötig ist. > 2. Ein Flag setzen. Warum dann eigentlich einen Interrupt? Da kann man doch einfach den Interrupt disablen und das Interruptflag direkt in der Mainloop auslesen und sich den ganzen Interruptoverhead sparen. MfG Klaus
Irgendwer schrieb: > Genau dafür wurden schon vor Uhrzeit > Interruptprioritäten erfunden. Auch wenn sich das noch nicht bis zu den > kleinen AVR herumgesprochen hat (bzw. manche meinen immer noch so > programmieren zu müssen), so können viele µC mittlerweile sowas:-) Prioritäten reichen hier nicht. Häufig bestimmt die Priorität nur, wer bei gleichzeitigen Anliegen von Interrupts der Gewinner ist. Wenn Du längere Zeit im Interrupt verweilen willst, brauchst Du auch noch nested Interrupts.
Steffen R. schrieb: > Wenn Du längere Zeit im Interrupt verweilen willst, brauchst Du auch > noch nested Interrupts. Das hat 'Irgendwer' sicher auch so gemeint, da er den AVR als Negativbeispiel genannt hatte. Anders war es seinerzeit bei µPs, die nur einen /INT-Eingang für ext. Peripherie hatten und damit keine Hardwarepriorität möglich war, es sein denn, man hatte einen vorgeschalteten Dekoder ...
m.n. schrieb: > Das hat 'Irgendwer' sicher auch so gemeint, da er den AVR als > Negativbeispiel genannt hatte. Ich beziehe mich hier z.B. auf den Unterschied ARM7 und Cortex-M3. 'Irgendwer' schien sich eher auf ältere Prozessoren zu beziehen. Ich eher auf den Unterschied Microprozessor <> Microcontroller.
Und wieder ein kleines Erfolgserlebnis, das ich unbedingt mit euch teilen möchte, passt auch zum Thema :> Seit gestern habe ich vergeblich versucht, eine Variable, die sich im IRQHandler in der "stm32f4xx_it.h" ändert, der "main.c" zu übergeben. Heute habe ich es endlich geschafft. Der Umstieg von MatLab auf C ist wirklich immens hart. Könntet ihr mir sagen, ob das so korrekt übergeben wird, da ich noch nicht so fit mit den Deklarationen in C bin: stm32f4xx_it.c:
1 | #include "stm32f4xx_it.h" |
2 | ...
|
3 | ...
|
4 | long int TriggerValue; |
5 | |
6 | void TIM2_IRQHandler(void) |
7 | {
|
8 | |
9 | if(TIM_GetITStatus(TIM2, TIM_IT_Trigger) != RESET) |
10 | {
|
11 | |
12 | TriggerValue = TIM_GetCounter(TIM2); // Get Timer2 Value |
13 | TIM_SetCounter(TIM2, 0); // Reset Timer2 |
14 | |
15 | TIM_ClearITPendingBit(TIM2, TIM_IT_Trigger); // Clear IRQ Timer 15 |
16 | |
17 | }
|
18 | }
|
stm32f4xx_it.h:
1 | extern long int TriggerValue; |
main.c:
1 | #include "stm32f4xx_it.h" |
2 | ...
|
3 | ...
|
4 | int main(void) |
5 | {
|
6 | ...
|
7 | ...
|
8 | while(1) |
9 | {
|
10 | long int a=TriggerValue; |
11 | printf("%li",a); |
12 | ...
|
13 | ...
|
14 | }
|
15 | }
|
Es geht hier lediglich um optische Rückmeldung, der TriggerValue wird im Handler später noch benötigt.
Ah, vergessen :) Also in der "stm32f4xx_it.c" anstatt "long int TriggerValue;":
1 | volatile long int TriggerValue; |
EDIT: ? :)
:
Bearbeitet durch User
Steffen R. schrieb: > Ich beziehe mich hier z.B. auf den Unterschied ARM7 und Cortex-M3. Die Knackpunkte sind: - lässt die CPU ein Nesting prinzipiell zu, - gibt es einen Interrupt-Controller mit Prioritäten. In den Cortex-M ist stets einer drin. Bei dem ARM7 ist das Sache desjenigen, der den Core mit Peripherie zusammen in einen Chip giesst. Meistens ist einer drin. Damit geht das auch beim ARM7. > 'Irgendwer' schien sich eher auf ältere Prozessoren zu beziehen. Priorisierte Interrupts mit Nesting sind kein sonderlich neues Konzept. Das war schon anno Z80 ziemlich verbreitet, weil fertig drin. Dass andererseits µCs ohne Interrupt-Controller mit Nesting dennoch irgendwelche Prioritäten für ihre Interrupt-Quellen haben liegt in der Natur der Sache, wenn man keinen Zufallsgenerator einbaut. Insofern ist alt/neu hier kein Kriterium. Und die Prioritäten bei AVRs sind selten das, was man üblicherweise mit Interrupt-Prioritäten verbindet.
:
Bearbeitet durch User
Hm, also so wie ich mir das gedacht habe, gehts jedenfalls nicht. Wenn ich das volatile allerdings in meine main() Funktion reinmache, dann bringt er mir keinen Fehler, wenn es über der main() Funktion steht aber schon. Komplett anderes Konzept hier in C :/
Nimm besser "volatile uint32_t TriggerValue", weil hier der Wert eindeutig eine 32-Bit Variable ohne Vorzeichen ist. In Deinem IRQHandler teste bitte IMMER auf ein aktives Ereignis, dessen Flag dann gelöscht wird. Dann lasse bitte noch Timer2 durchlaufen (nicht löschen), wenn das Timing exakt sein soll, oder lösche ihn per Hardware. Anderfalls könnte er zum Zeitpunkt des Löschens schon einen nennenswerten Zählerstand haben (ein anderer Interrupt höherer Priorität hat 'dazwischen gefunkt'). Aber gut, das sind Feinheiten für die Zukunft. Dein Programmierstil entwickelt sich ja ;-), aber lasse bitte leere Zeilen weg. Wenn man viel Code hat, hat man dadurch weniger Luft und mehr Substanz im Blick. Reginald L. schrieb: > Der Umstieg von MatLab auf C ist > wirklich immens hart. Aber miss mal die Zeit für Deine Interruptroutine. Ich schätze mal rund 100 - 150 ns. Das ist richtig schnell!
Reginald L. schrieb: > printf("%li",a); > ... > ... > } > } > > Es geht hier lediglich um optische Rückmeldung, der TriggerValue wird im > Handler später noch benötigt. Vielleicht testest Du doch noch einmal IAR-Kickstart. Mit 'Live Watch' kannst Du dir die Variable zur Laufzeit anzeigen lassen und nicht nur, wenn gerade main() ein printf() veranstaltet: zum Beispiel, wenn das Programm an irgendeiner Stelle hängen bleibt, die Interrupts aber weiterhin bedient werden. Gerade für die ersten Schritte ist das sehr hilfreich.
m.n. schrieb: > Nimm besser "volatile uint32_t TriggerValue", weil hier der Wert > eindeutig eine 32-Bit Variable ohne Vorzeichen ist. Tatsächlich, mach ich. m.n. schrieb: > In Deinem IRQHandler teste bitte IMMER auf ein aktives Ereignis, dessen > Flag dann gelöscht wird. Dann lasse bitte noch Timer2 durchlaufen (nicht > löschen), wenn das Timing exakt sein soll, oder lösche ihn per Hardware. > Anderfalls könnte er zum Zeitpunkt des Löschens schon einen > nennenswerten Zählerstand haben (ein anderer Interrupt höherer Priorität > hat 'dazwischen gefunkt'). Aber gut, das sind Feinheiten für die > Zukunft. Was meinst du mit dem Flag löschen genau, also den Sinn dahinter? Der Timer soll direkt nach dem Trigger ausgelesen werden, dann sofort neu starten. Dies eben jede Runde (Frequenz max 50Hz). Ob dazwischen weitergezählt wird, stört mich nicht (ausser du weißt etwas, was ich nicht weiß :) ).Ungern würde ich den Timer durchlaufen lassen und das Value dann aus den durchlaufenen Schleifen ziehen. Per Hardware löschen wäre super, aber ich habe bisher nur diese Möglichkeit gefunden, den Timer zurückzusetzen, kannst du mir da einen Tipp geben? m.n. schrieb: > Dein Programmierstil entwickelt sich ja ;-), aber lasse bitte leere > Zeilen weg. Wenn man viel Code hat, hat man dadurch weniger Luft und > mehr Substanz im Blick. Hey, ich programmiere ja schon seit Jahren mit MatLab, da ist die Welt nur mathematischer :P Und nein, die Luft bleibt drin, da kann ich besser gucken :) Dankeschön mal wieder :)
Reginald L. schrieb: > m.n. schrieb: >> Nimm besser "volatile uint32_t TriggerValue", weil hier der Wert >> eindeutig eine 32-Bit Variable ohne Vorzeichen ist. > > Tatsächlich, mach ich. Na danke, jetzt geht gar nichts mehr^^
m.n. schrieb: > Vielleicht testest Du doch noch einmal IAR-Kickstart. Mit 'Live Watch' > kannst Du dir die Variable zur Laufzeit anzeigen lassen und nicht nur, > wenn gerade main() ein printf() veranstaltet: zum Beispiel, wenn das > Programm an irgendeiner Stelle hängen bleibt, die Interrupts aber > weiterhin bedient werden. Ich werds grad mal runterziehen. Welche Version soll ich benutzen, blick da nicht durch mit C-Run und Co :)
Füge volatile auch im Header ein. Sonst weiss der Compiler beim compilieren der Main nicht, dass er den Zugriff auf die Variable nicht optimieren darf.
Luis schrieb: > Füge volatile auch im Header ein. Sonst weiss der Compiler beim > compilieren der Main nicht, dass er den Zugriff auf die Variable nicht > optimieren darf. Aber es reicht die Variable mit volatile jeweils einmal im Header und einmal im SourceCode zu modifizieren? Wird die Variable dann im kompletten Programm als volatile behandelt?
Jepp, wenn du den Header korrekt in jedem genutzten c-File includiert hast, reicht das. Vorsicht, wenn du innerhalb einer Funktion nochmals eine Angabe "volatile uint32_t TriggerValue" einbaust. Der Compiler legt dann ggf eine zweite Variable gleichen Namens auf dem Stack an. Prüfe mal den Warnung level deines Compilers, ob er meckert wenn er namens gleiche Variablen erstellen soll.
Luis schrieb: > Vorsicht, wenn du innerhalb einer Funktion nochmals eine Angabe > "volatile uint32_t TriggerValue" einbaust. Der Compiler legt dann ggf > eine zweite Variable gleichen Namens auf dem Stack an. Prüfe mal den > Warnung level deines Compilers, ob er meckert wenn er namens gleiche > Variablen erstellen soll. Wäre das die Option "Warn if anything is declared more than once in the same scope"? Komischerweise funktioniert "uint32_t" nicht, obwohl es im CodeCompletion auftaucht. Allerdings geht "unsigned long int". Weisst du woran das liegt? Und wieder mal ein herzliches Dankeschöne an alle, hilft ungemein, wenn es um solche Kleinigkeiten geht, deren Lösung schwerlichst im Internet zu finden sind. Zumindest als Anfänger in C. EDIT: Wenn ich "volatile unsigned long int TriggerValue;" jeweils im Header und in der Source angebe, sagt er mir aber:
1 | "src\stm32f4xx_it.c|166|warning: redundant redeclaration of 'TriggerValue' [-Wredundant-decls]|
|
2 | .\inc\stm32f4xx_it.h|28|note: previous declaration of 'TriggerValue' was here|
|
3 | bin\Debug\Test.map|1|Program size (bytes): 15128|
|
4 | ||Data size (bytes): 440|
|
5 | ||BSS size (bytes): 1888|
|
6 | || ----------------|
|
7 | ||Total size (bytes): 17456 (R/W Memory: 2328)|
|
8 | |||
|
9 | ||=== Build finished: 0 errors, 1 warnings (0 minutes, 0 seconds) ===|
|
:
Bearbeitet durch User
>Wenn ich "volatile unsigned long int TriggerValue;" jeweils im ... long ist ein Datentyp UND int ist ein Datentyp. verwende entweder long oder int. >Komischerweise funktioniert "uint32_t" nicht... Inkludier den Header <stdint.h> #include <stdint.h>
Luis schrieb: > long ist ein Datentyp UND int ist ein Datentyp. verwende entweder long > oder int. Ahhh, eieiei, aber es ist doch ein int ;) Luis schrieb: > Inkludier den Header <stdint.h> > #include <stdint.h> Ganz vergessen, dass ich irgendwo wortwörtlich gelesen habe "C kann ohne Bibliotheken fast gar nichts".
A. K. schrieb: > In den Cortex-M ist stets einer drin. Bei dem ARM7 ist das Sache > desjenigen, der den Core mit Peripherie zusammen in einen Chip giesst. > Meistens ist einer drin. Damit geht das auch beim ARM7. Der Interrupt Controller stößt immer den IRQ oder den FIRQ an. Ist der IRQ gerade aktiv nützt es auch nichts, wenn der Interrupt Controller einen Interrupt höherer Priorität anstoßen will. (per Software kann man da was drehen, aber das war ja auch die Aussage -> IRQ Behandlung ja nach Umgebung) Reginald Leonczuk
1 | "src\stm32f4xx_it.c|166|warning: redundant redeclaration of 'TriggerValue' [-Wredundant-decls]|
|
2 | .\inc\stm32f4xx_it.h|28|note: previous declaration of 'TriggerValue' was here|
|
Wie soll man etwas prüfen, wenn man nicht weiß, was du angestellt hast? Schau Dir die beiden angegebenen Zeilen an.
Steffen R. schrieb: > Wie soll man etwas prüfen, wenn man nicht weiß, was du angestellt hast? > Schau Dir die beiden angegebenen Zeilen an. Steht doch eigentlich alles in den obigen Beiträgen von mir. source:
1 | volatile uint32_t TriggerValue; |
2 | |
3 | void TIM2_IRQHandler(void) |
4 | {
|
5 | if(TIM_GetITStatus(TIM2, TIM_IT_Trigger) != RESET) |
6 | {
|
7 | |
8 | TriggerValue = TIM_GetCounter(TIM2); // Get Timer2 Value |
9 | TIM_SetCounter(TIM2, 0); // Reset Timer2 |
10 | |
11 | TIM_ClearITPendingBit(TIM2, TIM_IT_Trigger); // Clear IRQ Timer 15 |
12 | |
13 | }
|
14 | }
|
header:
1 | volatile uint32_t TriggerValue; |
Wenn du einen guten Link hast mit klaren Informationen für Anfänger zu dem Thema, ziehe ich das natürlich vor, als euch mit solchen stupiden Fragen zu bombardieren. Auf allen Seiten, die ich mir zu dem Thema angeschaut habe, finde ich nur unzureichende Informationen, vor allem, wenn es um volatile geht.
Im Header steht normalerweise nur die Deklaration => extern fehlt Du hast zweimal definiert == zwei Variable angelegt. Beim gcc dürfte dies gut gehen, da er nach meiner Erfahrung diese zusammenlegt. Header:
1 | extern volatile uint32_t TriggerValue; |
Aaaah, man darf extern noch zum volatile dazulegen? Supi, tausend Dank!
Reginald L. schrieb: > Wenn du einen guten Link hast mit klaren Informationen für Anfänger zu > dem Thema, https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich Naja, ein Einsteiger C Kurs im Netz oder als Buch solltest Du als Umsteiger doch mal überfliegen. Dass du C nicht von Pike auf lernen willst ist mir klar.
Steffen R. schrieb: > Der Interrupt Controller stößt immer den IRQ oder den FIRQ an. > Ist der IRQ gerade aktiv nützt es auch nichts, wenn der Interrupt > Controller einen Interrupt höherer Priorität anstoßen will. Funktioniert. Der Handler muss natürlich Nesting unterstützen, d.h. Stack wechseln, Interrupts wieder einschalten und Vektor auslesen (nicht zwingend in dieser Reihenfolge). Das kann u.U. bereits im Runtime-Evironment des Compilers enthalten sein, so dass der Programmierer davon nichts sieht. Entscheidend ist bei Interrupts nicht, ob das Verfahren hin hin zum Prolog/Epilog der Funktionen in der Hardware steckt (Cortex M), sondern ob priorisiertes Nesting mit geringem Aufwand überhaupt möglich ist. Und das ist bei ARM7 mit Interrupt-Controller der Fall, bei AVR hingegen nicht. > (per Software kann man da was drehen, aber das war ja auch die Aussage > -> IRQ Behandlung ja nach Umgebung) Anders als bei AVRs ist das dann aber ein vollständiges Nesting mit echten Prioritäten, d.h. Unterbrechung nur durch höher priorisierte Interrupts.
Steffen R. schrieb: > https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich > > Naja, ein Einsteiger C Kurs im Netz oder als Buch solltest Du als > Umsteiger doch mal überfliegen. Dass du C nicht von Pike auf lernen > willst ist mir klar. Hihi, dieser Link war meine erste Anlaufstelle ;) Allerdings steht da nicht die Information, die ich gerade von dir bekommen habe. Ich bin davon ausgegangen, dass volatile und extern sich gegenseitig ausschließen. So bin ich auf mehreren Seiten darauf gestoßen, dass volatile, extern, static und co in einer Tabelle als Speicherklassen aufgelistet werden. Nun kann ich ja nicht ahnen, dass eine Variable mehreren Speicherklassen zugeordnet werden kann. Zumindest in C. Seit ich den µC habe lese ich ziemlich viel in Bezug auf C. Muss ich auch, sonst kann ich aus dem "Geschäft" hier aussteigen. Ich poste hier auch nicht jede Frage rein die mir in den Sinn kommt. Wenn ich allerdings den halben Tag das Internet nach Header, volitale und Variablenübergabe durchsuche und dann einen Satz finde der da lautet: "Variablen allgemein verfügbar zu machen stellt ein besonderes Problem dar, das besonders für Anfänger schwer verständlich ist. Grundsätzlich sollte man den Variablen in Header-Dateien das Schlüsselwort extern voranstellen. Damit erklärt man dem Compiler, dass es die Variable meineVariable gibt, diese jedoch an anderer Stelle definiert ist." In Verbindung mit meiner oben genannten Fehlinterpretation, bin ich somit wieder bei euch gelandet. Das mit dem Buch, ist aber gar keine so schlechte Idee, hast du eine Empfehlung? Darf ruhig dicker sein.
A. K. schrieb: > Der Handler muss natürlich Nesting unterstützen, Gut. Der Handler, wo auch immer er sitzt, gehört bei mir zur Software. Du hast es aber gut auch die Position des Programmierers dargestellt. Reginald L. schrieb: > extern, static und co in einer Tabelle als Speicherklassen Ich glaub nicht, dass man extern zur Speicherklasse zählt. Reginald L. schrieb: > Hihi, dieser Link war meine erste Anlaufstelle ;) Allerdings steht da > nicht die Information, die ich gerade von dir bekommen habe. Soll ich sagen, dass du scheinbar die falschen Fragen stellst ;-) Der Link war für das Thema 'volatile'. Der Verweis auf Anfängerliteratur bezog sich auf die Nutzung der Schlüsselwörter. Reginald L. schrieb: > Das mit dem Buch, ist aber gar keine so schlechte Idee, hast du eine > Empfehlung? Darf ruhig dicker sein. Weiß nicht. Sollte eher dünner sein und sich "nur" mit C beschäftigen. Die restlichen Seiten sind meißt Nutzung unter Linux oder Windows. Vielleicht: Programmieren in C: Mit dem C-Reference Manual in deutscher Sprache von Kerninghan und Ritchie ISBN:3446154973
Steffen R. schrieb: > Ich glaub nicht, dass man extern zur Speicherklasse zählt. Laut diversen C-Guides, ja. Beispielsweise http://www2.informatik.uni-halle.de/lehre/c/c_storag.html Steffen R. schrieb: > Programmieren in C: Mit dem C-Reference Manual in deutscher Sprache > von Kerninghan und Ritchie Das empfiehlst du auch nur, weil da zwei Gartenzwerge aufm Einband sind!
Reginald L. schrieb: > Steffen R. schrieb: >> Ich glaub nicht, dass man extern zur Speicherklasse zählt. > > Laut diversen C-Guides, ja. Beispielsweise Ja, ok. Hast recht. (6.7.1) storage-class-specifier: typedef extern static auto register (6.7.3) type-qualifier: const restrict volatile > Steffen R. schrieb: >> Programmieren in C: Mit dem C-Reference Manual in deutscher Sprache >> von Kerninghan und Ritchie > > Das empfiehlst du auch nur, weil da zwei Gartenzwerge aufm Einband sind! ;-) Ich habs damit gelernt. Ist aber schon ewig her. C11 wirst Du dort auch nicht finden. Das Basiswissen über die Sprache aber schon. https://de.wikipedia.org/wiki/The_C_Programming_Language "Das Buch sorgte auch für die Bekanntheit des Hallo-Welt-Programms." "Es stammt von den Autoren Brian W. Kernighan und Dennis M. Ritchie, wovon Ritchie die Programmiersprache entwickelt hat." Also, wenn die nicht wissen, wie es gemeint ist ....
:
Bearbeitet durch User
Steffen R. schrieb: > Im Header steht normalerweise nur die Deklaration => extern fehlt Das müsste anders herum sein: Im Header (File xyz.h) steht die Deklaration MIT storage-class-specifier "extern". extern volatile uint32_t TriggerValue; In der zugehörigen xyz.c Datei "sollte" man den Specifier "extern" nicht nutzen. Dann legt der Compiler die Variable an. volatile uint32_t TriggerValue; // oder volatile uint32_t TriggerValue = Initvalue; Nutzt man "extern" im C File und initialisiert die Variable nicht, gibt es eine Fehlermeldung, da der Compiler die Variable dann nicht angelegt hat.
Steffen R. schrieb: > "Es stammt von den Autoren Brian W. Kernighan und Dennis M. Ritchie, > wovon Ritchie die Programmiersprache entwickelt hat." > Also, wenn die nicht wissen, wie es gemeint ist .... Ah OK, dann werde ich schauen, dass ich in die Richtung nach einem Buch schaue. Luis schrieb: > Das müsste anders herum sein War wohl nur ein Schreibfehler ;) Abermals ein Dankeschön an alle!
Hallo ihr! So langsam klappts bei mir jetzt auch mit C, Compiler und Co. Ich beginne zu begreifen. Inzwischen bin ich dabei, die Frequenz des Rotors über USB VCP an MatLab zu übergeben. Es macht richtig Fun :) Bin wieder zu CrossWorks gewechselt, EMBlocks bringt mich zur Weißglut mit seinen Fenstern und der vermeintlichen "MultiMonitor"-Unterstützung :/ Allerdings stellt sich mir hier eine weitere Frage zu volatile, in Bezug auf die obigen Posts: Wenn ich irgendwo einer Variable einen konkreten Wert zuweise, oder nur deklariere, und ich diese Variable anderswo verändere, muss ich bei der ersten Deklaration noch ein volatile davorhängen. Sonst kann es sein, dass der Compiler, falls Optimierungen aktiviert, nur diese erste konkrete Zuweisung beachtet. Nun habe ich aber der Variablen keinen konkreten Wert zugewiesen (siehe obiges Beispiel), dieser hängt ja von der Funktion "TIM_GetCounter(TIM2)" ab. Muss man hier nicht tiefer graben?
volatile unterbindet einfach gesagt nur die Optimierung. Das merkst Du speziell, wenn Du innerhalb einer Schleife auf die Veränderung der Variablen wartest. Ohne volatile würde der Compiler meinen, dass der Wert im Register immer aktuell ist. Der Interrupt würde aber nicht das Register, sondern den Speicher verändern. Und zu Deklaration und Definition. Bis auf wenige Ausnahmen solltest Du diese immer gleich machen (+ 'extern' natürlich). Also keine Variationen, wenn du nicht explizit weißt, dass es in dem speziellen Fall anders ist.
:
Bearbeitet durch User
Achso, also im Falle eines Timers ohne Interruptroutine, würde sowieso auf das Register zugegriffen werden und man bräuchte hier kein volantile, habe ich das richtig verstanden? Klick hat es noch nicht gemacht, aber ich glaube es geht in die richtige Richtung. Muss mich wohl ein wenig in die Hardware reinarbeiten. PS: Morgen müsste übrigens das von dir empfohlene Buch ankommen, dazu habe ich noch dieses "Lösungsbuch" bestellt. Gebraucht, war nicht teuer ;)
Reginald L. schrieb: > Achso, also im Falle eines Timers ohne Interruptroutine, würde sowieso > auf das Register zugegriffen werden und man bräuchte hier kein > volantile, habe ich das richtig verstanden? Habe ich es wohl doch zu stark vereinfacht. Für die Variable, in der Du den Zählerwert speicherst, bräuchtest du es nicht. Die Register des Timers sind im allgemeinen jedoch volatile. Diese ändern sich ja ohne Kontrolle des Programms selbsttätig.
Steffen R. schrieb: > Für die Variable, in der Du den Zählerwert speicherst, bräuchtest du es > nicht. Die Register des Timers sind im allgemeinen jedoch volatile. > Diese ändern sich ja ohne Kontrolle des Programms selbsttätig. Bin da immer noch nicht durchgestiegen. Spätestens, wenn mein Programm nicht das tut, was es meiner Meinung nach tun sollte, werde ich dahintergestiegen sein. Learning-by-doing ;)
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.