Forum: Mikrocontroller und Digitale Elektronik Atmega UART mit internen Takt nachregel anhand der empfangenen Daten


von Michael S. (schiko)


Lesenswert?

Ich meine es sollte möglich sein, die Baudrate auf der
Controllerseite anhand der Emfangenen Bytes nachzuregeln.

Speziell in meinem Fall:

An der Gegenstelle sind
9600 ,8,n,1
fest vorgegeben.

Es kommen nur Druckbare Zeichen in Frage.

Ein Kommando (Payload) besteht aus einem Buchstaben und
zwei Ziffern, wobei ich Große oder kleine Buchstaben
festlegen könnte.


Überlegung:
Wenn nicht mehr als die untersten 6 bits (zB. Ziffern'0'-'9')
benötigt würden, könnte man einfach das 7. und 8. Bit testen:

if ( 8.bit gesetzt ) //Stopbit als 8. Bit erkannt
  Baudrate ++
else if (7.bit gesetzt) // 6. Bit (der Ziffer) als 7. Bit erkannt
  Baudraute --

Speziell bei mir (zwei Ziffern, ein Buchstabe) dann so:

if ( 8.bit gesetzt ) //Stopbit als 8. Bit erkannt
  Baudrate ++
else if (7.bit mind. 2 x hintereinander gesetzt) // 6. Bit als 7. Bit 
erkannt
  Baudraute --


Für einen Atmega8 mit 8MHz und PC Terminal bei ~20° habe ich
einfach mal verschiedene VCC von 2,8 V bis 5,5V durchprobiert
und konnte durch (hardkodierte) Variation von
BAUD_DELTA (-1 .. +1 ) immer stabil kommunizieren:

   #define BAUD 9600
   #define BAUD_DELTA (-1)
   #define MYUBRR (F_CPU/16/BAUD-1  +  BAUD_DELTA)
   void Init_USART( )
   {
      UBRRH = (unsigned char)(MYUBRR>>8);
      UBRRL = (unsigned char) MYUBRR    ;


Liege ich da falsch mit meinen Überlegungen?

Wie würdet ihr Nachregeln?
OSCCAL ändern? (Oscillator Calib Value)
UBRRH
UBRRL  ändern? (Baudrate)
Noch andere Ideen?
Wie kann man am sichersten sein, überhaupt die Bytes zu bekommen,
also nicht eventuell vom UART verworfen werden?

Schiko

von Ulrich F. (Gast)


Lesenswert?

Hmm .....

Ich würde mir einen LogigAnalyser, oder Ossi, oder Frequenzzähler 
schnappen und anhand dessen den Takt kalibrieren.
(wenn es denn unbedingt nötig ist)

Fertig.

von Coder (Gast)


Lesenswert?

1. Ist ein externer "Baudratenquarz" zu teuer?
2. Es gibt Controller deren interne Taktquelle hinreichen exakt für UART 
sind.

von Michael S. (schiko)


Lesenswert?

Coder schrieb:
> 1. Ist ein externer "Baudratenquarz" zu teuer?

Wenn man ihn x-fach an gegebenen fertigen Platinen an MLF-Pads flicken 
müsste, ja. Und Platz ist Geld

von Michael S. (schiko)


Lesenswert?

Ulrich F. schrieb:
> Ich würde mir einen LogigAnalyser, oder Ossi, oder Frequenzzähler
> schnappen und anhand dessen den Takt kalibrieren.
> (wenn es denn unbedingt nötig ist)

Mir geht es nicht um eine Kommunikation unter Laborbedingungen,
sondern darum, ob ein automatisches nachstellen des Taktes/Baudrate 
möglich ist.

von Ulrich F. (Gast)


Lesenswert?

Vielleicht hilft dir das 
http://www.g-heinrichs.de/attiny/Kalibrierung.pdf ja weiter ...

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Michael Schikora schrieb:
> Wie würdet ihr Nachregeln?
> OSCCAL ändern? (Oscillator Calib Value)

VUSB regelt z.B. OSCCAL nach, um ein eigenes Quarz zu sparen. Klappt 
recht gut.

Man könnte auch drüber nachdenken, den Kalibrierungswert anschließend 
ins EEPROM zu schreiben, damit man eine weitere Kalibrierung nur dann 
durchführen muss, wenn sich die Oszillatorfrequenz deutlich geändert 
hat.

von Wolfgang (Gast)


Lesenswert?

Michael Schikora schrieb:
> Wenn nicht mehr als die untersten 6 bits (zB. Ziffern'0'-'9')
> benötigt würden, könnte man einfach das 7. und 8. Bit testen:

Wenn die Signale sehr sauber sind (Flanken-Jitter deutlich unter ca. 
1/16 Bit-Zeit) mag das funktionieren.

von Schaulus Tiger (Gast)


Lesenswert?

Michael Schikora schrieb:

> Ich meine es sollte möglich sein, die Baudrate auf der
> Controllerseite anhand der Emfangenen Bytes nachzuregeln

Grundsätzlich eine nette Idee, aber du merkst eine Abweichung erst bei 
mehr als 5% (ein halbes Bit von ca. 10 Bit). Das scheint mir etwas grob 
und der Sicherheitsabstand bis zu falschen Datenbits ist minimal.

> Wie würdet ihr Nachregeln?
> OSCCAL ändern? (Oscillator Calib Value)
> UBRRH
> UBRRL  ändern? (Baudrate)

Natürlich OSCCAL, dafür ist das doch da, oder? Damit hättest du auch 
gleich genauere Frequenzen für Timer o.ä. und nicht nur für ein UART.

> Noch andere Ideen?

* Wenn sowieso zyklisch Daten ausgetauscht werden (also 
Timer-gesteuert), könnte man Nachrichten-Takt statt Bit-Takt verwenden.
* Auf einem STM32 trimme ich den Oszillator mit dem 1Hz-Takt aus einem 
RTC-Chip.
* Mit CAN geht es auf den ersten Blick garnicht, andererseits gibt es 
"Time-triggered communication". Was ist das? Würde es damit gehen?

> Wie kann man am sichersten sein, überhaupt die Bytes zu bekommen,
> also nicht eventuell vom UART verworfen werden?

Solange die Baudraten nominell gleich sind, verwirft ein normales UART 
keine Daten. Ab mehr als der doppelten Sende-Baudrate kann das Startbit 
kürzer als ein halbes Bit erscheinen. Dann würde der Empfänger alle 
Bytes ignorieren, die als LSB eine 1 und nur einzelne 0-Bits haben. Aber 
selbst dann setzt ein gutes UART noch ein "Noise Flag". Zwei aufeinander 
folgende Nullen werden wieder als Startbit interpretiert.


Coder schrieb:

> Ist ein externer "Baudratenquarz" zu teuer?

Erstens das, zweitens mechanisch empfindlich, drittens ein unnötiger 
Sender, viertens schlecht lötbar (oder zu groß). Es gibt aber inzwischen 
Keramik-Resonatoren mit 0.3% Gesamtfehler bis 125⁰C. Evt. sogar besser 
als 0.1% im Büro-Temperaturbereich.

von m.n. (Gast)


Lesenswert?

Michael Schikora schrieb:
> Wie kann man am sichersten sein, überhaupt die Bytes zu bekommen,
> also nicht eventuell vom UART verworfen werden?

Per soft-UART empfangen und bei Flankenwechsel (nach-)synchronisieren.
Oder mit 8-facher Überabtastung RxD einlesen, speichern und anschließend 
auswerten.

von Michael S. (schiko)


Lesenswert?

Schaulus Tiger schrieb:
> Solange die Baudraten nominell gleich sind, verwirft ein normales UART
> keine Daten. ...

Das ist hilfreich!

> VUSB regelt z.B. OSCCAL nach, um ein eigenes Quarz zu sparen. Klappt
recht gut.

das macht auch Mut!

"quasi" zyklisches Senden ist möglich.

Ich vergaß:
Soft-UART oder Flankenwechsel-Zeitmessungen kommen nicht in Betracht,
da die Timer schon belegt sind.

Danke zusammen!

von Coder (Gast)


Lesenswert?

Mechanisch empfindlich auch nicht schlecht LOL

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Coder schrieb:
> Mechanisch empfindlich auch nicht schlecht LOL

Wieso Lol? Das ist ein bekanntes Problem in mobilen Geräten, denn ein 
Quarz ist nun mal ein mechanisches Gebilde. Wenn der runterfällt und 
einige g aufnehmen muss, geht er kaputt. Nicht umsonst geben 
Quarzhersteller maximale Beschleunigungen an, denen man ihr Produkt 
aussetzen kann.

Hatte ich schon sehr oft in Fernbedienungen und portablen Funkgeräten 
als Fehler. Resonatoren, Quarzfilter und Quarze gehen durchaus kaputt.

von Christian B. (casandro)


Lesenswert?

Also zumindest ein einmaliges Justieren muss sein, denn auch wenn der µC 
erst mal scheinbar einwandfrei läuft, so kann die Temperaturdrift den 
leicht aus dem Toleranzbereich bringen.

Ich würde das über die Framing-Fehler machen. Die sagen Dir schon ob 
Dein Byte "richtig" lang war oder nicht.

Oder, wenn das das Gesamtkonzept das her gibt, übertrage regelmäßig eine 
Zeit. Lass dann lokal auf dem µC auch eine Uhr mit laufen, und regle 
durch den Zeitunterschied die Frequenz nach.

von c-hater (Gast)


Lesenswert?

Michael Schikora schrieb:

> Ich meine es sollte möglich sein, die Baudrate auf der
> Controllerseite anhand der Emfangenen Bytes nachzuregeln.

Ist es definitiv.

> Speziell in meinem Fall:
>
> An der Gegenstelle sind
> 9600 ,8,n,1
> fest vorgegeben.

Dann ist es ganz besonders simpel. Es geht aber auch autobaud und 
autotune kombiniert. Dann ist allerdings für eine schnelle und wirklich 
zuverlässige Erkennung die Mitarbeit des Senders gefragt, der muss eine 
Weile ein brauchbares Sync-Muster aussenden.

Aber wie schon gesagt: dein Fall mit bekannter Senderbitrate und 
ebenfalls bekanntem Frameformat ist vergleichsweise simpel zu lösen.

> Es kommen nur Druckbare Zeichen in Frage.

Damit wird es nochmal merklich einfacher.

> Überlegung:
[...]

Ungünstig, denn da schlägt Shannon/Nyquist gnadenlos zu. Zum Messen mußt 
du mindestens doppelt so schnell abtasten wie das Signal ist. Natürlich 
kann man das Schieberegister der UART auch zum Messen gebrauchen, aber 
nicht so, wie du dir das vorstellst.

> Wie würdet ihr Nachregeln?
> OSCCAL ändern? (Oscillator Calib Value)

Natürlich.

> UBRRH
> UBRRL  ändern? (Baudrate)

Nicht, wenn (wie in deinem Fall) von vornherein bekannt ist, was zu 
empfangen sein sollte.

> Wie kann man am sichersten sein, überhaupt die Bytes zu bekommen,
> also nicht eventuell vom UART verworfen werden?

Die UART-Hardware ist stockedoof, die verwirft garnix. Auch wenn das 
Statusregister FE (oder ggf. auch UPE) meldet: UDR liefert trotzdem 
getreulich die Signal-Aufzeichnung des Schieberegisters.

von Michael S. (schiko)


Lesenswert?

Ich habe einfach mal OSCCAL durchincrementiert und bei jeder
Spannung zwischen 3V und 5V5 immer einen Bereich von ca. 20
OSCCAL-Werten gehabt, bei denen die Kommunikation stabil war.

AB     ursprünglich ab Werk
9E..B3 bei  5v5
AC..BF bei  3v6
B0..C4 bei  3v0
1
   uint8_t g_nLastSerIn = 0;
2
   void CheckBaudAndCorrectIt(  uint8_t ch )
3
   {
4
      if(       ch & 0x80 )                          //Bit 7 muss 0 sein
5
         IncOSCCAL();
6
      else if( (ch & 0x40) && (g_nLastSerIn & 0x40) )// 2 x keine Ziffer
7
         DecOSCCAL();
8
      g_nLastSerIn = ch;
9
   }
Inc/DecOSCAL ändert daher gleich 10 Schritte (max. +/-20 vom Startwert)

Lässt sich schön testen und verstellen mit dem Terminal.
Spätestens bei der zweiten Ziffer ist die Kommunikation wieder OK :)

Damit kann ich wohl gut leben.
Danke für die Hints!
Schiko

von Route_66 H. (route_66)


Lesenswert?

Hallo!
Siehe ATMEL Application Note:
"AVR054: Run-time calibration of the internal RC
oscillator"

von Schiko (Gast)


Lesenswert?

Route 66 schrieb:
> Hallo!
> Siehe ATMEL Application Note:
> "AVR054: Run-time calibration of the internal RC
> oscillator"

Das ist nicht schlecht beschrieben!
Danke
..kommt nur bei mir nicht zum Einsatz, da alle Timer belegt sind.


Da wird es ja fast schon generell überflüssig, für Frequenzen bis ~8MHz 
einen Quarz einzuplanen, wenn er nur wegen des UART Not täte.

von ohne Worte (Gast)


Lesenswert?

Michael Schikora schrieb:
> Ich habe einfach mal OSCCAL durchincrementiert und bei jeder
> Spannung zwischen 3V und 5V5 immer einen Bereich von ca. 20
> OSCCAL-Werten gehabt, bei denen die Kommunikation stabil war.

nicht übersehen: über die Spannung ändert sich die Frequenz bedeutend 
weniger als über die Temperatur

von Schiko (Gast)


Lesenswert?

ohne Worte schrieb:
> Michael Schikora schrieb:
>> Ich habe einfach mal OSCCAL durchincrementiert und bei jeder
>> Spannung zwischen 3V und 5V5 immer einen Bereich von ca. 20
>> OSCCAL-Werten gehabt, bei denen die Kommunikation stabil war.
>
> nicht übersehen: über die Spannung ändert sich die Frequenz bedeutend
> weniger als über die Temperatur

Lt. Datenblatt Mega8A für 8Mhz genau andersrum:
..zumindest wo es für  mich interessant ist:
20°: bei 3V bis 5,5V => 7,3 bis 8,1 MHz
5V : bei 85°bis-40°  => 7,7 bis 8,2 MHz
Ich benötige  normal 10°-30° max "nur" ~0° bis 50°, passt.

Ich habe mich vorher mit OSCCAL nicht mehr beschäftigt,
als dass ich wusste, dass es die Möglichkeit des Takt-Tunens gibt.

Sehr "cool" finde ich, dass man den Takt ohne ext. Quarz bis auf 12MHz 
tunen kann. (hierzu finde ich nichts, was das verbietet)

von Ulrich F. (Gast)


Lesenswert?

> (hierzu finde ich nichts, was das verbietet)
Ich aber!
EEPROM und Flash schreiben wird/kann scheitern.
10% Abweichung sind erlaubt

12MHz sind ca 50% Abweichung (bei ursprünglichen 8MHz)

von ohne Worte (Gast)


Lesenswert?

Schiko schrieb:
> Lt. Datenblatt Mega8A für 8Mhz genau andersrum:
> ..zumindest wo es für  mich interessant ist:
> 20°: bei 3V bis 5,5V => 7,3 bis 8,1 MHz
> 5V : bei 85°bis-40°  => 7,7 bis 8,2 MHz

da muss man wohl für jeden Prozessor extra nachschauen:
beim Mega88 z.B.
> 20°: bei 3V bis 5V => 7,95 bis 8,08 MHz
> 5V : bei 85°bis-40°  => 7,8 bis 8,3 MHz

die Temperaturabhängigkeit ist ähnlich, die Spannungsabhängigkeit ist 
hier aber deutlich kleiner

von Schiko (Gast)


Lesenswert?

> da muss man wohl für jeden Prozessor extra nachschauen: [..]

jupp, ich denke, das ist immer so:
Vom Prinzip her ist immer alles erstaunlicherweise exakt gleich,
bis auf die Kleinigkeit, bei der man sich wirklich gaaaanz sicher ist 
;-)

von Bernd K. (prof7bit)


Lesenswert?

Folgende Lösung hab ich mal implementiert:

Eine separate PC-Software nur für diesen Zweck sendet alle x 
millisekunden das Byte 0x80 an der serielen Schnittstelle, das gibt 
genau ein Rechteck mit 8 bit Länge.

Das Gerät, unmittelbar nach dem Einschalten, überprüft für eine kurze 
Zeit ob an rx etwas anliegt das sich nur durch Vorhandensein obigen 
Signals erklären lässt, also eins von diesen:

0b00000000
0b10000000
0b11000000
0b11100000
0b11110000
0b11111000

etc..

Dann fährt es OSCCAL vom kleinsten bis zum grössten wert (Vorsicht, es 
gibt 2 Bereiche), notiert sich OSCCAL-Wert wenn zum ersten Mal statt 
0b11000000 (wir sind noch zu langsam) ein 0b10000000 (wir sind richtig) 
empfangen wird, dann erhöht es OSCCAL weiter bis zum ersten mal statt 
0b10000000 ein 0b00000000 (jetzt sind wir zu schnell) empfangen wird und 
bildet dann den Mittelwert. Das wird dann ins OSCCAL geschrieben und 
auch im EEPROM gespeichert.

Wenn beim Einschalten nicht nach ein paar dutzend Millisekunden das 
obige Kalibriersignal erkannt wird dann wird der Wert aus dem EEPROM ins 
OSCCAL geschrieben und das Gerät startet normal.

So musste ich nicht das Protokoll ändern, hab keine abenteuerliche 
Autobaud-Erkennung die zur Laufzeit komische Sachen machen könnte, 
brauch keine spezielle Hardware zum Kalibrieren, es wird nur einmal 
durchgeführt ganz am Anfang nachdem das Gerät das Licht der Welt 
erblickt hat und dann nie wieder, es sei denn man hat den vagen Verdacht 
es wäre nicht ordentlich kalibriert, dann wirds nochmal da drangehängt 
und einmal kurz aus- und eingeschaltet.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Schiko schrieb:

> ..kommt nur bei mir nicht zum Einsatz, da alle Timer belegt sind.

Natürlich hast du zumindest insofern Recht: Das Problem erfordert 
überhaupt keinen zusätzlichen Timer.

Die wegen der Baudraten-Abweichung sowieso disfunktionale UART kann aber 
nicht nur Messungen machen, sondern auch als Timer dienen und sie kann 
das beides sogar gleichzeitig leisten. Es bedarf nur eines kompetenten 
Programmierers, der diese latenten UART-Fähigkeiten dazu nutzt, den 
eingehenden Scheiß zu vermessen und den Systemtakt per 
OSCCAL-Manipulation soweit anzupassen, daß die UART wieder so genutzt 
werden kann, wie Gott/Atmel es eigentlich beabsichtigt hat...

Die Fähigkeit, sowas umzusetzen, ist wohl genau das, was 
C&P-"Programmierer" von denen unterscheidet, die das Attribut 
"Programmierer" wirklich verdienen...

von Michael S. (schiko)


Lesenswert?

Ulrich F. schrieb:
>> (hierzu finde ich nichts, was das verbietet)
> Ich aber!
> EEPROM und Flash schreiben wird/kann scheitern.
> 10% Abweichung sind erlaubt
>
> 12MHz sind ca 50% Abweichung (bei ursprünglichen 8MHz)

Ei der Daus!
Beim Nachlesen gleich noch ein Fehler meiner Überlegung gefunden:
Es wird ja IMMER in OSCCAL der Wert für 1 MHz geladen, egal was man
in den Fuses für einen Takt eingestellt hat!
Die vorgeschlagene Prozedur um an die Kalibrierwerte für 2,4 u. 8 MHz
zu kommen, ist ja fürchterlich. (Per Programmer lesen, dann ins Flash
oder EEPROM schreiben..)

von Michael S. (schiko)


Lesenswert?

Bernd K. schrieb:
> Folgende Lösung hab ich mal implementiert:

> Eine separate PC-Software nur für diesen Zweck sendet alle x
> millisekunden das Byte 0x80 an der serielen Schnittstelle [..]

..die Idee finde ich auch nicht schlecht.
Hmm.. für Codepage-Unabhängigkeit mit 'nem Terminal könnte man
auch das '?' nehmen das Bit 0 und 7 ignorieren und für die Auswertung
die beiden Übergänge beim Wechsel zwischen den 3 hohen Bits nehmen.
1. Übergang von (0x7E & UBR) == 0x1E --> (0x7E & UBR) == 0x3E
2. Übergang von (0x7E & UBR) == 0x3E --> (0x7E & UBR) == 0x7E
Wenn ansonsten '~' '>' und 0x1E nicht im Protokoll vorkommen,
könnte jederzeit mit dem Finger auf '?' "nachgetunet" werden.

von Michael S. (schiko)


Lesenswert?

c-hater schrieb:
> Schiko schrieb:
>
>> ..kommt nur bei mir nicht zum Einsatz, da alle Timer belegt sind.
>
> Natürlich hast du zumindest insofern Recht: Das Problem erfordert
> überhaupt keinen zusätzlichen Timer.
>
> Die [..] UART kann aber
> nicht nur Messungen machen, sondern auch als Timer dienen

sogar ohne Gegenstelle bei Verwendung des Transmit-Complete-Interrupts 
:)

> Die Fähigkeit, sowas umzusetzen, ist wohl genau das, was
> C&P-"Programmierer" von denen unterscheidet, die das Attribut
> "Programmierer" wirklich verdienen...

Bei sowas bin ich vorsichtig. "Gut" Kopiert ist schließlich besser,
als ein krummes Rad neu zu erfinden. Man muss nur genau wissen, was man 
kopiert.

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.