www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik [STM32] USART + Interrupt


Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
void USART1_IRQHandler (void)
{
 if(USART1->SR & USART_SR_RXNE)
 {
   zeichen = USART1->DR;
   [....]
 }
[....]
} 

In einem Beispielprogramm von ST hab ich dann noch folgendes gefunden:
 
  /* Enable the USARTy Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USARTy_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  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!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der NVIV gehört zu den Kernkomponenten des Cortex-M3 und deren Doku 
findet man daher nicht in der STM32 Reference sondern in der Cortex-M3 
Doku von ARM und dem Cortex-M3 Programming Manual zum STM32.

Für das Verständnis nützlicher: 
http://www.amazon.de/Definitive-Guide-Cortex-M3-Em...
und der Insiders Guide
http://www.st.com/mcdfiles/1221142709.pdf

Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-/

Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
; External Interrupts
                DCD     WWDG_IRQHandler           ; Window Watchdog
                DCD     PVD_IRQHandler            ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler         ; Tamper
                DCD     RTC_IRQHandler            ; RTC
                DCD     FLASH_IRQHandler          ; Flash
                DCD     RCC_IRQHandler            ; RCC
                DCD     EXTI0_IRQHandler          ; EXTI Line 0
                DCD     EXTI1_IRQHandler          ; EXTI Line 1
                DCD     EXTI2_IRQHandler          ; EXTI Line 2
                DCD     EXTI3_IRQHandler          ; EXTI Line 3
                DCD     EXTI4_IRQHandler          ; EXTI Line 4
                DCD     DMAChannel1_IRQHandler    ; DMA Channel 1
                DCD     DMAChannel2_IRQHandler    ; DMA Channel 2
                DCD     DMAChannel3_IRQHandler    ; DMA Channel 3
                DCD     DMAChannel4_IRQHandler    ; DMA Channel 4
                DCD     DMAChannel5_IRQHandler    ; DMA Channel 5
                DCD     DMAChannel6_IRQHandler    ; DMA Channel 6
                DCD     DMAChannel7_IRQHandler    ; DMA Channel 7
                DCD     ADC_IRQHandler            ; ADC
                DCD     USB_HP_CAN_TX_IRQHandler  ; USB High Priority or CAN TX
                DCD     USB_LP_CAN_RX0_IRQHandler ; USB Low  Priority or CAN RX0
                DCD     CAN_RX1_IRQHandler        ; CAN RX1
                DCD     CAN_SCE_IRQHandler        ; CAN SCE
                DCD     EXTI9_5_IRQHandler        ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler       ; TIM1 Break
                DCD     TIM1_UP_IRQHandler        ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler   ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler        ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler           ; TIM2
                DCD     TIM3_IRQHandler           ; TIM3
                DCD     TIM4_IRQHandler           ; TIM4
                DCD     I2C1_EV_IRQHandler        ; I2C1 Event
                DCD     I2C1_ER_IRQHandler        ; I2C1 Error
                DCD     I2C2_EV_IRQHandler        ; I2C2 Event
                DCD     I2C2_ER_IRQHandler        ; I2C2 Error
                DCD     SPI1_IRQHandler           ; SPI1
                DCD     SPI2_IRQHandler           ; SPI2
                DCD     USART1_IRQHandler         ; USART1
                DCD     USART2_IRQHandler         ; USART2
                DCD     USART3_IRQHandler         ; USART3
                DCD     EXTI15_10_IRQHandler      ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler       ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler      ; USB Wakeup from suspend
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
DCD     USART1_IRQHandler         ; USART1 
 an die oberste Stelle kopieren, sodass dies im SETENA Register dem 
ersten Bit entspricht?

Oder versteh ich da gerade etwas total falsch?

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meine Tabelle für IAR sieht so aus:
const tISR_Item __vector_table[] = {
  { .mPointer = __sfe( "CSTACK" ) },  /* SP    */
  __iar_program_start,        /* Index 1  */
  NMIException,            /* Index 2  */
  HardFaultException,          /* Index 3  */
  MemManagerException,        /* Index 4  */
  BusFaultException,          /* Index 5  */
  UsageFaultException,        /* Index 6  */
  NULL,                /* Reserved */
  NULL,                /* Reserved */
  NULL,                /* Reserved */
  NULL,                /* Reserved */
  SystemDriverSVCallISR,        /* Index 11  */
  UndefinedInterruptISR,        /* Index 12  */
  NULL,                /* Reserved */
  UndefinedInterruptISR,        /* Index 14  */
  UndefinedInterruptISR,        /* Index 15  */
  UndefinedInterruptISR,        /* Index 16  */
  UndefinedInterruptISR,        /* Index 17  */
  UndefinedInterruptISR,        /* Index 18  */
  UndefinedInterruptISR,        /* Index 19  */
  UndefinedInterruptISR,        /* Index 20  */
  UndefinedInterruptISR,        /* Index 21  */
  UndefinedInterruptISR,        /* Index 22  */
  UndefinedInterruptISR,        /* Index 23  */
  UndefinedInterruptISR,        /* Index 24  */
  UndefinedInterruptISR,        /* Index 25  */
  UndefinedInterruptISR,        /* Index 26  */
  UndefinedInterruptISR,        /* Index 27  */
  UndefinedInterruptISR,        /* Index 28  */
  UndefinedInterruptISR,        /* Index 29  */
  UndefinedInterruptISR,        /* Index 30  */
  UndefinedInterruptISR,        /* Index 31  */
  UndefinedInterruptISR,        /* Index 32  */
  UndefinedInterruptISR,        /* Index 33  */
  UndefinedInterruptISR,        /* Index 34  */
  UndefinedInterruptISR,        /* Index 35  */
  UndefinedInterruptISR,        /* Index 36  */
  UndefinedInterruptISR,        /* Index 37  */
  UndefinedInterruptISR,        /* Index 38  */
  UndefinedInterruptISR,        /* Index 39  */
  UndefinedInterruptISR,        /* Index 40  */
  UndefinedInterruptISR,        /* Index 41  */
  UndefinedInterruptISR,        /* Index 42  */
  UndefinedInterruptISR,        /* Index 43  */
  UndefinedInterruptISR,        /* Index 44  */
  UndefinedInterruptISR,        /* Index 45  */
  UndefinedInterruptISR,        /* Index 46  */
  UndefinedInterruptISR,        /* Index 47  */
  UndefinedInterruptISR,        /* Index 48  */
  UndefinedInterruptISR,        /* Index 49  */
  UndefinedInterruptISR,        /* Index 50  */
  UndefinedInterruptISR,        /* Index 51  */
  UndefinedInterruptISR,        /* Index 52  */
  UndefinedInterruptISR,        /* Index 53  */  /* UART 1  */
  UndefinedInterruptISR,        /* Index 54  */
  UndefinedInterruptISR,        /* Index 55  */
  UndefinedInterruptISR,        /* Index 56  */
  UndefinedInterruptISR,        /* Index 57  */
  UndefinedInterruptISR         /* Index 58  */
};
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?

Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Systemvektoren sind bei mir weiter vorne im Code:
__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     DebugMon_Handler          ; Debug Monitor Handler
                DCD     0                         ; Reserved
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler



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?

Autor: Plan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@STM32 Beginner:
Vergiss nicht den UART im RCC einzuschalten (USART1EN in RCC_APB2ENR) 
und den IRQ im UART selbst anzuknipsen: RXNEIE in USART_CR1.

Autor: STM32 Beginner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Karl Heinz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Gregor Rebel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: tobiflea (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
void UART_Init(void)
{
  /* enable clock for UART */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

  USART1->BRR = (24000000 / 115200);
  USART1->CR1 = (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_TCIE | USART_CR1_RXNEIE);

  /* init ringbuffer */
  ringbuffer_init(&uart_tx_ringbuffer_s, uart_tx_data_ac, UART_TX_BUFFER_LENGTH);

  uart_status_ec = UART_STATE_IDLE;

  USART1->DR = 0xAA;
}

void UART_Transmit(uint8_t* data_pc, uint8_t length_c)
{
  /* fill TX ringbuffer */
  while (length_c > 0)
  {
    ringbuffer_write(&uart_tx_ringbuffer_s, *data_pc);
    data_pc++;
    length_c--;
  }

  /* start transmission */
  uart_status_ec = UART_STATE_TX_BUSY;
  USART1->DR = ringbuffer_read(&uart_tx_ringbuffer_s);
}

void USART1_IRQHandler(void)
{
  if ((USART1->SR & USART_SR_TC) != 0x00)
  {
    /* Transmission clompete interrupt */
    if (uart_tx_ringbuffer_s.content_c > 0)
    {
      USART1->DR = ringbuffer_read(&uart_tx_ringbuffer_s);
      uart_status_ec = UART_STATE_TX_BUSY;
    }
    else
    {
      uart_status_ec = UART_STATE_IDLE;
    }
  }
}

Der UART wird im NVIC natürlich mit NVIC->ISER[1] |= NVIC_ISER_SETENA_5; 
aktiviert.


Hat jemand eine Idee, woran das liegen könnte?

Gruß tobiflea

Autor: tobfilea (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: tobiflea (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn das SR-Register vor der Abfrage in der if-Bedingung explizit in 
eine Variable kopiert wird, funktioniert die ganze Sache. Wieso auch 
immer...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.