Forum: Mikrocontroller und Digitale Elektronik UART zwei mal ausgelöst nach Interrupt?


von Bergsfrau (Gast)


Lesenswert?

Hallo guten Tag,

warum wird mein UART-Interrupt zwei mal ausgelöst wenn ich etwas 
eintippe und Enter drücke? Der Buffer hat dann einmal den ersten 
Buchstaben und einmal den Rest.

Mein Programm soll bei scanfx in eine while(1) Schleife gehen bis eine 
Eingabe erfolgt und ein Empfang-Flag auf 1 setzt.
1
cmd0
2
cmd1
3
scanfx -> while(1)  <-- Eingabe durch Interrupt
4
nutze das eingelesene
5
cmd2
6
cmdn
7
scanfx -> while(1)  <-- Eingabe durch Interrupt

Was mir aufgefallen ist:
Wenn ich in der while-Schleife bin, etwas eintippte und enter drücke 
wird meine Interrupt Funktion 2 mal hintereinander aufgerufen..

Wenn ich eingebe: "test"
wird zuerst das "t" als Eingabe verwendet.
direkt danach scheint die Funtkion nochmal "est" zu erhalten.
Das sehe ich auch an der Ausgabe von "est" und "t"...


hier setze ich den handler:
1
  MSS_UART_set_rx_handler(&g_mss_uart0, uart3_rx_handler, MSS_UART_FIFO_SINGLE_BYTE);

Hier ist der interrupt handler:
1
 
2
g_rx_buff  =  buffer
3
this_uart = mein gewählter UART port

1
void uart3_rx_handler(mss_uart_instance_t *this_uart)
2
{
3
  unsigned int rx_size = MSS_UART_get_rx(this_uart, g_rx_buff, sizeof(g_rx_buff) );
4
  
5
  printf("\n------------------------- [UART RX HANDLER]");
6
  uart_calls_cnt++;
7
  printf("\n-call cnt: %d", uart_calls_cnt);
8
  printf("\n * Size RX char: %d", rx_size);
9
  printf("\n *Your input: ");
10
  printf("  [I]%s[/I]", (char *)g_rx_buff);
11
  uart_handler_flag = 1;

von chris (Gast)


Lesenswert?

normalerweise müsste jedes Zeichen einen Int auslösen welcher dann in 
den Buffer geschrieben wird, scheint ja auch zu funktionieren nur das 
wohl bei SCANFX als Routine evtl was schiefläuft aber was genau wird 
schwierig...

von DerEinzigeBernd (Gast)


Lesenswert?

Bergsfrau schrieb:
> Hier ist der interrupt handler:

Du rufst printf IM Interrupt-Handler auf.

Das ist eine sehr schlechte Idee.

von Bergsfrau (Gast)


Lesenswert?

Aber wenn ich dann "test" eingebe,

 dann wird direkt das "t" erkannt und der Interrupt ausgelöst?
Wird dabei "est" reingeschrieben und dann ebenfalls ein weiterer 
interrupt auslöst?

Will ja nur dass er test komplett einliest.
liegt das "MSS_UART_FIFO_SINGLE_BYTE" ?
Dass der da schon interrupted?

scanfx soll nur eine Ersatz sein für while(1)

So sieht die etwa aus:
1
int flag = 0; // global
2
3
bool scanfx(){
4
5
while(1) { 
6
7
if  ( flag== 1) {
8
return true}
9
else{}
10
}
11
}

DerEinzigeBernd schrieb:
> Du rufst printf IM Interrupt-Handler auf.

Warum? weil diese Funktion viel Zeit kostet?
Ist das ok für einen ersten Debug?

von C.K. (Gast)


Lesenswert?

Ein paar weitere Salamiescheiben werden hilfreich.

Was für einen Microcontroller benutzt du, was für eine API ist das 
MSS_*...

Wo tippst du eine? Auf dem PC mittels Terminal.

Läuft das dann über ein USB-UART-Adapter?


Schickt deine Terminal-Anwendung den Text Zeichenweise raus, oder erst 
wenn Enter gedrückt wird? Aus deiner Beobachtung vermute ich letzteres.

Des weiteren gehe ich davon aus das du einen USB-UART Adapter benutzt.
USB ist paketorientiert und hat auf PC Seite einen Input Buffer.

Deine Terminal Anwendung schickt den gesamten String in einem Rutsch in 
den USB-Input Buffer. Sobald da das erste Zeichen rein kommt, wird 
bereits das erste USB-Packet abgesendet, und der Adapter schickt das 
erste Zeichen aus. [Dein erster Interrupt auf deinem Microkontroller]

Die Restlichen Zeichen liegen im USB-Input Buffer, und werden im 
nächsten USB-Packet an den Adapter gesendet. der dann die Zeichen ohne 
weitere Pause per UART aussendet. [2. Interrupt, bis du den Buffer 
ausliest, sind bereits die restlichen Zeichen angekommen]

USB-Pakete haben ein Timing von 1ms. Da kannst du nichts ändern.

von Udo S. (urschmitt)


Lesenswert?

chris schrieb:
> normalerweise müsste jedes Zeichen einen Int auslösen welcher dann in
> den Buffer geschrieben wird,

Wahrscheinlich sind nach der 1. IRQ-Behandlung alle restlichen Zeichen 
schon eingegangen und zum Glück gepuffert worden. Folge der viel zu 
langsamen printf Aufrufe.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bergsfrau schrieb:
> Will ja nur dass er test komplett einliest.
Naja, ein wenig musst du schon noch selber machen. Das nennt sich 
programmieren. Du musst den Strin einlesen, bis du (d)ein 
Terminierungszeichen erkennst (z.B. CR/LF), und kannst dann den 
empfangenen String parsen.

Allein mit "ich will" kommst du nicht ans Ziel.

C.K. schrieb:
> Was für einen Microcontroller benutzt du, was für eine API ist das
Ein SmartFusion FPGA (aka Actel):

https://www.eejournal.com/article/microchip-microsemi-and-atmel-and-actel/

https://www.microsemi.com/product-directory/soc-fpgas/1693-smartfusion

https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/smartfusion-2-fpgas

C.K. schrieb:
> Salamiescheiben
Wiederstand gegen die übermäßiege Verwendung des -ie-!   ;-)

von chris (Gast)


Lesenswert?

In der Tat. Komplett übersehen und deshalb wird immer der IRQ gesetzt 
weil das nächste Byte ansteht wird zwar zwischen gespeichert aber da die 
Ausgabe im ertsen Moment recht lang ist wird erst nur das T ausgegeben 
und zwischen durch wird der Rest dann beim zweiten durchlauf im Buffer 
abgelegt und als EST ausgegeben.

von DerEinzigeBernd (Gast)


Lesenswert?

Bergsfrau schrieb:
> DerEinzigeBernd schrieb:
>> Du rufst printf IM Interrupt-Handler auf.
>
> Warum? weil diese Funktion viel Zeit kostet?

Sieh mal, wie viele einzelne Zeichen Du hier für jeden einzelnen 
Interrupt-Aufruf ausgibst:

>   printf("\n------------------------- [UART RX HANDLER]");
>   uart_calls_cnt++;
>   printf("\n-call cnt: %d", uart_calls_cnt);
>   printf("\n * Size RX char: %d", rx_size);
>   printf("\n *Your input: ");
>   printf("  [I]%s[/I]", (char *)g_rx_buff);


Selbst wenn diese printf()-Aufrufe nicht blockieren (d.h. erst 
zurückkehren, bis sie alles ausgegeben haben), dauert die ISR ziemlich 
lange. Es kann also sein, daß beim Einlaufen des nächsten Zeichens bei 
der UART die ISR noch nicht beendet ist, und direkt der nächste 
Interrupt ausgelöst wird.

Und wenn die Aufrufe blockieren (weil Deine Umgebung keinen 
interruptgesteuerten Ausgabehandler mit ausreichend großem Sendepuffer 
hat), dann geht richtig viel Zeit in der ISR drauf; sofern die 
UART-Hardware nicht mehrere empfangene Bytes puffern kann, gehen diese 
unweigerlich verloren.

Also: Nein, das ist auch für "ein erstes Debug" eine ganz schlechte 
Idee.

von Bergsfrau (Gast)


Lesenswert?

das hat mir schon mal weiter geholfen.
Ich konnte jetzt schon die ersten Eingaben machen die funktionieren wenn 
sie verglichen werden.
Ist noch ein bisschen holprig mit den Interrupts aber werde mir das noch 
mal genauer anschauen :D

von Bergsfrau (Gast)


Lesenswert?

Lothar M. schrieb:
> Naja, ein wenig musst du schon noch selber machen. Das nennt sich
> programmieren. Du musst den Strin einlesen, bis du (d)ein
> Terminierungszeichen erkennst (z.B. CR/LF), und kannst dann den
> empfangenen String parsen.

Ok, also wenn ein Interrupt geschieht werde ich mal alle vorhandenen 
Zeichen einlesen.
Die Anzahl der einzulesenden Zeichen werde ich aus dem Rückgabewert von 
MSS_UART_get_rx nehmen.
Bei jedem Element was ich reinschreibe werde ich vergleichen ob '\n' 
vorhanden ist.
Wenn ja ist das das Ende des Strings und ich kann ihn verwenden.

Wenn ein Interrupt kommt stehen die Daten ab Index 0 im Buffer.
Ich muss diese dann an die bereits ausgelesenen Daten anhängen.
Dafür muss die vorherige Position bekannt sein.
1
for ( int i= 0 ; i < (int) rx_size ; i ++){
2
command[index] <= g_rx_buff[i]
3
}
4
index += (int) rx_size;


Udo S. schrieb:
> Wahrscheinlich sind nach der 1. IRQ-Behandlung alle restlichen Zeichen
> schon eingegangen und zum Glück gepuffert worden. Folge der viel zu
> langsamen printf Aufrufe.

Wenn ich printf weglasse geschieht das gleiche.

Wenn ich einen Breakpoint in die ISR setze ist einmal 't' drin und 
einmal 'e' 's' 't' '\n'

von Bergsfrau (Gast)


Lesenswert?

Grade am testen:
Es scheint echt besser zu laufen :D
1
unsigned int rx_size = MSS_UART_get_rx(this_uart, g_rx_buff, sizeof(g_rx_buff));
2
  (void)rx_size;
3
4
  uart_calls_cnt++;
5
6
  uart_handler_flag = 0;
7
8
9
  for (int i = 0; i < (int)rx_size; i++) {
10
    if (g_rx_buff[i] != '\n') {
11
      command[index_uart_read_out_cnt + i]   = g_rx_buff[i];
12
      value_str[index_uart_read_out_cnt + i] = g_rx_buff[i];
13
    } else {
14
      // END OF STRING
15
16
      break;
17
    }
18
  }
19
  // IF END OF STRING:
20
  if (strchr((char *)g_rx_buff, '\n') != NULL) {
21
    memset(&g_rx_buff[0], 0, 128); // clear rx buffer
22
    uart_handler_flag       = 1;   // so the while(1) loop @ scanf () will break and programm will proceed
23
    index_uart_read_out_cnt = 0;
24
25
  } else {
26
    index_uart_read_out_cnt += (int)rx_size;
27
  }

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.