Forum: Mikrocontroller und Digitale Elektronik STM32 UART Interrupt funktioniert nur "teilweise"


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo liebes Forum,

Zu allererst: ich verwende einen STM32F3.
Damit ich kein Polling bei der UART machen muss, möchte ich dass beim 
Ankommen der Daten ein Interrupt ausgelöst wird.
Wenn ich im Debug-Modus bin und ich schicke das erste mal einen char, 
dann wird kein Interrupt ausgelöst. Erst beim wiederholten Senden wird 
ein Interrupt ausgelöst. Und nach mehrmaligem weiteren Senden ist das 
quasi eine Lotterie: manchmal wird ein Interrupt ausgelöst, und dann 
wieder nicht.
Könnt ihr mir helfen? Habe ich in der Konfiguration etwas vergessen?
Vielen Dank im Voraus!
1
#include <stm32f30x.h>
2
#include <stm32f30x_gpio.h>
3
#include <stm32f30x_rcc.h>
4
#include <stm32f30x_usart.h>
5
#include <stm32f30x_misc.h>     
6
7
8
9
//global variables
10
volatile unsigned char uart_receive;    // for receiving one char
11
12
13
// prototypes
14
unsigned char USART_ReadByteSync(USART_TypeDef *USARTx);
15
void USART2_IRQHandler(void);
16
void InitializeUSART();
17
int _write (char *pBuffer, int size);
18
19
20
void InitializeUSART()
21
{
22
    RCC_USARTCLKConfig(RCC_USART2CLK_SYSCLK);
23
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
24
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);  //Enable peripheral clock for USART2
25
26
27
    GPIO_InitTypeDef gpioConfig;
28
29
    //PB3 = USART2.TX => Alternative Function Output
30
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_7);  //Alternativ Funktionalität USART2 für Pin 3 an GPIOB aktivieren
31
    gpioConfig.GPIO_Mode = GPIO_Mode_AF;            // Alternate function mode  page: 237
32
    gpioConfig.GPIO_OType = GPIO_OType_PP;          // Output Push-Pull         page: 237
33
    gpioConfig.GPIO_Speed = GPIO_Speed_10MHz;       // Medium speed             page: 238
34
    gpioConfig.GPIO_PuPd = GPIO_PuPd_NOPULL;        // No pull-up, pull down    page: 239
35
    gpioConfig.GPIO_Pin = GPIO_Pin_3;
36
    GPIO_Init(GPIOB, &gpioConfig);                  // pin initialization
37
38
39
    //PB4 = USART2.RX => Alternative Function Output
40
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_7);
41
    gpioConfig.GPIO_Mode = GPIO_Mode_AF;
42
    gpioConfig.GPIO_OType = GPIO_OType_PP;
43
    gpioConfig.GPIO_Speed = GPIO_Speed_10MHz;
44
    gpioConfig.GPIO_PuPd = GPIO_PuPd_NOPULL;
45
    gpioConfig.GPIO_Pin = GPIO_Pin_4;
46
    GPIO_Init(GPIOB, &gpioConfig);
47
48
49
    USART_InitTypeDef usartConfig;
50
51
    usartConfig.USART_BaudRate = 9600;
52
    usartConfig.USART_WordLength = USART_WordLength_8b;         //USART2->CR1 |= 0x0000;
53
    usartConfig.USART_StopBits = USART_StopBits_1;
54
    usartConfig.USART_Parity = USART_Parity_No;
55
    usartConfig.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
56
    usartConfig.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
57
    USART_Init(USART2, &usartConfig);
58
59
60
61
    // ######## configure NVIC for Interrupt when data received: ###########
62
    NVIC_InitTypeDef NVIC_InitStructure;
63
64
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;               // select NVIC channel
65
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       // value between 0 and 15; A lower priority value indicates a higher priority
66
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
67
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
68
    NVIC_Init(&NVIC_InitStructure);
69
    USART_ClearITPendingBit(USART2, USART_IT_RXNE);                 // Clear interrupt flag
70
    USART_ClearITPendingBit(USART2, USART_IT_TXE);
71
72
    USART_ITConfig(USART2, USART_IT_TXE, DISABLE);                  // disable Transmit Data Register empty interrupt
73
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);                  // Enable the USART RX Interrupt
74
    //NVIC_EnableIRQ(USART2_IRQn);                                    // Enable USART2 global interrupt
75
76
77
    USART_Cmd(USART2, ENABLE);      // UART2 enable             //USARTx->CR1 |= USART_CR1_UE;  //Enable the selected USART by setting the UE bit in the CR1 register */    page: 937
78
}
79
80
81
82
void USART2_IRQHandler(void)
83
{
84
    //Interrupt handler implementation
85
    
86
    if (USART_GetITStatus(USART2, USART_IT_RXNE))   //checking if interrupt
87
        uart_receive = USART_ReadByteSync(USART2);
88
89
    USART_ClearITPendingBit(USART2, USART_IT_RXNE); //Clear interrupt flag
90
}
91
92
93
94
unsigned char USART_ReadByteSync(USART_TypeDef *USARTx)
95
{
96
    while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET)       // RXNE is set when content of the shift register is transferred to the RDR
97
    {
98
99
    }
100
101
    return (unsigned char)USART_ReceiveData(USARTx);
102
}
103
104
105
106
int main ()
107
{
108
109
    SystemInit();
110
    InitializeUSART();
111
112
    for (;;)
113
    {
114
    while(1)
115
        {
116
             //for sending 1 char
117
            while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);    // we can only write in the TDR register when TXE=1 (because when TXE ==1 -> data is transferred to the shift register)     page: 898 - 899
118
            {
119
                USART_SendData(USART2, 0x55);       //USARTx->TDR = (Data & (uint16_t)0x01FF);      //Transmit data by writing it in the TDR
120
            }
121
           
122
123
        }
124
    }
125
}

von ui (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Schonmal an der Priorität des Interrupts geschraubt?

Reindebuggen in die ISR funktioniert? Also die wird angesprungen?

Ansonsten schaut der Code auf den schnellen Blick gut aus.

von ui (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ach ja die Baudrate schaut komisch aus.
Aus dem Code zum USART von STM:
1
  uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
2
                                           The baud rate is computed using the following formula:
3
                                            - IntegerDivider = ((PCLKx) / (8 * (OVR8+1) * (USART_InitStruct->USART_BaudRate)))
4
                                            - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 8 * (OVR8+1)) + 0.5 
5
                                           Where OVR8 is the "oversampling by 8 mode" configuration bit in the CR1 register. */

der Wert 9600 entspricht NICHT 9600 Baud.

von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
ui schrieb:
> Schonmal an der Priorität des Interrupts geschraubt?

Naja, es ist bereits die höchste Priorität vergeben!

ui schrieb:
> Reindebuggen in die ISR funktioniert? Also die wird angesprungen?

Ja hab ich, Aber wie gesagt: Sie wird nur hin und wieder angesprungen!

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Könnt ihr mir helfen?

Ja.

Aber vor dem Helfen muss bei deiner Quelle erst noch eine heftigste 
Schimpfkanonade stattfinden. Hast du denn überhaupt nicht mal 
nachgedacht über einen sinnvollen Treiber für deinen USART2 ? Wo bleibt 
die Pufferung? Wo bleibt der entgegengesetzte Datenstrom? Wo bleibt die 
sinnvolle Kapselung des ganzen inneren Schmonzes des Treibers?

Abgesehen davon graust mich dein Quellcode. Du kannst natürlich immerzu 
so weitermachen und dich in die ST-Lib hineinwühlen bis du nicht mehr 
weiterkommst (was anscheinend gerade jetzt erreicht ist) ODER du 
schmeißt den ganzen Haufen aufgedunsenen Zeuges weg und denkst dir dann 
ein ordentliches Konzept aus.

Damit du mal nen Eindruck eines Interrupthandlers bekommst, zitiere ich 
mal aus einer meiner Quellen:
1
/* Pufferlängen: immer eine 2er Potenz */
2
#define OBLEN  32
3
#define IBLEN  8
4
5
#define TUBUF  struct T_UARTBUF
6
struct T_UARTBUF
7
{ char OutBuf[OBLEN];
8
  char InBuf[IBLEN];
9
  volatile int  InWP;
10
  volatile int  InRP;
11
  volatile int  OutWP;
12
  volatile int  OutRP;
13
};
14
15
/* die Puffer für alle 5 USART/UART */
16
...
17
TUBUF U2Buf;
18
...
19
20
21
__irq void USART2_IRQHandler (void)
22
{ char c;
23
  int  i, j;
24
25
  if (USART2_ISR & ((1<<5)|(1<<3)))      // RX: Zeichen empfangen
26
  { c = USART2_RDR;
27
    i = U2Buf.InWP;
28
    j = (i+1) & (IBLEN-1);
29
    if (j!=U2Buf.InRP)
30
    { U2Buf.InBuf[i] = c;
31
      U2Buf.InWP = j;
32
    }
33
  }
34
35
  if  (USART2_ISR & (1<<7))              // TX: Sendepuffer leer?
36
  { i = U2Buf.OutRP;
37
    if (i!=U2Buf.OutWP)                  // ob es was zu senden gibt
38
    { USART2_TDR  = U2Buf.OutBuf[i];
39
      U2Buf.OutRP = (i+1) & (OBLEN-1);
40
    }
41
    else
42
    { USART2_CR1 &= ~(3<<6);             // nö, TXEIE und TCIE ausschalten
43
    }
44
  }
45
}

Hier werden Input und Output gepuffert und sämtlicher 
Schnittstellenverkehr erfolgt per Interrupt. Der USART ist ein eher 
langsames Interface, also spielt die Priorität keine große Rolle.
Ach ja, beim Senden, also wenn der Treiber was in den Sendepuffer 
schreibt, wird TXEIE und TCIE wieder eingeschaltet.

So. lies und versuche es zu verstehen. Den Rest des Treibers solltest du 
jetzt selber schreiben können.

W.S.

von Oswin (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> (USART2_ISR & ((1<<5)|(1<<3)))
So ein Murks!
Code sollte sich selbst eklären, nicht durch Kommentare die vor dem 
nächsten Strg-S schon veraltet sind.
Im Manual sind die Bits benamst. Das sollte sich im Code auch 
wiederfinden.

Warum häst Du Dich eigentlich immer für den Schlausten, der die Weisheit 
bzw. die Programmiererleuchtung mit Löffeln gefressen hat?!?

von unkti (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>Warum häst Du Dich eigentlich immer für den Schlausten, der die Weisheit
>bzw. die Programmiererleuchtung mit Löffeln gefressen hat?!?

Na Du fragst dumm: Weil er die Lernbetty erfunden hat!

von Adib (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo har,

Nimm doch den aktuellen cubeMx.
Der generiert dir Code, der zumindest beim Senden funktioniert.
Empfang mache ich per Dma.

Adib.

von W.S. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Oswin schrieb:
> Code sollte sich selbst eklären, nicht durch Kommentare die vor dem
> nächsten Strg-S schon veraltet sind.

Kannst du steckenlassen. Ich mache das aus gutem Grund und ich füge auch 
aus gutem Grund einen Kommentar dran.

Du bist nicht der TO, sondern nur jemand, der eben mal daherkommt um 
hier seinen Spruch abzulassen und was besserzuwissen, ohne auch nur die 
Spur eines echten eigenen Beitrages geliefert zu haben.

Also poste mal etwas wirklich Funktionables, dann können all diejenigen, 
die Hilfe suchen, selber entscheiden, ob sie deins nehmen oder nicht.

Klar soweit?

W.S.

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]
  • [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.