Hallo STM Experten! Entweder habe ich nach den falschen Schlüsselwörtern gesucht oder ich stehe ein bisschen auf dem Schlauch... Mein Vorhaben: Ich will bei einem STM8S mittels TIM4 Interrupt einen Counter inkrementieren. Soweit so fein. Ich hab jetzt gefühlt schon 100 Beispiele aus dem Netz durchgelesen und versucht zu verstehen wie dieser Vorgang funktioniert. Eines vorneweg, Ich verwende die STDLib und IAR EW for STM8 und einen STM8003f3. Es geht mir hier rein ums Verständnis. Meine Überlegung: Wenn ich den Clock und den Timer konfiguriert habe, dann generiert mir der TIM4 bei jedem Überlauf einen Interrupt. Die Preisfrage die sich mir stellt ist. Wie kann ich diesen Interrupt "abgreifen"? Es gibt Beispiele im Netz bei denen einfach der TIM4 Counter im main.c verwendet wird und per if-Bedingung überprüft wird ob eine gewisse Anzahl an Counts abgelaufen ist. Das ist aber nicht Sinn und Zweck der Veranstaltung... (meiner Meinung nach). Dann gibts noch Beispiele wo im stm8s_it.c in der Methode vom Interrupt Handler Codezeilen hinzugefügt werden, zb um Ausgänge zu ändern... Und zu guter Letzt finde ich noch Beispiele wo mit #pragma vector = HEX-Wert gearbeitet wird. TIM4_OVR_UIF dürfte das Bit(oder Konstrukt) sein dass beim Overflow den Interrupt sozusagen auslöst. Aber ganz blicke ich da nicht durch. Vielleicht hab ich auch nur etwas übersehen. Vielleicht könnt ihr mir erklären wann welche Vorgehensweise zu wählen ist, welche Vorteile/Nachteile diese drei haben und wie der Interrupt funktioniert. Anbei drei exemplarische Beispiele anhand derer ich versucht habe mir das ganze herzuleiten... https://programmer.group/stm8s-timer-basic-interrupt-timing.html http://www.emcu.it/STM8/STM8-Discovery/Tim4/TIM4.html http://embedded-lab.com/blog/starting-stm8-microcontrollers/18/ Ich hoffe ihr könnt mir den entscheidenden Puzzlestein liefern, Danke schon mal!
Ohne den stm8 zu kennen MB schrieb: > Wenn ich den Clock und den Timer konfiguriert habe, dann generiert mir > der TIM4 bei jedem Überlauf einen Interrupt. Die Preisfrage die sich mir > stellt ist. Wie kann ich diesen Interrupt "abgreifen"? Es gibt Beispiele Vielleicht solltest du dich noch einmal mit dem Grundprinzip "Interrupt" beschäftigen, da du es scheinbar noch nicht ganz verstanden hast. Beim überfliegen der links wird es dort ja scheinbar ganz gut erklärt. Datenblatt lesen hilft da ungemein. Der Interrupt wird nicht abgegriffen und es gibt auch keinen Konstruktor. Bei aktivierten Interrupts wird das Hauptprogramm bzw. die Main Funktion unterbrochen und die ISR (interrupt service routine) wird ausgeführt. : > im Netz bei denen einfach der TIM4 Counter im main.c verwendet wird und > per if-Bedingung überprüft wird ob eine gewisse Anzahl an Counts > abgelaufen ist. Das ist aber nicht Sinn und Zweck der Veranstaltung... > (meiner Meinung nach). Das macht dann Sinn, wenn man interrupts vermeiden möchte oder einfach nicht benötigt. Beispiel (sehr rudimentär): es soll ein einfacher Scheduler implementiert werden, der Tasks zyklisch alle 1ms, 5ms und 10ms aufruft. Hier benötigt man keine interrupts. Das timer register wird in einer Schleife gepollt und bei entsprechendem Wert die Task ausgeführt. Bei erreichen der 10ms wird das timer register zurück gesetzt. Benötigte interrupts: 0 > Dann gibts noch Beispiele wo im stm8s_it.c in der > Methode vom Interrupt Handler Codezeilen hinzugefügt werden, zb um > Ausgänge zu ändern... Der ausgeführt Code in der ISR sollte nicht zu groß werden, deine Idee einen counter in der isr zu inkrementieren und in deiner main auszuwerten ist richtig. Interrupt flag löschen nicht vergessen. > Und zu guter Letzt finde ich noch Beispiele wo mit > #pragma vector = HEX-Wert gearbeitet wird. Wie gesagt, ohne je mit dem stm8 gearbeitet zu haben., schätze ich mal, hier wird die isr dem Interrupt vector zugewiesen. RTFM. Gruß
> IAR EW for STM8 Da wird auch Dokumentation mit installiert. Z.B. der "IAR C/C++ Development Guide". Der enthaelt auch einen Abschnitt: "Primitives for interrupts, concurrency, and OS-related programming" Den musst du lesen, und nicht > 100 Beispiele aus dem Netz. Wenn der Controller nichts weiter zu tun hat, kann man natuerlich > per if-Bedingung den Timer auswerten. In diesem Fall reicht das als "Sinn und Zweck". Tu dir einen Gefallen und benutze fuers Kennenlernen etwas groesseres als den STM8003f3. Z>B. den STM8 der auf dem STM8-Discovery sitzt. Das hat auch gleich einen STM8 tauglichen ST-Link dabei. Ich benutze hier zur Entwicklung z.B. einen STM8S208RBT6.
Larry schrieb: > Tu dir einen Gefallen und benutze fuers Kennenlernen > etwas groesseres als den STM8003f3 Käse, gerade kleine controller sind zum Einstieg besser als große IMHO, oder ist der STM8003F3 so eine Gurke, a la PIC10, ohne on-chip debugger? (nicht on-board debugger) Larry schrieb: > Da wird auch Dokumentation mit installiert. > Z.B. der "IAR C/C++ Development Guide". Das, und das Datenblatt bzw ANs des Chips/Herstellers.
Ganz Klar schrieb: > Larry schrieb: >> Da wird auch Dokumentation mit installiert. >> Z.B. der "IAR C/C++ Development Guide". > > Das, und das Datenblatt bzw ANs des Chips/Herstellers. *lesen Etwas unglücklich formuliert.
Eines vorneweg, mir ist klar was ein Interrupt macht, nur nicht wie er "genau" funktioniert. Dass der Interrupt das laufende Programm unterbricht(weswegen er auch Interrupt heisst) ist bekannt, die Datenblätter und sonstige RefMans hab ich auch gelesen... auch mehrmals. Ganz Klar schrieb: > Der Interrupt wird nicht abgegriffen und es gibt auch keinen > Konstruktor. Bei aktivierten Interrupts wird das Hauptprogramm bzw. die > Main Funktion unterbrochen und die ISR (interrupt service routine) > wird ausgeführt. Das ist der fehlende Teil der sich mir, warum auch immer nicht erschlossen hat. Das pollen will ich mir ersparen, denn dass funktioniert doch nur solange richtig bis das Timer-Counter Intervall kürzer wird als ein gesamter Programmdurchlauf... Das läuft dann als "Hardware-Schleife" dh. nicht eine Methode zählt rauf sondern die Hardware. Macht der Timer jedoch in der Zeit eines Programmdurchlaufs mehr als einen Count kann es passieren dass man beim pollen ein paar Counts über Ziel hinaushaut. Ganz Klar schrieb: >Der ausgeführt Code in der ISR sollte nicht zu groß werden, deine Idee >einen counter in der isr zu inkrementieren und in deiner main >auszuwerten ist richtig. Interrupt flag löschen nicht vergessen. Soweit war meine Überlegung also richtig. Larry schrieb: > Da wird auch Dokumentation mit installiert. > Z.B. der "IAR C/C++ Development Guide". > Der enthaelt auch einen Abschnitt: > "Primitives for interrupts, concurrency, and OS-related programming"... Asche auf mein Haupt, DIESE Hilfe hab ich tatsächlich noch nicht gelesen... Auszug:
1 | #pragma vector = UART1_R_RXNE_vector /* Symbol from I/O */ |
2 | __interrupt void MyInterruptRoutine(void) |
3 | {
|
4 | /* Do something */
|
5 | }
|
Nur damit ich das jetzt richtig verstanden habe... Mit dem "__interrupt" definiere ich eine sogenannte "Interrupt-Funktion", dann kommt das verpflichtende void für den Rückgabewert, dann kommt der Funktionsname. und zum Schluss der Anweisungsblock... so wie bei jeder anderen Methode/Funktion auch. um zb den Interrupt des TIM4 zu verwenden im main.c :
1 | ...
|
2 | #pragma vector = 0x19 //TIM4 Update/Overflow
|
3 | __interrupt void TIM4OVR(void) |
4 | {
|
5 | count++ |
6 | if(count>3) |
7 | {
|
8 | count=0; |
9 | action=true; |
10 | }
|
11 | TIM4_ClearITPendingBit(TIM4_IT_UPDATE); |
12 | }
|
13 | ...
|
muss ich den #pragma vector immer direkt vor der __interrupt Funktion schreiben damit er weiss bei welchem Interrupt ich welche Interruptfunktion ausführen will? Weil der Name der Funktion, also das TIM4OVR kann ich mir ja aussuchen oder? Danke für die prompte Hilfe!
MB schrieb: > #pragma vector = 0x19 //TIM4 Update/Overflow Schreib wie in dem Beispiel den Namen hin und kein magische Nummer. Dann brauchst Du auch den Kommentar nicht. Bei einem anderen Derivat kann nämlich die Nummer eine andere sein.
Der STM8003F3 ist m.W. einer der Kandidaten, aus dem man sich
bei "ungeschickter" Programmierung ganz aussperren kann.
Verifizieren darf der TO die Aussage gerne selber.
> gerade kleine controller sind zum Einstieg besser
Beim STM8S sind die Funktionseinheiten immer die selben.
Nur haben manche STM8 eben nicht alle oder weniger davon.
Im Sinne der Komplexitaet gibt es also kein klein oder gross.
Ein STM8S208RBT6 hat ein Superset all dieser Einheiten.
D.h. alles was im Referenzmanual zum STM8S steht, kann man
mit ihm ausprobieren. Die Art und Weise wie die Peripherie
angesprochen wird, ist auch innerhalb der Serie gleich,
und daher nicht schwieriger oder leichter.
Zum Kennenlernen ist daher der abgespeckte STM8003F3
denkbar ungeeignet.
> Weil der Name der Funktion, also das > TIM4OVR kann ich mir ja aussuchen oder? Darueber solltest du noch einmal lange und gruendlich nachdenken.
MB schrieb: > muss ich den #pragma vector immer direkt vor der __interrupt Funktion > schreiben damit er weiss bei welchem Interrupt ich welche > Interruptfunktion ausführen will? Das steht in der Dokumentation des Compilers. Was glaubst du, warum dir alle immer wieder sagen, daß du die lesen sollst? Interrupts sind kein Teil des C-Standards. Deswegen kann das jeder C-Compiler anders machen. Und macht es auch. Für den STM8 gibt es Compiler mindestends von Keil (IAR), von Cosmic und den SDCC. Jeder macht das mit den Interrupts ein bißchen anders. > Weil der Name der Funktion, also das > TIM4OVR kann ich mir ja aussuchen oder? Bei deinem Compiler anscheinend ja. Andere Compiler verwenden einfach "magische" Namen, an denen der Compiler erkennt, an welchen Vektor er die Funktion anbinden muß.
MB schrieb: > Das ist der fehlende Teil der sich mir, warum auch immer nicht > erschlossen hat. Na hat es denn jetzt klick gemacht oder muss es noch weiter erklärt werden? MB schrieb: > Das pollen will ich mir ersparen, denn dass funktioniert doch nur > solange richtig bis das Timer-Counter Intervall kürzer wird als ein > gesamter Programmdurchlauf... Das läuft dann als "Hardware-Schleife" dh. > nicht eine Methode zählt rauf sondern die Hardware. Macht der Timer > jedoch in der Zeit eines Programmdurchlaufs mehr als einen Count kann es > passieren dass man beim pollen ein paar Counts über Ziel hinaushaut. Es kommt ganz auf den Anwendungsfall und die benötigte Genauigkeit an, gleiches gilt für die Timer Auflösung (ticks per us/ms/s). Interrupts können auch problematisch werden. MB schrieb: > muss ich den #pragma vector immer direkt vor der __interrupt Funktion > schreiben damit er weiss bei welchem Interrupt ich welche > Interruptfunktion ausführen will? Das hängt vom Compiler ab, ich vermute sehr stark: ja. RTFM! > Weil der Name der Funktion, also das > TIM4OVR kann ich mir ja aussuchen oder? RTFM! Und wenn dem so ist, sollte man wie immer "meaningful names' vergeben.
Larry schrieb: > Ein STM8S208RBT6 hat ein Superset all dieser Einheiten. So habe ich mir es schon gedacht, war aber schlicht weg zu faul es herauszufinden.
Sodala... Nach einem ausgiebigem Mittagessen und nochmaligem Studium der IAR-eigenen Hilfeseiten habe ich auch noch die Hilfeseite zu den "Pragma-Directives" gefunden. Konklusio: Nach der Pragma-Directive folgt immer eine Interrupt- oder Trap-Funktionsdeklaration. UND Beim nächsten mal, noch länger die Dokumentation(en) durchlesen. Ob ich bei den kryptischen Zahlen werde, die man direkt aus dem Datenblatt des jeweiligen µC entnehmen kann, oder ob die Aussagekräftigeren Namen(zu finden im stm8s_it.c) zur anwendung kommen weiss ich noch nicht. Jedenfalls hat sich ein relativ großes Fragezeichen in Wohlgefallen aufgelöst. Danke an alle!
> kryptischen Zahlen werde, die man direkt aus dem > Datenblatt des jeweiligen µC entnehmen kann Da hast du wohl noch nicht genug gelesen. Lies mal weiter. Lesen bildet!
1 | /*------------------------------------------------------------------------- |
2 | * Interrupt vector numbers |
3 | * |
4 | * Note: The vector numbers listed in ST's manuals for STM8 are offset |
5 | * by 2 compared to the vector numbers used by EWSTM8. |
6 | *-----------------------------------------------------------------------*/ |
7 | #define AWU_vector 3 /* IRQ No. in STM8 manual: 1 */ |
8 | #define CLK_CSS_vector 4 /* IRQ No. in STM8 manual: 2 */ |
9 | #define CLK_SWITCH_vector 4 /* IRQ No. in STM8 manual: 2 */ |
10 | #define EXTI0_vector 5 /* IRQ No. in STM8 manual: 3 */ |
11 | |
12 | ... |
MB schrieb: > Ob ich bei den kryptischen Zahlen werde, die man direkt aus dem > Datenblatt des jeweiligen µC entnehmen kann Die Vectornamen lassen sich auch sehr leicht aus dem Datenblatt herleiten.
Larry schrieb: > Beim STM8S sind die Funktionseinheiten immer die selben. > Nur haben manche STM8 eben nicht alle oder weniger davon. > Im Sinne der Komplexitaet gibt es also kein klein oder gross. > Ein STM8S208RBT6 hat ein Superset all dieser Einheiten. > D.h. alles was im Referenzmanual zum STM8S steht, kann man > mit ihm ausprobieren. Die Art und Weise wie die Peripherie > angesprochen wird, ist auch innerhalb der Serie gleich, > und daher nicht schwieriger oder leichter. Das stimmt so leider nicht: es gibt Varianten der verschiedenen Funktionseinheiten mit verschiedenen Leistungsmerkmalen. Einige Leistungsmerkmale gibt es nur bei RM0016 "Low density devices" wie STM8S003 oder STM8S903. So hat z.B. der ADC1 in Low Density hat einen "Buffered continuous conversion mode", diesen gibt es beim ADC2 des STM8S208RB nicht. Bei den UART-Varianten gibt es noch mehr Unterschiede (UART1..4) (STM8S208RB hat UART1 und UART3, STM8S105K6 hat einen UART2). Nicht immer kann man diesen Nummern wirklich trauen (teilweise Zweitmarkt für Automotive-Produkte). Weitere Unterschiede ergeben sich im Speicherzugriff (Read-While-Write): Testen von EEPROM-Schreiben mit High Density dürfte zu Überraschungen bei Low Density führen. Es ist übrigens spannend, wie hier Komplexität mit Kompliziertheit verwechselt wird. Leider ist das Thema nicht nur kompliziert. Der Umstand, dass dies nicht leicht zu sehen ist, liegt an der Komplexität. > Zum Kennenlernen ist daher der abgespeckte STM8003F3 > denkbar ungeeignet. Auch da kann ich nicht zustimmen. Ein STM8S103F3P6 kann ohne weiteres auf einem Steckbrett getestet werden. Das geht beim großen High Density Bruder in der Variante STM8S207K8T6C zwar auch, aber die ist letztlich ebenfalls abgespeckt (32pin), ist bei weitem nicht so leicht zu bekommen und muss erst auf einen LQFP32-Adapter gelötet werden. Den STM8S103F3P6 auf einer blauen Leiterkarte gibt's dagegen für 80ct fertig aus China (oder für 30ct wenn man ein wenig löten möchte).
Hi Na ja, so wirklich aufschlußreich fand ich eure Erklärungen zu Interrupts nicht. Daher hab ich mich mal entschlossen, solche Begriffe wie Interrupt Service Routine (ISR) und Interrupt Vektor Tabelle (IVT) nochmal zu erläutern. Richtig ist, das ein Hauptprogramm gar nichts vor der ISR weiß und diese auch nicht aufruft. Es ist die interne Struktur eines Controllers oder Prozessors, die bei einem Interrupt dem Programmcounter nach Ablegen der Rücksprungadresse eine fest verdrahtete Adresse im Programmspeicher zuweist. Sozusagen eine Hardwareadressierung. Da diese Speicherzelle nur für einen Befehl Platz hat, ist es ziemlich übersichtlich. Nur, wenn nur ein Befehl dort Platz hat, wie funktioniert dann ein Interrupt. ganz einfach, entweder steht dort ein RETI, also ein Return from Interrupt, oder ein Sprungbefehl zu der ISR. Diese schließt dann mit dem RETI ab. Hier ist genug Platz für die erforderlichen Sicherungen der verwendeten Register, denn ein Interrupt kann zu jeder Zeit an einer x-beliebigen Programmstelle auftreten und da sind dann u. U. die Inhalte der Rechenregister verloren, wenn sie nicht mit Push und Pop in der ISR gesichert werden. In meinen Anfängerjahren sprach man oft davon, eine Interruptadresse zu verbiegen. Nun, ganz einfach, die in der IVT hinterlegte Adresse der ursprünglichen ISR mit der Adresse des eigenen Programmes versehen und dieses dann abschließend mit einem Sprung in die ursprüngliche ISR zu versehen. Bis Win98 war dies auf jedem Windowsrechner ohne Probleme möglich. So konnte eine Schnittstelle ganz schnell für eigene Bedürfnisse interruptfähig angepaßt werden. Aber jetzt noch mal ganz kurz: Interrupt : Prorammcounter wird wie beim Aufruf eines Unterprogramms gesichert Programmcounter erhält eine dem Interrupt zugewiesene Adresse in der IVT Dort steht entweder ein RETI (keine Bearbeitung) oder ein Sprungbefehl (ISR) Rücksprung aus der ISR erfolgt mit einem RETI, (gesicherte Adresse wird in den Programmcounter eingetragen) Das sollte immer noch für alle Prozessoren und Controller im Prinzip so ablaufen. Gruß oldmax
Beim STM8 steht die Vektortabelle fix im Flash ab 0x008004. Verbiegen muss man ihn dafuer nicht :-). Ein VTOR Register wie bei einigen ARMs, um die Adresse dieser Tabelle festzulegen hat der STM8 leider nicht. In der Vektortabelle steht die Adresse der ISR und kein Sprungbefehl. Statt eines RETI, wird bei vom Programmierer unbelegten Vektoren, eine Default ISR ausgefuehrt. Das kann auch ein Sprung auf sich selbst sein. Das sollte der TO bei seiner Compilerversion noch verifizieren. Die Default ISR ist Bestandteil der Laufzeitumgebung des Compilers. In den IAR Kickstartversionen hat man u.U. keinen Zugriff auf die Quellen dieser Umgebung. Das muss man sich dann im Debugger ansehen wie die Default ISR programmiert wurde. Wenn man sich selbst bei den Vektoren vertut, wird diese Default ISR dann bei einem Interrupt ausgeloest. Mal so als Ergaenzung zu oldmax hilfreichen Beitrag. > STM8S003 oder STM8S903 Da hab ich ja Glueck. Die setze ich nicht ein. Meine kleinsten sind die STM8S105K4T6.
Martin V. schrieb: > Hi > Na ja, so wirklich aufschlußreich fand ich eure Erklärungen zu > Interrupts nicht. Daher hab ich mich mal entschlossen, solche Begriffe > wie Interrupt Service Routine (ISR) und Interrupt Vektor Tabelle (IVT) > nochmal zu erläutern.... Na da ist aber auch Halbwissen und Pauschalisierung im Spiel... Natürlich passiert das context switching, Sicherung der register, PC, etc... Ich hatte auch kurz überlegt, damit anzufangen - hatte auch schon einen Satz zu RETI getippt, aber auf Grund der Fragestellungen wieder Abstand genommen. Erst Doku lesen, dann fragen!
Hi Ich will darauf noch mal kurz eingehen.. Larry schrieb: > Beim STM8 steht die Vektortabelle fix im Flash ab 0x008004. > Verbiegen muss man ihn dafuer nicht :-). > Ein VTOR Register wie bei einigen ARMs, um die Adresse dieser > Tabelle festzulegen hat der STM8 leider nicht. > In der Vektortabelle steht die Adresse der ISR und kein > Sprungbefehl. Ok, Die IVT steht wohl in jedem Prozessor / Controller irgendwo und wird auch nicht verbogen. Irgendwie müssen ja die Adressen hingepackt werden, die eine eingebaute Hardware bei einem ausgelösten Interrupt in den Programmcounter pakt, um die ISR abzuarbeiten. Aber, sind schon ISR eingebaut, ist ein "Verbiegen" der Adresse der ISR auf eine eigene Ergänzung der vorhandenen ISR durch ein Zwischenschalten hier möglich. Und der Ausdruck "Spruungbefehl" ist natürlich nicht so wörtlich zu nehmen, hat sich aber eingebürgert. Ein Unterproramm wird auch nicht "gecalled" oder zu deutsch aufgerufen. Wenn da eine Adresse steht landet diese im Programmcounter. Bei einem "Sprung" ohne eine Sicherung auf dem Stack, bei einem "Call" mit einer Ablage der Rücksprungadresse auf dem Stack und ein Interrupt ist im Prinzip wie ein "Call" mit ein paar Besonderheiten. Dir Larry brauch ich es nicht erklären, aber der Fragesteller hat zwar gesagt, das ihm ISR und IVT irgenwie etwas sagen, er aber trotzdem nicht weiß, wo er die ISR "abgreifen" kann. Und ich denke, das meine Erklärung dazu ein wenig hilfreich war. Ach ja, sorry, das ich Begriffe wie Jmp und Call nutze. Ein C Programm hat da sicherlich einen anderen Befehlssatz für, aber da hab ich nun keine Ahnung von.... Gruß oldmax
Martin V. schrieb: > Ein C Programm hat da sicherlich einen anderen Befehlssatz für, aber da > hab ich nun keine Ahnung von.... Aua. Ein C-Programm hat gar keinen Befehlssatz in diesem Sinne. Die tool chain (compiler, linker assembler) übersetzt das ganze von C "in den Befehlssatz" der Zielarchitektur. Als C-Entwickler muss man sich eben nicht mit RETI, context switching und nur bedingt mit IVT herum schlagen. Das. Macht eben die tool chain mehr oder weniger gut automatisch (über pragma, Namen oder Linker Skript).
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.