STM32 korrekte Interrupt-Handhabung

OP (Firma: HEGRO GmbH) #4224527
Lesenswert?

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.
Gast #4224532
Lesenswert?

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?
Gast #4224543
Lesenswert?

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?"
;-)
OP (Firma: HEGRO GmbH) #4224574
Lesenswert?

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.
Gast #4224594
Lesenswert?

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.
Gast #4224595
Lesenswert?

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.
Gast #4224621
Lesenswert?

> 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.
OP (Firma: HEGRO GmbH) #4224639
Lesenswert?

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 :)
#4224647
Lesenswert?

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.
Gast #4224671
Lesenswert?

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.
Gast #4224672
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4224709
Lesenswert?

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 :)
Gast #4225122
Lesenswert?

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:-)
Gast #4225126
Lesenswert?

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
#4225225
Lesenswert?

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.
Gast #4225260
Lesenswert?

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 ...
OP (Firma: HEGRO GmbH) #4225355
Lesenswert?

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.
#4225383
Lesenswert?

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.
Gast #4225396
Lesenswert?

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!
Gast #4225404
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4225415
Lesenswert?

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 :)
OP (Firma: HEGRO GmbH) #4225431
Lesenswert?

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 :)
OP (Firma: HEGRO GmbH) #4225481
Lesenswert?

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?
Gast #4225505
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4225520
Lesenswert?

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) ===|
Gast #4225533
Lesenswert?

>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>
#4225608
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4225629
Lesenswert?

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.
#4225669
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4225670
Lesenswert?

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.
#4225701
Lesenswert?

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
OP (Firma: HEGRO GmbH) #4225721
Lesenswert?

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!
#4225780
Lesenswert?

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 ....
Gast #4225818
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4225960
Lesenswert?

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!
OP (Firma: HEGRO GmbH) #4229035
Lesenswert?

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?
#4229098
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4229206
Lesenswert?

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 
;)
#4229636
Lesenswert?

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.
OP (Firma: HEGRO GmbH) #4231331
Lesenswert?

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 ;)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren