Hi,
nachdem ich mittels Polling schon einzelne Zeichen empfangen kann,
möchte ich einen Schritt weiter gehen und meine Empfangsroutine
interruptfähig machen. Aus eigenem Bestreben möchte ich gerne auf den
Einsatz der ST-Firmware-Library verzichten - man hat irgendwie überhaupt
keine Ahnung auf welche Register die einzelnen Funktionen zugreifen...
Ich hab versucht möglichst viele Informationen aus dem Reference Manual,
den Beispielprogrammen von ST und den Threads im Internet zu quetschen.
Leider hab ich bis jetzt überhaupt keine Erfahrungen mit Interrupts auf
dem Cortex-M3.
Meine bisherigen Überlegungen sehen so aus:
Wenn ich das Reference Manual richtig verstanden habe, dann muss ich das
USART_CR1_RXNEIE Flag setzen? Im Interrupt Handler wird dann geprüft ob
ein Zeichen im Empfangsbuffer liegt:
1
voidUSART1_IRQHandler(void)
2
{
3
if(USART1->SR&USART_SR_RXNE)
4
{
5
zeichen=USART1->DR;
6
[....]
7
}
8
[....]
9
}
In einem Beispielprogramm von ST hab ich dann noch folgendes gefunden:
1
2
/* Enable the USARTy Interrupt */
3
NVIC_InitStructure.NVIC_IRQChannel=USARTy_IRQn;
4
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
5
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
6
NVIC_Init(&NVIC_InitStructure);
Nur was macht der Codeauszug? Ich hab im Reference Manual nach dem
Begriff "NVIC" gesucht, aber da finde ich gerade mal 3 Seiten, die mich
als absoluten Anfänger, jetzt nicht soviel weiter bringen..
Irgendwie steh ich grad voll an. Ich finde im Internet zwar ziemlich
viele Infos, aber überall nur Codeauszüge, die mit der ST-Firmware_Lib
einhergehen...
Ich hoffe, mir kann jemand die Funktionsweise von Interrupts auf einem
Cortex M3 näher bringen - im Moment bin ich einfach nur total verwirrt!
Danke!
Den Insiders Guide von Hitex kenn ich. Das Buch klingt echt interessant
- mal schauen vielleicht leg ich mir das zu. Ich werd mal die ganzen
Manuals studieren und mich dann nochmal melden.
Danke für die Tipps!
Hallo,
hab mir jetzt mal die ganzen Manuals hergenommen und ein bisschen
quergelesen. Ich hoffe ich hab das jetzt richtig verstanden: Um einen
Interrupt zu aktivieren gehe ich her und setze im "Interrupt-Set-Enable"
Register an geeigneter Stelle einen 1er. Die Bitposition entspricht
dabei der Position in der Vektortabelle im Startup File?
Vorsicht.
Das ist im NVIC m.E. ein wenig unpraktisch gelöst.
Die ersten 16 Vektoren (0 - 15) sind sog. Systemvektoren, die Du in
jedem Cortex-M3 (ST, TI, NXP,...) hast. Diese werden im Register "System
Handler Control and State Register" (0xE000ED24) ein-/ausgeknipst
(sofern das möglich ist - beim NMI natürlich nicht). Siehe ARM Doku DDI
0337G Seite 8-29 ff.
Alle weiteren Vektoren (16 - n) schaltest Du - wie Du bemerkt hast -
über IRQ n to m Set Enable Register ein/aus. Selbes Dokument, Seite 8-13
ff.
Ist ein wenig verwirrend, hatte es am Anfang auch falsch :-/
Gut zu wissen, dass die Systemvektoren in einem anderen Register
konfiguriert werden. Da hätte ich wieder ewig gesucht.
Aber um den USART1 Interrupt zu enablen, brauch ich ja erstmal die
Systemvektoren nicht anzurühren, oder?
Oben hab ich geschrieben, dass die Bitposition im SETENA (Set-Enable)
Register der Position in der Vektortabelle im Startup File entspricht.
Mein Startup File sieht so aus:
Der Eintrag, der für mich interessant ist (USART1 Interrupt) steht an
37.Stelle. Da das SETENA Register nur 32bit breit ist, hab ich da ja
dann ein Problem? Kann ich jetzt einfach hergehen und die Zeile
1
DCDUSART1_IRQHandler;USART1
an die oberste Stelle kopieren, sodass dies im SETENA Register dem
ersten Bit entspricht?
Oder versteh ich da gerade etwas total falsch?
Da sind nur die Systemvektoren hart eingetragen. Zur Laufzeit kopiere
ich die Tabelle ins SRAM und trage dort dann die Vektoren ein, die ich
je nach Applikation benötige.
> Oder versteh ich da gerade etwas total falsch?
Teilweise... ;)
UART 1 liegt an Index 53. Da 'pokst' Du dann die Adresse Deiner ISR
rein, setzt im Interrupt Set-Enable Register dann eine 1 an der
richtigen Stelle (müsste in 0xE000E104 das Bit Nr. 4 sein, d.h. 'das
fünfte von rechts' ;) -> Index 53 - 16 (Systemvektoren) = 37).
Es gibt nicht nur EIN Interrupt Set-Enable Register! Das ERSTE liegt bei
0xE000E100 für die ersten 32 Applikationsvektoren (oben Index 16 bis
47), bei 0xE000E104 liegt das zweite für die zweiten 32
Applikationsvektoren (oben Index 48 bis 79). Klaro?
Schau ins Usermanual von ST (RM0008) Kap 9.1.2 Table 52. Die Angaben in
der Spalte 'Position' sind für die Interrupt-Set-Enable Register die
wichtigen.
BTW: wieso enthält Deine Vektortabelle keine Systemvektoren (0..15)?
oder sind die weiter vorne im Code?
Die Systemvektoren sind bei mir weiter vorne im Code:
1
__VectorsDCD__initial_sp;TopofStack
2
DCDReset_Handler;ResetHandler
3
DCDNMI_Handler;NMIHandler
4
DCDHardFault_Handler;HardFaultHandler
5
DCDMemManage_Handler;MPUFaultHandler
6
DCDBusFault_Handler;BusFaultHandler
7
DCDUsageFault_Handler;UsageFaultHandler
8
DCD0;Reserved
9
DCD0;Reserved
10
DCD0;Reserved
11
DCD0;Reserved
12
DCDSVC_Handler;SVCallHandler
13
DCDDebugMon_Handler;DebugMonitorHandler
14
DCD0;Reserved
15
DCDPendSV_Handler;PendSVHandler
16
DCDSysTick_Handler;SysTickHandler
Wenn ich dich jetzt richtig verstanden habe, dann schalte ich den
gewünschten USART1 Interrupt mit der folgenden Zeile ein:
NVIC->ISER[1] = (1<<6);
Stimmt das?
37 - 32 = 5.
vvvvvvvvvvvvvvvvvvvvvvv
NVIC->ISER[1] = (1<<4);
^^^^^^^^^^^^^^^^^^^^^^^
NVIC->ISER[1] |= 0x00000010;
Das oder | sollte rein, denn es könnten ja noch andere ISRs an sein.
Kleiner Nachtrag:
Ich hab mich oben verzählt, der USART1 Interrupt steht an der 38.Stelle.
Das heißt, um den USART1 Interrupt zu aktivieren ist folgende Zeile
nötig:
NVIC->ISER[1] |= 0x00000020;
Der Interrupt funktioniert jetzt tadellos. Herzlichen Dank an alle, die
mir den richtigen Weg aufgezeigt haben!
Hallo,
Ich würde gerne was Ähnliches machen und zwar Hab ich eine
Hauptfunktion laufen und sobald ich von der USART2 ein Befehl erhalte
oder Zeichen empfange, soll eine entsprechende Funktion (je nach
empfangenen Zeichen) ausgeführt werden.
Kann mir da vielleicht jemand helfen?
Die ToolChain_STM32 ist OpenSource und bietet u.a. ein
interruptgesteuertes USART Interface. Zum VErständnis gibt es einige
Beispielprogramme.
Zu finden ist die ToolChain hier:
http://thetoolchain.com
Hallo,
ich habe zu diesem Thema UART mit Interrupts am STM32 auch eine Frage.
Und zwar wird bei mir ein Interrupt ausgelöst, wenn ich den UE, TE, RE
und die IRQ-Enable-Bits TCIE und RXNEIE setze. Und wenn später in der
Software Daten senden will und in das DR-Register schreibe, kommt kein
Interrupt mehr.
Hier mein Code:
Ich habe gemerkt, dass mein Debugger (STM32VL-Discovery mit SWD) sich
unterschiedlich verhält. Mal springt er nur einmal beim Aktivieren des
UARTs (UE, TE, RE) direkt in die ISR. Nach einem Reset springt er nach
UART-Initialisierung andauernd in die ISR. Das Verhalten ist völlig
komisch.
Kann mir jemand einen Code der UART mit IRQ-Verwendung zur Durchsicht
zur Verfügung stellen?