Forum: Mikrocontroller und Digitale Elektronik STM32 USART Interrupt


von Jens K. (mister232)


Lesenswert?

Hallo Leute,

habe mal wieder eine Frage an euch. Ich habe hier ein STM32VL-Discovery 
Board liegen. Ich programmiere gerade eine Art Gateway, welches einen 
Computer mit einem I/O-Modul verbindet, für meine Bachelorarbeit. Ich 
möchte hier jetzt nicht den ganzen Code posten, da er zu lang ist, aber 
hier folgt der Code für den USART2, welcher für die Kommunikation mit 
einem Computer zuständig ist.
1
// Handle Interrupts on USART2 (USB connection)
2
void USART2_IRQHandler()
3
{
4
  uint8_t i;
5
  uint16_t crc;
6
7
  // Receive-Interrupt
8
  if(USART_GetITStatus(USART2, USART_IT_RXNE))
9
  {
10
    // Reset the interrupt-flag
11
    USART_ClearFlag(USART2, USART_FLAG_RXNE);
12
13
    TIM4->CNT = 0x00;
14
15
    // Enable the status LED "Connection to computer okay"
16
    GPIOB -> BSRR = GPIO_Pin_0;
17
18
    ReceiveByte(USART_ReceiveData(USART2));
19
20
  }
21
22
  // Transmit-Interrupt
23
  else if(USART_GetITStatus(USART2, USART_IT_TXE))
24
  {
25
    // Reset the interrupt-flag
26
    USART_ClearFlag(USART2, USART_FLAG_TXE);
27
28
    if(getNewMsg)
29
    {
30
        // Calculate the CRC for the temporary buffer
31
        crc = calcCRC(pcSendBuf[posPCsendBufRead].payload, pcSendBuf[posPCsendBufRead].msgLen);
32
33
        // Add the CRC to the last two positions in the temporary buffer
34
        pcSendBuf[posPCsendBufRead].payload[pcSendBuf[posPCsendBufRead].msgLen] = (crc & 0xff00) >> 8;
35
        pcSendBuf[posPCsendBufRead].payload[pcSendBuf[posPCsendBufRead].msgLen + 1] = (crc & 0xff);
36
        pcSendBuf[posPCsendBufRead].msgLen = pcSendBuf[posPCsendBufRead].msgLen + 2;
37
38
        getNewMsg = 0;
39
        pcSendBuf[posPCsendBufRead].pos = 0;
40
    }
41
42
    else
43
    {
44
      // Send data via USART
45
      USART_SendData(USART2, pcSendBuf[posPCsendBufRead].payload[pcSendBuf[posPCsendBufRead].pos]);
46
47
      pcSendBuf[posPCsendBufRead].pos++;
48
49
      // See if the end of the actual sub-buffer is reached
50
      if(pcSendBuf[posPCsendBufRead].pos >= pcSendBuf[posPCsendBufRead].msgLen)
51
      {
52
        for(i = 0; i < MAX_PC_MESSAGE_SIZE; i++)
53
        {
54
          pcSendBuf[posPCsendBufRead].payload[i] = '\0';
55
        }
56
57
        pcSendBuf[posPCsendBufRead].msgLen = 0;
58
59
        posPCsendBufRead++;
60
61
        getNewMsg = 1;
62
63
        // Check if the end of the send-buffer is reached
64
        if(posPCsendBufRead >= PC_SEND_BUFFER_SIZE)
65
        {
66
          // Chose the first sub-buffer
67
          posPCsendBufRead = 0;
68
          pcSendBuf[posPCsendBufRead].pos = 0;
69
        }
70
71
        // See if the sendBuf is empty
72
        if(posPCsendBufRead == posPCsendBufWrite)
73
        {
74
          pcSendBuf[posPCsendBufRead].pos = 0;
75
          // Disable the transmit interrupt on USART
76
          USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
77
        }
78
      }
79
    }
80
  }
81
}

Die Kommunikation funktioniert soweit prima. Wenn ich zum Computer jede 
Menge Daten vom I/O-Modul schicke, ohne das der Computer sich einmischt, 
klappt das auch soweit. Da habe ich schon über Millionen Daten rüber 
geschaufelt. Wenn der Computer aber nun während der Übertragung noch 
anfragen nach dem aktuellen Status des Gateways stellen soll, 
funktioniert dies zunächst auch noch und dann bricht die Kommunikation 
zusammen. Wenn ich nun mit Atolic TrueStudio debugge und schau wo er 
hängen geblieben ist, dann springt er immer wieder in die oben 
aufgeführte ISR, aber beide abfragen (Receive-Interrupt und 
Transmit-Interrupt) sind falsch. Kurz danach springt er wieder rein und 
die abfragen sind wieder beide falsch. Irgendwie scheint er also in 
dieser ISR zu hängen, obwohl es keinen Interrupt gibt. Die 
Interrupt-Flags setzte ich aber immer wieder sofort zurück.

Ich weiß, es sind nicht viele Infos und wahrscheinlich könnt ihr mir da 
nicht groß weiter helfen. Vielleicht hat aber der ein oder andere von 
euch doch so eine Vermutung, woran der Fehler liegen könnte.

Gruß
Mister232

von Jim M. (turboj)


Lesenswert?

Kann man das TXE Interrupt Flag beim STM32VL einfach so "clear"en? Ich 
habe vorhin einen Beitrag gesehen, der das Gegenteil behauptet.

von Jens K. (mister232)


Lesenswert?

Also bisher hat das immer sehr gut funktioniert.  Das Problem ist ja 
auch, dass er in die ISR springt, aber beide Abfragen (TXE und RXNE) das 
Ergebnis falsch liefern
 Aber warum wird die ISR aufgerufen, wenn kein Interrupt vorliegt? Und 
es passiert auch erst nach einer kurzen Weile.

von katastrophenheinz (Gast)


Lesenswert?

Andere Interrupt-Ursache wie z.b. frame Error oder overrun ? Schon mal 
das gesamte Interruptstatus-register ausgelesen, ob noch andere Bits als 
die von dir getesteten gesetzt sind?

von W.S. (Gast)


Lesenswert?

Jens K. schrieb:
> Aber warum wird die ISR aufgerufen, wenn kein Interrupt vorliegt?

So, Bachelor willst du werden. Damit?

Eine ISR wird nicht aufgerufen, jedenfalls nicht im landläufigen Sinne, 
sondern sie ist die Reaktion der Hardware auf einen zur Reaktion 
anstehenden Interrupt. Es gibt je nach µC und Peripherie ganz 
unterschiedliche Interrupt-Verhaltensweisen. Manchmal ist es so, daß ein 
Interrupt gnadenlos "kommt", wenn eine statische Bedingung erfüllt ist. 
Aber meistens ist es so, daß ein Interrupt ausgelöst wird, wenn eine 
statische Bedingung erfüllt wird (also von NEIN auf JA wechselt).

Bei den mir bekannten UART-Cores von NXP und ST ist letzteres der Fall, 
also der Interrupt "kommt" nur dann, wenn das Sende-Puffer-Register 
gerade leer wird. Wenn es erstmal leer ist_ und leer _bleibt dann 
gibt's keinen Interrupt.

Mein dringender Rat: schmeiße diese ST-Lib aus deinen Programmen raus 
und lerne, die Peripherie SELBST zu verstehen. Zumindest dies würde 
ich von einem angehenden Bachelor erwarten.

W.S.

von (prx) A. K. (prx)


Lesenswert?

Jim Meba schrieb:
> Kann man das TXE Interrupt Flag beim STM32VL einfach so "clear"en?

Nein, das kann man nicht. Man stellt ggf. den entsprechenden Interrupt 
ab, und wieder an, wenn im Puffer was drin ist.

Sein Umgang mit RXNE ist ähnlich sinnlos. Weil unnötig.

von Jens K. (mister232)


Lesenswert?

Danke für deinen Rat. Dafür habe ich aber leider keine Zeit mehr. Ich 
bin Hardwareentwickler und kein Softwareentwickler. Die Software gehörte 
nur leider mit zur Bachelorarbeit dazu, also versuche ich mich ein wenig 
damit anzufreunden. Ich bin überhaupt schon froh das sie bis jetzt 
zumindest einigermaßen läuft.

von (prx) A. K. (prx)


Lesenswert?

Jens K. schrieb:
> aufgeführte ISR, aber beide abfragen (Receive-Interrupt und
> Transmit-Interrupt) sind falsch.

Was bedeutet, sie "sind falsch"?

> Interrupt-Flags setzte ich aber immer wieder sofort zurück.

TXE nicht, weil das schlicht nicht geht. Und RXNE setzt sich beim Lesen 
vom Datenregister selbst zurück.

Es gibt aber neben RXNE und TXE weitere Interrupt-Möglichkeiten. Wenn 
die eingeschaltet sind, aber nicht behandelt werden, dann gibts 
Dauerarbeit für den armen Handler.

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Und welche sind das? Wie lassen sie sich ausschalten?

von (prx) A. K. (prx)


Lesenswert?

Jens K. schrieb:
> Und welche sind das?

Schau ins CR1 rein, da sind alle IE-Bits aufgereiht.

> Wie lassen sie sich ausschalten?

Indem man sie nicht erst einschaltet. Genauer wirds nicht, weil ich 
ebenso wie W.S. kein Freund der Lib bin, sondern auf die Register gehe.

Aber du kannst ja mal den übrigen Code der USART hier reinstellen. Also 
Init, und was sonst noch damit arbeitet.

: Bearbeitet durch User
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
Noch kein Account? Hier anmelden.