UART Problem mit ATTiny2313

OP #2981248
Lesenswert?

Ich habe ein kleines Problem mit dem UART (USI) beim Attiny2313. 
Grundsätzlich funktioniert die Datenübertragung absolut einwandfrei. Ich 
werde die serielle Schnittstelle, um Daten an einen Raspberry Pi (3,3V 
Logik, kein Pegelwandler oÄ erforderlich) zu übertragen. Auf dem Pi 
läuft die Automatisierungssoftware openHAB, die die Daten dann 
auswertet. Dabei kommt es leider häufig vor, dass die Verzögerung 
zwischen dem 8. und 9. Byte der Übertragung größer ist als zwischen den 
übrigen Bytes. openHab interpretiert dies als neue Übertragung. Der 
betreffende Code sieht so aus:

Berechnungen
1
#define F_CPU 11059200
2

3
//UART
4
#define BAUD 9600UL          // Baudrate
5

6

7
// Berechnungen
8
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
9
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
10
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
11

12
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
13
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
14
#endif

Initialisierung
1
UCSRB |= (1<<RXEN);
2
UCSRB |= (1<<TXEN);
3
UBRRH = UBRR_VAL >> 8;
4
UBRRL = UBRR_VAL;


Funktion
1
static uint8_t uart_putc(unsigned char c)
2
{
3
  while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
4
  {
5
  }
6
  
7
  UDR = c;                      /* sende Zeichen */
8
  return 0;
9
}

Übertragung
1
cli();
2
for (int x = 0; x < buffersize; x++) {
3
  uart_putc(buffer[x]);
4
  buffer[x] = 0;
5
  }
6
sei();

Hat jemand eine Idee, wordurch diese unterschiedlichen Latenzen zustande 
kommen???
OP #2981273
Lesenswert?

Um wie viel kann ich nicht sagen. Ich sehe halt nur, dass für openHAB 
die Übertragung abgeschlossen ist. Und das entspricht dem Verhalten, 
dass ich sehe, wenn ich händisch eine Verzögerung einbaue. Eine 
Microsekunde reicht da schon. Wenn es der FIRO im Pi ist, kann ich 
wahrscheinlich nicht viel machen, oder?
Gast #2981450
Lesenswert?

> Ich sehe halt nur, dass für openHAB die Übertragung abgeschlossen ist.
> [..] Eine Microsekunde reicht da schon.

Klingt wie ein krankes Protokoll. Steig um auf was vernünftiges [0], das 
Timing als Paketmarker ist komplett fehlangebracht [1].

HTH

[0] z.B. was mit Start-Ende-Kennungen
[1] vergleiche die Übertragungszeit für ein einzelnes Zeichen, die ist 
hier etwa 1ms - das ist Eintausendmal länger!
OP #2981623
Lesenswert?

Ich nehme einen normalen Quarz. F_CPU habe ich gerade mal in kleineren 
Schritten sowohl nach oben als auch nach unten so lange angepasst, bis 
die Datenübertragung fehlschlägt. Das Problem bestand immer unverändert. 
Wenn ich das richtig verstanden habe, ist der Quarz, den ich verwende, 
doch ein Baudratenquarz und es müsste gar nicht groß gerundet werden, 
oder liege ich da falsch?
Gast #2982252
Lesenswert?

> Das Protokoll kann ich mir ja nicht wirklich aussuchen, dann müsste ich
> die ganze Lösung wechseln.

Afaik unterstützt openHAB so ziemlich alles an Protokollen und ist sogar 
problemlos um eigene erweiterbar. Kannst ja was ganz primitives machen, 
sowas wie 'Klartext mit \n als Ende-Marker'. Oder das vorhandene 
Protokoll um eine High-Level-Paketerkennung erweitern, die sich nicht an 
den Grenzen der einzelnen 'Status Updates' aufhängt.
OP #2982530
Lesenswert?

Daran habe ich auch schon gedacht. Leider sind ist es um meine 
Java-Kenntnisse nicht gut bestellt. Ich habe das Problem gestern in der 
openHAB Newsgroup gepostet. Einer der Programmierer wollte sich das 
ansehen und eventuell den Code so umbauen, dass nach dem letzten Zeichen 
noch ein paar ms auf weitere gewartet wird. Der entsprechende Code sieht 
zZ so aus

while (dataavailable){
do stuff
}

Und anscheinend gibt es irgendwo den Punkt, an dem aus Sicht von openHAB 
keine weiteren Daten mehr verfügbar sind...
OP #2983323
Lesenswert?

Ich habe die Berechung von UBRR mal angepasst
1
//UART
2
#define BAUD 9600UL          // Baudrate
3

4

5
// Berechnungen
6
#define UBRR_VAL ((F_CPU/(16*BAUD))-1)  // runden nicht nötig, wegen Baudratenquarz
7
//#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
8
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
9
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
10

11
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
12
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
13
#endif

Die eingestellte Baudrate sollte jetzt genau 9600 sein. Leider hat das 
das Problem auch nicht gelöst, aber vielleicht ist die Info ja für 
jemand anderes von Nutzen. Das UARt Tutorial fand ich sehr hilfreich.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren