Forum: Mikrocontroller und Digitale Elektronik STM8 UART blockiert


von Christoph R. (christoph_r463)


Lesenswert?

Hallo Zusammen,
Ich habe hier ein kleines Testsystem mit zwei Slaves und einem Master. 
Die Kommunikation realisiere ich über UART. Der Master ist ein STM32 und 
die Slaves STM8Ss.
Die Slaves lauschen auf Daten vom Master, welche an den jeweiligen Slave 
adressiert sind (ID im Bytestream). Das ganze läuft für eine gewisse 
Zeit sehr gut (30Sek-2Min). Danach jedoch sehen die beiden(!) Slaves mit 
einem Mal keine eingehenden Daten mehr, als ob sich der UART an den 
STM8ern abgeschaltet hätte (Auf der Leitung sind die Daten aber 
vorhanden, - mit Oszilloskop gemessen).
Ich habe mit dem Interrupt getestet und bin nun beim pollen angelangt. 
Jede Variante zeigt dieses Verhalten.

Meine Empfangsroutine startet so:
1
 /* clear new data received flag */
2
  UART1_ClearFlag(UART1_FLAG_RXNE);
3
  UART1_ReceiveData8(); 
4
  
5
  /* wait here for first data byte */
6
  while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);
7
8
  /* Read one byte from the receive data register */
9
 byValue = UART1_ReceiveData8();
10
  
11
  /* check for frame start */
12
  if(START_OF_FRAME == byValue)
13
14
....

Im Fehlerfall hängen die STMs immer beim „while 
(UART1_GetFlagStatus(UART1_FLAG_RXNE)“. Wenn ich das umgehe und einfach 
immer nur per UART1_ReceiveData8() ein Byte vom UART DR lese und auf 
mein Frame Start Byte warte, passiert nichts -> zum Beispiel:
1
  while (UART1_ReceiveData8() != START_OF_FRAME);

Wenn ich nur einen STM8 allein betreibe habe ich keine Probleme. Es kann 
hin und wieder vorkommen, dass beide STM8s zur selben Zeit etwas senden, 
was aber vom Master erkannt wird. Könnte das ein Problem für die STM8s 
darstellen? Suche ich an der falschen Stelle? Hat jemand einen Tipp?

Danke!
Grüße
Chris

von aSma>> (Gast)


Lesenswert?

Servus,
mache das lieber per ISR und einen Protokoll. Pollen kann man schon aber 
nur wenn man DMA hat oder einen Sender mit Buffer...

Du bekommst mit Sicherheit ein Overflow, weil die Daten zu langsam 
abgearbeitet werden.

Programmiere also per ISR ein FIFO und werte die Daten per Protokoll 
aus. Erstelle eine ISR die Fehler abarbeitet.

mfg

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Check mal ob du nen Error bekommst UART_SR:(FE|OR). Manche Controller 
empfange nicht mehr wenn ein Fehler aufgetreten ist.

von Christoph R. (christoph_r463)


Lesenswert?

aSma>> schrieb:
> Servus,
> mache das lieber per ISR und einen Protokoll. Pollen kann man schon aber
> nur wenn man DMA hat oder einen Sender mit Buffer...
>
> Du bekommst mit Sicherheit ein Overflow, weil die Daten zu langsam
> abgearbeitet werden.
>
> Programmiere also per ISR ein FIFO und werte die Daten per Protokoll
> aus. Erstelle eine ISR die Fehler abarbeitet.
>
> mfg

Hallo aSma

Meine erste Version sah genau so aus, also ISR + FIFO + Protokoll. das 
einzige was ich da getestet habe, war das erste Byte des Frames -> 
Startbyte. Sowie das Zweite Frame -> Länge des kommenden Frames.

Was für Fehler meinst du, die ich in der ISR abarbeiten sollte? Gibt es 
da noch mehr Flags die man auswerten kann, bzw. zurücksetzen muss?

Ich hatte mal ausprobiert das OR Flag noch zurück zu setzen, aber da ist 
mir der STM auch immer eingefroren
1
UART1_ClearFlag(UART1_FLAG_OR);

Wenn ich nur einen Slave nutze, läuft meine Lösung wirklich gut bei 
250KBaud (sehr kurze Leitungen werden genutzt), ob ich nun Interrupt 
oder Polling nehme.

Danke und Grüße
Chris

von Christoph R. (christoph_r463)


Lesenswert?

Christopher B. schrieb:
> Check mal ob du nen Error bekommst UART_SR:(FE|OR). Manche
> Controller
> empfange nicht mehr wenn ein Fehler aufgetreten ist.

Hi Christopher,

das ist ein guter Hinweis, dass bestimmte Controller nicht mehr 
empfangen. Was muss man dann im allgemeinen tun? Einfach die Fehler 
Register wieder zurücksetzen?

(Ich teste mich da mal durch!)

Danke und Grüße!
Chris

von Christoph R. (christoph_r463)


Lesenswert?

Reagiert eine Lösung mit Polling nicht genauso schnell wie ein 
Interrupt?

sowas hier zum Beispiel:
1
while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);

Also die reine Reaktionszeit, vom befüllten Buffer bis zum ersten Code 
in der ISR, bzw nach der while()-Schleife....

von aSma>> (Gast)


Lesenswert?

Christoph R. schrieb:
> /* wait here for first data byte */
>   while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);
Fehler Quelle 1
>
>   /* Read one byte from the receive data register */
>  byValue = UART1_ReceiveData8();
>
>   /* check for frame start */
>   if(START_OF_FRAME == byValue)
Fehler Quelle 2

Hier mein Beispiel für !stm32 aber:
1
//----------------------------------------------------------------------------
2
// USART1_IRQHandler: USART1 Tx,Rx interrupt request handler
3
//----------------------------------------------------------------------------
4
void USART1_IRQHandler(void)
5
{
6
  if((USART_GetITStatus(USART1, USART_IT_RXNE) == SET)) //only 1 byte
7
  {
8
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);   //clear flag
9
10
    Usart_Rx_Buffer[Receive_W] = USART_ReceiveData(USART1);
11
    Receive_W++;
12
    Receive_C++;
13
  }
14
15
16
  if((USART_GetITStatus(USART1, USART_IT_TXE) == SET))
17
  {
18
      USART_ClearITPendingBit(USART1, USART_IT_TXE);//clear flag
19
20
      if(Usart_Tx_Buffer[Send_C] != '\0')
21
    {
22
      USART_SendData(USART1, Usart_Tx_Buffer[Send_C]);
23
      Send_C++;
24
    } else {
25
      Send_C = 0;
26
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
27
    }
28
  }
29
30
}
Alle Var in der ISR sind global und volatile!

Jetzt musst du nur noch eine Fkt. schreiben, in der du den Header, 
Daten, Terminator bearbeitest. Ein Header aus nur einen Char ist halt 
Fehler anfällig.
1
void UsartRead(void)
2
{
3
  if (Receive_C>0){
4
...
5
//header
6
//terminator
7
//data
8
Receive_C--;
9
}
mfg

von Christoph R. (christoph_r463)


Lesenswert?

aSma, Christopher, ihr seids super :) Danke!

es ist eine Kombination aus beidem. Mit dem reinen Polling habe ich mich 
etwas verzettelt. Initial warte ich nun auf einen USART_IT_RXNE 
Interrupt, polle danach dann aber weiter (mit Timeout) - funktioniert 
wunderbar. Mein Protokoll besteht übrigens aus einigen mehr bytes + crc 
usw, - hatte es hier nur zur Vereinfachung weggelassen :)

In der ISR werte ich nun alle Flags aus, - und wie Christopher schon 
vermutet, poppt irgendwann ein OR Interrupt auf. Genau da hängt es dann.


So ungefähr:
1
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
2
{
3
  if(UART1_GetFlagStatus(UART1_FLAG_RXNE) == SET)
4
  {
5
    IRQHandler_Rx(); //-> Emfangsroutine
6
  }
7
  else
8
  {
9
    if(UART1_GetFlagStatus(UART1_FLAG_OR) == SET)
10
    {
11
      UART1_ReceiveData8();  // -> clear!
12
    }
13
    if(UART1_GetFlagStatus(UART1_FLAG_FE) == SET)
14
    {
15
      UART1_ReceiveData8();  
16
    }
17
  }
18
}


Interessant ist nur, warum immer beide Slaves gleichzeitig blockiert 
wurden. Das liegt sicher irgendwo an der Tatsache, dass beide manchmal 
zur selben Zeit senden.

Naja, so oder so, - es läuft jetzt erstmal :)
Danke nochmal für eure Zeit und euren Input!
Grüße
Chris

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.