Forum: Mikrocontroller und Digitale Elektronik Zeitverzögerung UART TX


von Head B. (headbanger82)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich habe einen dspic30F6014A und Zeitkritische Aufgaben zu bewältigen. 
Dazu gehört unter anderem, über einen gewissen Zeitraum Aufgaben zu 
erledigen und die Ergebnisse dann zu Übertragen mittels UART. Dazu habe 
ich mir einen FIFO gebaut in dem ich die Ergebnisse schreibe und die 
UART soll sich diese dann abholen. Ich habe eine Zeitschleife die 100ms 
läuft. Nach dem schreiben in den FIFO soll sofort wieder mit den 
eigentlichen Aufgaben weiter gemacht werden. Das klappt auch alles 
soweit ganz gut, bis auf den entscheidenden Punkt, das die Übertragung 
der Daten (9-15 ASCII Zeichen) bis zu 15 ms dauert und die Zeitschleife 
erst dann wieder startet, was bedeutet: Diese ist dann 110-115 ms statt 
die geforderten 100ms.

Ich kann zwar einen Teilsatz der Daten (5 Zeichen) in den UART Sende 
Buffer schreiben und dann weiter machen ohne das zu viel Zeit verloren 
geht (2-3ms wären OK), allerdings bei den kompletten Strings habe ich 
halt besagtes Problem. Alle von der Bibliothek zur Verfügung gestellten 
Funktionen haben das gleiche Problem mit der Übertragungsgeschwindigkeit 
wenn die strings größer sind als der eigentliche Sendebuffer der UART.

Ich bin langsam am verzweifeln, habe schon das Netz durchforstet Bücher 
gewälzt, aber nirgends eine brauchbare Lösung gefunden. Vielleicht hat 
ja einer von euch auch schon mal ein gleichartiges Problem  gehabt und 
kann mir irgendwie dabei helfen.  Schonmal vielen Dank im voraus.

Gruß

Christian

von Werner M. (Gast)


Lesenswert?

Head Banger schrieb:
> Ich habe eine Zeitschleife die 100ms läuft.
Da liegt der Fehler. Warum benutzt du keinen Timer dafür und erledigst 
die Abarbeitung der Queue per ISR?

von Head B. (headbanger82)


Lesenswert?

Hallo Werner,
erstmal Danke für die schnelle Antwort.

Habe mich da etwas unklar ausgedrückt. Die "Zeitschleife" ist ein 1ms 
Tick, realisiert mit dem Timer1. Alle anderen Aufgaben, auch das 
Empfangen von Befehlen und deren Verarbeitung, laufen und stören den 
eigentlichen Ablauf der Schleife nicht. An den Berechnungen die 
Ausgeführt werden liegt es auch nicht. Habe ja schon viele Möglichkeiten 
durchgespielt. Ich kann alles anlassen und schalte nur das Senden ab, 
schon läuft alles so wie gewünscht. Senden von UART_Buffer größe läuft 
auch, nur halt strings die länger sind halten auf. Das verschieben in 
den UART Buffer läuft mit Zeigern um unnötige kopiervorgänge zu 
minimieren.

Das er hier verzögert wird höchstwarscheinlich daran liegen:
while(!U1STAbits.TRMT);
da er hier wartet bis der Sender wieder bereit ist und die anderen 
Zeichen verarbeiten kann. Aber ich weiss halt nicht wie ich das anders 
lösen kann das alle Zeichen des strings gesendet werden.

Gruß

von g457 (Gast)


Lesenswert?

> Senden von UART_Buffer größe läuft auch, nur halt strings die länger sind
> halten auf.

Puffer (unmittelbar oder mittelbar) vergrößern oder Nachrichten 
verkürzen. Das war jetzt einfach.

von Werner (Gast)


Lesenswert?

Head Banger schrieb:
> Das er hier verzögert wird höchstwarscheinlich daran liegen:
> while(!U1STAbits.TRMT);
> da er hier wartet bis der Sender wieder bereit ist und die anderen
> Zeichen verarbeiten kann. Aber ich weiss halt nicht wie ich das anders
> lösen kann das alle Zeichen des strings gesendet werden.

Du wartest nicht per Polling auf das Freiwerden des Sendepuffers, 
sondern löst einen ISR aus, wenn das UART bereit ist, ein neues Zeichen 
aufzunehmen. Das sollte der PIC können.

von Head B. (headbanger82)


Lesenswert?

Das sollte man eigentlich denken. Bei Polling wäre die Zeitverzögerung 
ja auch erklärbar. Es geht ja nicht drum das der Sendevorgang nicht 
klappt, sondern nur um diese 10-15ms Verzögerung die ich mir in dieser 
Anwendung absolut nicht leisten kann.

void UART_TX(int bufSize)
{
  while(bufSize)
  {
 FIFO_Get(sendBufPTR,&U1TXREG);              // Zeichen in UART TX FIFO 
zum senden schreiben
    bufSize--;
  //  while(U1STAbits.UTXISEL);
    while(!U1STAbits.TRMT);
  }
}



Diese Schleife kann ja erst weiterarbeiten wenn das Transmit Shift 
Register wieder leer ist und die nächsten Zeichen aufnehmen kann und 
sobald die bufSize dann abgearbeitet ist wird weiter gemacht.

Übrigens der FIFO ist 64 Zeichen groß.

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

Du redest immer von zeitkritisch und benutzt dann Timer und Polling...
Das widerspricht sich !

Der UART erzeugt einen INT wenn der Sendebuffer leer ist, da stellst du 
das nächste Zeichen ein, wenn es eines gibt, oder schaltest den INT ab 
(TXIE).

Wenn ein Zeichen in den FIFO geschrieben wird, wird der TXIE 
eingeschaltet...

von Falk B. (falk)


Lesenswert?

@ Head Banger (headbanger82)

>ja auch erklärbar. Es geht ja nicht drum das der Sendevorgang nicht
>klappt, sondern nur um diese 10-15ms Verzögerung die ich mir in dieser
>Anwendung absolut nicht leisten kann.

Ja eben, du schreibst die Daten im Pollingbetrieb. Sprich, nach jedem 
Zeichen wartest du, bis der Sendepuffer wieder frei ist. Während der 
Übertragung ist deine CPU damit blockiert. Und gerade bei langsamen 9600 
Baud ist das ein volle Millisekunde, die pro Byte verplempert wird.

Das Gegenteil davon ist Interruptbetrieb, dann klingelt jedes Mal 
der Interrupt, wenn ein neues Zeichen gesendet werden kann. Die CPU lädt 
dieses in den USRT und macht dann wieder andere Sachen.

>Übrigens der FIFO ist 64 Zeichen groß.

Ein FIFO nützt dir wenig, wenn du den nicht intelligent nutzt. Siehe 
oben. Was du hier hast ist ein klassisches Beispiel für blockierenden 
Programmfluß. Das Gegenteil lautet Multitasking.

von Head B. (headbanger82)


Lesenswert?

Klappt jetzt. habe mich da gestern wohl etwas blöd angestellt. Vielen 
Danke erst mal.

Zu dem Timer: Das funktioniert ganz gut. Da wird ein INT ausgelöst wenn 
der in Überlauf geht (1ms) und ein counter immer hochgezählt. So weiss 
ich genau wie viel Zeit vergangen ist und kann das in eine do while 
Schleife als Bedingung setzten und immer wenn die gewünschte Zeit 
abgelaufen ist, führt er die dann geforderten Aufgaben aus und geht 
wieder zurück in die do while.

Ist eigentlich eine recht saubere und schnelle Lösung.

Aber vielen Dank nochmal für euer Hilfe.

Gruß

von Falk B. (falk)


Lesenswert?

@Head Banger (headbanger82)


>Klappt jetzt.

Was hast du geändert?

von Head B. (headbanger82)


Lesenswert?

Den Fehler im FIFO, dann die ISR:

void _attribute_ ((_interrupt_, _auto_psv_)) _U1TXInterrupt(void)
{
  IFS0bits.U1TXIF = 0;
  if (sendBufPTR->readIndex != sendBufPTR->writeIndex)
  {// Wenn FIFO nicht leer dann...
    FIFO_Get(sendBufPTR, &U1TXREG);
  }
}

und der eigentliche Aufruf des ganzen ist dann nur noch:
IFS0bits.U1TXIF = 1;

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.