Forum: Mikrocontroller und Digitale Elektronik AVR UART + andere Interrupts / Konflikte


von Sum (Gast)


Lesenswert?

Hallo!

Ich habe eine grundsätzliche Frage zum Thema UART und Interrupt. Wie 
kann ich den Empfangsinterrupt beim Atmega austricksen?

Ich bin relativ neu bei C/C++ und Mikrocontroller. Habe mich aber glaub 
einigermaßen in die Materie reingewurstelt und baue aktuell einen 
LED-Tisch mit folgender Hardware:

-100 ws2812b RGB-LED in einer 10x10 Matrix
-Atmega1284P@16MHz mit Quarz
-verschiedener Kleinkram für Touch-Erkennung, Kommunikation, 
Stromversorgung etc

Mein Programm funktioniert soweit. Sicherlich nicht schön und effizient 
programmiert, aber ich kann durch ein Menü verschiedene Animationen 
aufrufen, Einstellungen im EEPROM vornehmen, Signalquelle umschalten und 
später kommen noch eine handvoll einfache Spiele hinzu.

Nun will ich gerne eine RS232-Schnittstelle implementieren um 
Steuerbefehle empfangen zu können. Hardware mit Max232 ist bereits 
vorhanden. Grundsätzlich denke ich, der Code ist machbar, zumal es ja 
offenbar viele gute Libs hat. Ich stehe aber an der Stelle vor einer 
Verständnissfrage:

Die LEDs werden über BitBanging angesteuert mit der Lib light_ws2812

https://github.com/cpldcpu/light_ws2812/blob/master/README.md

Die Sequenz für 100 LED dauert etwa 3ms. Aufruf erfolgt aktuell noch in 
einem Timer-Interrupt, der mit ~51Hz ausgeführt wird. Da die LED 
empfindlich auf Timing reagieren darf die Sequenz nicht unterbrochen 
werden. Also ist ein Aufruf in der main mit abgeschaltenen Interrupts 
auch nicht Besser.

Bei Standard-9600Baud  können ja aber in den ~3ms Zeit fast 30 Zeichen 
reintrudeln und den RX-Speicher hoffnungslos überlaufen lassen. Ein 
Interrupt um empfangene Zeichen in einen größeren Puffer wegzuschreiben 
geht nicht, da er ja die LED-Sequenz unterbrechen würde.

Habt ihr Ideen, wie ich das Problem umgehen könnte? Einen Attiny814 als 
Puffer dazwischen?
(DSub->RX Attiny, TX Attiny->RX Mega1284, TX Mega1284->DSub) Scheint mir 
aber übertrieben, aufwendig, kompliziert und Fehleranfällig.

Gibt es eine Art TTL-Baustein, der die Daten "Zwischenspeichern" und 
wenn Zeit ist (also auf Befehl vom 1284P) weiterleiten kann?

Oder habt ihr Vorschläge, wie ich das ganze einfach in Software lösen 
kann?

Oder sehe ich das alles einfach nur zu kritisch und das geht alles 
problemlos?

Viele Grüße,
Sum

von Georg G. (df2au)


Lesenswert?

Möchtest du die Datenrate des UART noch einmal nachrechnen? Baud ist 
nicht Byte/s sondern Bit/s.

Du könntest als primitivsten Ansatz die Baudrate herunter setzen auf zB 
ungefährliche 2400Bd.

von Eric B. (beric)


Lesenswert?

Falls die HW sich noch ändern lässt: Teile deine 10x10 Pixel auf in 4 
Quadranten mit 5x5 pixel, und steuere die eins nach dem anderen. Jedes 
Quadrant braucht dann weniger als 1ms zum ansteuern, und dir bleibt noch 
ein bisschen Zeit um zu schauen ob beim UART was angekommen ist.
Nachdem alle 4 Quadrandten angesteuert sind nimmst du dir Zeit um die 
UART-Zeichen auszuwerten, Kaffee zu trinken usw, bis die 20ms (bei deine 
~50Hz) vergangen sind.

Etwa so:
1
LOOP EVERY 20ms
2
  FOR q = 0 .. 3
3
    do output to quadrant(q)
4
    read character from UART, if present
5
  END FOR
6
  process all characters from UART
7
  do other stuff
8
END LOOP

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Sum schrieb:

> Habt ihr Ideen, wie ich das Problem umgehen könnte?

In Assembler programmieren und die Ausgabe an die LEDs nicht per 
dümmlichem Bitbanging abwickeln.

> Oder habt ihr Vorschläge, wie ich das ganze einfach in Software lösen
> kann?

Einfach ist relativ. Kommt ganz auf die Fähigkeiten des Betrachters an.

Einen Teil brauchst du jedenfalls nicht mehr selber entwickeln. Die 
unterbrechbare WS28xx-Ausgabe für bis zu 1024 WS28xx in Assembler habe 
ich schon fertig und bereits vor einiger Zeit hier gepostet. Ist zwar 
für einen Tiny4313@20MHz designed, läßt sich aber ganz sicher auch auf 
einen Mega1284P@16MHz anpassen, wenn deine Kohle nicht reicht, um einen 
20MHz-Quarz für 23 Cent zu kaufen. Wenn du dir ihn hingegen leisten 
kannst, brauchst du sogar bloss zwei Zeilen (die ersten beiden) zu 
ändern und der Code läuft sofort nach Neuassemblierung auch auf einem 
Mega1284P.

Allzu viel Luft für weitere Interupts neben dem für die LED-Ausgabe 
benutzten ist zwar nicht, aber einer geht auf jeden Fall noch. Ich habe 
z.B. in einem Projekt eine DDS-Soundausgabe mit 78kHz 
Interruptfolgefrequenz parallel zu der LED-Ausgabe drin. UART mit selbst 
115,2 kBit/s sollte also keinerlei Probleme bereiten, da ist die 
maximale Interruptfolgefrequenz ja nur lächerliche 11,5kHz. Allerdings 
muss die ISR hochoptimiert sein, ähnlich wie es auch die der LED-Ausgabe 
ist.

Viel weniger kritisch ist Code, der auschließlich in main() läuft. Du 
hast bei 20Mhz ungefähr 45% der Rechenzeit dort zur Verfügung und der 
Code dort kommt auch ziemlich regelmäßig zum Laufen, die längste Pause 
habe ich jetzt nicht im Kopf, sie ist aber in jedem Fall deutlich kürzer 
als die Dauer der Übertragung des "Datenpaketes" für eine LED. Also 
deutlich kürzer als 24/800000=30µs.

von Falk B. (falk)


Lesenswert?

@Sum (Gast)

>Ich habe eine grundsätzliche Frage zum Thema UART und Interrupt. Wie
>kann ich den Empfangsinterrupt beim Atmega austricksen?

Warum sollte man das?

>Ich bin relativ neu bei C/C++ und Mikrocontroller.

Eben DARUM sollte man eher weniger tricksen.

>Nun will ich gerne eine RS232-Schnittstelle implementieren um
>Steuerbefehle empfangen zu können.

Da muss man rein gar nichts tricksen.

>Die LEDs werden über BitBanging angesteuert mit der Lib light_ws2812

>https://github.com/cpldcpu/light_ws2812/blob/maste...

Hmm.

>Die Sequenz für 100 LED dauert etwa 3ms. Aufruf erfolgt aktuell noch in
>einem Timer-Interrupt, der mit ~51Hz ausgeführt wird.

Da liegt schon das erste Problem. Diese Aktion gehört in die 
Hauptschleife!
Siehe Interrupt.

> Da die LED
>empfindlich auf Timing reagieren darf die Sequenz nicht unterbrochen
>werden.

Für EINE LED! Aber man muss nicht die drei ms durchweg senden.

> Also ist ein Aufruf in der main mit abgeschaltenen Interrupts
>auch nicht Besser.

Doch. Denn man kann, sinnvolle Programmierung vorausgesetzt, an weniger 
zeitkritischen Stellen den UART abfragen (neudeutsch polling) und die 
Daten zwischenspeichern, z.B. in einem FIFO.

>Bei Standard-9600Baud  können ja aber in den ~3ms Zeit fast 30 Zeichen
>reintrudeln

DREI! Siehe Baud.

>und den RX-Speicher hoffnungslos überlaufen lassen. Ein
>Interrupt um empfangene Zeichen in einen größeren Puffer wegzuschreiben
>geht nicht, da er ja die LED-Sequenz unterbrechen würde.

Ja.

>Habt ihr Ideen, wie ich das Problem umgehen könnte? Einen Attiny814 als
>Puffer dazwischen?

NÖ.

>(DSub->RX Attiny, TX Attiny->RX Mega1284, TX Mega1284->DSub) Scheint mir
>aber übertrieben, aufwendig, kompliziert und Fehleranfällig.

Eben.

>Gibt es eine Art TTL-Baustein, der die Daten "Zwischenspeichern" und
>wenn Zeit ist (also auf Befehl vom 1284P) weiterleiten kann?

Hirn 2.0 mit gescheiter Programmierung. GGf. nutzt man das SPI, um die 
Daten in die LEDs zu takten, das entspannt die Sache auch nochmal 
deutlich.

>Oder sehe ich das alles einfach nur zu kritisch und das geht alles
>problemlos?

Es geht, wenn gleich man schon ein paar KONZEPTE kennen und umsetzen 
muss. Mit tricksen hat das wenig zu tun.

von Falk B. (falk)


Lesenswert?

Da der Resetcode erst nach 50us erkannt wird, hat man zwischen jedem BIT 
für die LEDs 50us Zeit, andere Dinge zu tun. Praktisch reicht es 
wahrscheinlich, nach jedem Byte oder gar jeder LED oder einer Anzahl N 
LEDs eine kleine Pause zu machen und den UART abzufragen. Langweilig, 
zumal 50us bei 16 MHz eine kleine Ewigkeit sind ;-)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Sum schrieb:
> Die Sequenz für 100 LED dauert etwa 3ms.

 Ja.

> Bei Standard-9600Baud  können ja aber in den ~3ms Zeit fast 30 Zeichen
> reintrudeln und den RX-Speicher hoffnungslos überlaufen lassen.>

 Nein, es sind (fast) 3 Zeichen.


> Aufruf erfolgt aktuell noch in
> einem Timer-Interrupt, der mit ~51Hz ausgeführt wird.

 In der ISR irgendetwas ausführen, vor allem etwas, das 3ms dauert, ist
 eine schlechte Idee.


> Habt ihr Ideen, wie ich das Problem umgehen könnte? Einen Attiny814 als
> Puffer dazwischen?

 Nein.
 51Hz = 19ms - 3ms = 16ms für andere Sachen.

 Also, Steuerbefehl (1 Byt) wird gesendet - nur ein Byte und dann wird
 auf Antwort gewartet.
 Dieses Byte landet in UART Data Register, RXC Flag wird gesetzt.
 Nachdem Daten für WS2812 raus sind, wird TXC geprüft.
 Falls gesetzt, hat dein uC noch 16ms Zeit um eine Bestätigung raus
 zuschicken, kompleten Steuerbefehl zu empfangen und auszuführen.

 Wo ist da ein Problem ?

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Falk B. schrieb:

 Etwas vorweg:
 Musst du immer 50 Zeilen zitieren, um dann ein "Hmmm" oder "Ja" von
 sich zu geben ?


>> Da die LED
>>empfindlich auf Timing reagieren darf die Sequenz nicht unterbrochen
>>werden.
>
> Für EINE LED! Aber man muss nicht die drei ms durchweg senden.

 LOL.
 Natürlich muss man das.


Falk B. schrieb:
> Da der Resetcode erst nach 50us erkannt wird, hat man zwischen jedem BIT
> für die LEDs 50us Zeit, andere Dinge zu tun. Praktisch reicht es
> wahrscheinlich, nach jedem Byte oder gar jeder LED oder einer Anzahl N

 Selbstverständlich sind das keine 50us, besonders WS2812B sind da sehr
 zickig, alles über 20us ist schon reines Gluck.

 Und warum soll er dauernd hin und her springen, wenn zwischen
 Auffrischen 16ms Zeit ist (etwa 800 Mal so lange).

Falk B. schrieb:
> Hirn 2.0 mit gescheiter Programmierung.

 Ja, anstatt 1000 Worte schreiben ohne etwas gescheites zu sagen
 oder eine konkrete Lösung anzubieten.


> GGf. nutzt man das SPI, um die
> Daten in die LEDs zu takten, das entspannt die Sache auch nochmal
> deutlich.

 Selbstverständlich nicht.
 WS2812 mit SPI ohne DMA ansteuern ist und bleibt Blödsinn.
 Entweder man bleibt in der SPI Schleife, dann ist da kein Unterschied
 zu Bitbanging, oder man arbeitet mit Interrupt, dann kann der uC von
 laufendem Hin- und Herspringen zwischen main() und ISR sowieso nichts
 gescheites machen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Marc Vesely (Firma: Vescomp) (logarithmus)

> Musst du immer 50 Zeilen zitieren, um dann ein "Hmmm" oder "Ja" von
> sich zu geben ?

Hmmm, vielleicht ;-)

>>> Da die LED
>>>empfindlich auf Timing reagieren darf die Sequenz nicht unterbrochen
>>>werden.
>
>> Für EINE LED! Aber man muss nicht die drei ms durchweg senden.

> LOL.
> Natürlich muss man das.

Nö. Siehe Datenblatt. Reset wird erst nach 50us Sendepause auf LOW 
erkannt. Schrieb ich bereits.

von Thomas E. (thomase)


Lesenswert?

Falk B. schrieb:
> Nö. Siehe Datenblatt. Reset wird erst nach 50us Sendepause auf LOW
> erkannt. Schrieb ich bereits.

Ja, das steht da. Aber die meisten WS2812b haben das Datenblatt leider 
nicht gelesen.

von Falk B. (falk)


Lesenswert?

@ Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)

>> Nö. Siehe Datenblatt. Reset wird erst nach 50us Sendepause auf LOW
>> erkannt. Schrieb ich bereits.

>Ja, das steht da. Aber die meisten WS2812b haben das Datenblatt leider
>nicht gelesen.

Selbst wenn es nur 20us sind, ist das mehr als ausreichend.

von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> Da der Resetcode erst nach 50us erkannt wird
[...]
> Praktisch reicht es
> wahrscheinlich, nach jedem Byte oder gar jeder LED oder einer Anzahl N
> LEDs eine kleine Pause zu machen und den UART abzufragen.

Das hast du niemals wirklich selber probiert, soviel ist mal sicher. Ein 
typisches Dummschwätzer-Posting.

Tatsächlich ist es nämlich so: Man darf sich keinesfalls darauf 
verlassen, dass erst ab 50µs ein Reset erkannt wird, das passiert viel 
früher. Nämlich bei der ersten LED der Kette. Dort zuerst und in der 
Folge auch bei den weiteren LEDs...

Die 50µS des DB beschreiben nämlich die Anforderungen an den Reset für 
eine Kette maximaler Länge. Erst ab dieser Resetdauer ist garantiert, 
dass auch die letzte LED einer Kette maximaler Länge den Reset noch 
als solchen erkennt.

Trotzdem ist dein Ansatz nicht völlig daneben. Man kann tatsächlich 
anderen Code in einer dümmlichen Bitbanging-Ausgabe unterbringen, der 
das Timing verzerrt, ohne die LED-Ausgabe insgesamt aus dem Tritt zu 
bringen. Das liegt daran, dass die "Sensitivität" der WS28xx generell 
auf die Dauer der *Low*-Pegel im Signal geeicht ist, nicht nur bezüglich 
des Reset, sondern auch bezüglich der Daten.

Das ermöglicht es, die High-Phasen eines jeden Datenbit DB-widrig zu 
verlängern. Allerdings nur in Maßen, irgendwann kommen die LEDs aus dem 
Tritt. Je länger die Kette und je länger die High-Phase, desto 
wahrscheinlicher. Bei voller Kettenlänge ist dieser Trick praktisch 
nicht mehr anwendbar, da sollte man tunlichst auch in dieser Beziehung 
an das vom DB vorgegebene Timing halten.

> Langweilig,
> zumal 50us bei 16 MHz eine kleine Ewigkeit sind ;-)

Es geht nicht um die 50µs, die frei sind, sondern um die 3ms (bei 100 
LEDs), die es nicht sind. Das wenigstens solltest du doch begriffen 
haben...

von Marco H. (damarco)


Lesenswert?

Leider muss ich Falk recht geben.  Ein falsches Hardwarekonzept macht 
die Sache schwieriger. Es würde schon gehen wenn man die Rs232 mit 
Flusskontrolle benutzt.  So werden immer dann Zeichen gelesen wenn die 
Daten auf den Streifen geschrieben wurden. Die Flusskontrolle ist aber 
so ziemlich aus der Mode gekommen.

von Falk B. (falk)


Lesenswert?

@ c-hater (Gast)

>Das hast du niemals wirklich selber probiert, soviel ist mal sicher. Ein
>typisches Dummschwätzer-Posting.

Das sagt der Richtige ;-)

Nimm deine Pillen und verschone uns mit deinen Beiträgen. Danke.

von Marco H. (damarco)


Lesenswert?

Der Streifen macht bei allem über 9µS einen Reset bzw. übernimmt die 
Values in die PWM Register.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Falk B. schrieb:
> Selbst wenn es nur 20us sind, ist das mehr als ausreichend.

 Wofür ?

 Aber selbst wenn es 50us sind, warum und wozu ?
 Es besteht ganz einfach keine Notwendigkeit, UART in dieser Zeit
 abzufragen.

 Taster usw. vielleicht, da magst du Recht haben, aber UART muss
 bestimmt nicht abgefragt werden.
 Kann natürlich, bringt aber überhaupt keine Vorteile.

von Falk B. (falk)


Lesenswert?

@Sum (Gast)

>-100 ws2812b RGB-LED in einer 10x10 Matrix

>Die LEDs werden über BitBanging angesteuert mit der Lib light_ws2812

>Die Sequenz für 100 LED dauert etwa 3ms.

Nun ja, es ist wohl eher KEINE LED-Matrix, so wie es der Rest der 
Welt versteht, sondern eine Kette aus 100 intelligenten LEDs. Die 100 
LEDs könnte man in 4x25 Stränge aufteilen, dann dauert es nur noch 
~750us pro Kette. Dazwischen kann man in Ruhe andere Dinge tun, ganz 
ohne Stress. Und da du es so oder so Bitbanging machst, geht das auch 
mit mehreren, verschiedenen Pins.
Ob das diese Lib kann weiß ich nicht.

von Falk B. (falk)


Lesenswert?

@ Marc Vesely (Firma: Vescomp) (logarithmus)

>> Selbst wenn es nur 20us sind, ist das mehr als ausreichend.

> Wofür ?

Um den UART abzufragen, schrieb ich schon mehrfach.

> Es besteht ganz einfach keine Notwendigkeit, UART in dieser Zeit
> abzufragen.

Doch, vor allem wenn man, warum auch immer, höhere Baudraten OHNE 
Flußkontrolle nutzen will. Kann man machen, muss man nicht.

> Taster usw. vielleicht, da magst du Recht haben, aber UART muss
> bestimmt nicht abgefragt werden.
> Kann natürlich, bringt aber überhaupt keine Vorteile.

Doch, siehe oben.

von c-hater (Gast)


Lesenswert?

Falk B. schrieb:

> Nimm deine Pillen und verschone uns mit deinen Beiträgen. Danke.

Nein, das werde ich ganz sicher nicht tun. Im Gegenteil, dieses Posting 
von dir liefert mir die Steilvorlage, dich komplett zu demontieren.

Denn ich kann durch Code jede meiner Aussagen in diesem Thread für jeden 
nachvollziehbar beweisen. Was dir hingegen äußerst schwerfallen 
dürfte...

Willst du wirklich für jeden offensichtlich als Vollarsch mit 
Gottkomplex dastehen oder bist du bereit jetzt einen Rückzieher zu 
machen?

Last chance...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Falk B. schrieb:
>> Kann natürlich, bringt aber überhaupt keine Vorteile.
>
> Doch, siehe oben.

 Nein, siehe unten.
 PC (oder wer auch immer) sendet ein einziges Byte und wartet auf
 Antwort (wobei es gar kein warten ist, sondern nur Abfrage von Zeit
 zu Zeit ob ein Zeichen empfangen worden ist).
 Kann sowieso nicht länger als 3ms dauern.
 Danach hat der PC (oder wer auch immer) 16ms Zeit um den Rest zu
 senden und der uC hat genauso viel Zeit, um das auszuführen.

>> Es besteht ganz einfach keine Notwendigkeit, UART in dieser Zeit
>> abzufragen.
>
> Doch, vor allem wenn man, warum auch immer, höhere Baudraten OHNE
> Flußkontrolle nutzen will.

 Was haben höhere Baudraten damit zu tun ?
 Und warum sollte die andere Seite Kilobits ohne Flußkontrolle
 losschicken ?
 Und mit Flusskontrolle bist du genausoweit wie mit 1 Byte und
 anschliessender Bestätigung, weil der PC (oder wer auch immer)
 immer auf RTS oder CTS warten muss.
 Wo siehst du da irgendwelche Vorteile ?

 Hältst du beim Autofahren auch alle paar Km an, um Sprit aus
 dem Kanister nachzufüllen, anstatt eine Tankstelle anzufahren
 wenn es Zeit dazu ist ?

von Peter D. (peda)


Lesenswert?

Da die UART ja bis zu 3 Byte puffern kann, sollte das doch mit den 3ms 
und 9600 Baud noch gerade so hinhauen.
Vorzugsweise schreibt man den RX-Interrupt als do{}while() Schleife und 
spart so den Prolog/Epilog-Overhead ein, falls wirklich 3 Byte 
angekommen sind.
Und mit Parity und 2 Stopbits hat man etwas mehr Luft (2,4Byte/3ms).

P.S.:
Ist doch nicht so einfach, es können ja schon 9 Bits gekommen sein, wenn 
der Timerinterrupt zuschlägt. Man müßte also noch mit Pin-Change den 
RXD-Pin überwachen und gegebenenfalls den Timerinterrupt verzögern, bis 
das Byte komplett ist.
D.h. Pin-Change Interrupt sperrt den Timerinterrupt und der RX-Interrupt 
gibt ihn wieder frei.
4800Baud wäre die einfachere Lösung.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Peter D. schrieb:

> Da die UART ja bis zu 3 Byte puffern kann

Nein, das kann sie nicht. Es sind nur (knapp) 2 Byte. Nämlich ein volles 
Byte in (received) UDR und alle Datenbits eines zweiten Bytes im 
Empfangsschieberegister, abzüglich des Stop-Bits dieses Bytes, Denn 
dessen Eintreffen verwirft bereits den Inhalt von UDR und ersetzt ihn 
durch den Inhalt des Scheiberegisters.

Und selbst wenn es wirklich drei wären:

Was machst du mit diesem Ansatz, wenn es sich nicht um 100, sondern um 
200 WS28xx-LEDs handelt. Die UART-Bitrate halbieren? Und wenn es 1024 
sind, noch zweimal halbieren?...

Das wäre zumindest dann ziemlich kontraproduktiv, wenn über eben diesen 
Kanal die Daten für die LEDs reinkommen sollen, findest du nicht auch?

Meine Fresse, warum gebt ihr nicht einfach zu, dass C hier einfach mal 
Scheisse ist. Selbst noch mit dem Trick, den ich euch verraten habe, der 
es euch ermöglichen würde, die unsägliche C-Schwäche bei ISRs zumindest 
für kurze Ketten hinreichend gut auch in dümmlichen Bitbanging-Ausgaben 
zu umschiffen. Jedenfalls wenn man ihn (im Gegensatz zu diesem unsäglich 
inkompetenten Brunner-Typen wenigstens begreift und sinnvoll 
anwendet...)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> D.h. Pin-Change Interrupt sperrt den Timerinterrupt und der RX-Interrupt
> gibt ihn wieder frei.
> 4800Baud wäre die einfachere Lösung.

 Nein.
 Die einfachere (und einzig sinnvolle) Lösung habe ich schon
 genannt. Dieses rumhantieren mit Rx- und Pinchange Interrupts
 verkompliziert die Sache nur unnötig.

 Ohne DMA gehen immer 3ms verloren, es sei denn, man macht es mit
 Assembler und Tricks (wie c-hater).
 Und selbst dann muss es durchdacht und miteinander verschachtelt
 sein, damit auch was sinnvolles daraus wird.

 Das alles ist aber ganz einfach unnötig - es ist genügend Zeit
 vorhanden, vor allem da man (nach Bestätigung) das Ganze mit 250KB
 oder mit 500KB anstatt mit 4800B rausjagen kann...

: Bearbeitet durch User
von Rainer B. (katastrophenheinz)


Lesenswert?

c-hater schrieb:
> Peter D. schrieb:
>
>> Da die UART ja bis zu 3 Byte puffern kann
>
> Nein, das kann sie nicht. Es sind nur (knapp) 2 Byte. Nämlich ein volles
> Byte in (received) UDR und alle Datenbits eines zweiten Bytes im
> Empfangsschieberegister, abzüglich des Stop-Bits dieses Bytes, Denn
> dessen Eintreffen verwirft bereits den Inhalt von UDR und ersetzt ihn
> durch den Inhalt des Scheiberegisters.

Vielleicht solltest du doch mal einen Blick ins Datenblatt riskieren, 
c-hater. So steht's im Abschnitt zur USART:
...
The Data OverRun (DORn) Flag indicates data loss due to a receiver 
buffer full condition. A Data OverRun occurs when the receive buffer is 
full (two characters), it is a new character waiting in the Receive 
Shift Register, and a new start bit is detected.
...
Macht drei, wenn ich mich nicht verrechnet habe, und der Overrun tritt 
erst beim darauffolgenden Startbit auf.

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Nein, das kann sie nicht. Es sind nur (knapp) 2 Byte.

OMG.
Probiers doch wenigstens mal aus, eh Du solchen Schmarrn erzählst.
Schreib eine Schleife aus 5s Delay und Senden solange RX-Puffer nicht 
leer.
Und dann gibt z.B. "12345" ein.
Die '1' und '2' landen im Doppelpuffer. Die '3' bleibt solange im 
Schieberegister, bis das nächste Startbit erkannt wird.
Wenn Du alles innerhalb der 5s gesendet hast, kriegst Du somit nach 5s 
"125" zurück.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Rainer B. schrieb:
> Macht drei, wenn ich mich nicht verrechnet habe, und der Overrun tritt
> erst beim darauffolgenden Startbit auf.

 Nein, du hast dich nicht verrechnet aber das ist auch egal.
 Wenn DOR Flag gesetzt wird, ist es unmöglich festzustellen,
 wieviele Bytes schon ev. verlorengegangen sind - es kann ja schon
 2 Bytes vorher gesetzt worden sein.
 Und wenn so etwas passiert, dann ist irgendetwas mit deinem Program
 falsch.
 Anstatt eine 100% sichere und ungefähr 100 Mal schnellere Prozedur
 mit Bestätigung zu implementieren, wird auf einer überaus langsamen
 und unsicheren Prozedur bestanden.

 Macht Ihr das beruflich auch so ?

von Falk B. (falk)


Lesenswert?

https://www.youtube.com/watch?v=qpMvS1Q1sos

Man beachte die ersten Lyrics im Video.

Nuff said.

;-)

von Sum (Gast)


Lesenswert?

Danke für eure Hinweise.
Ich hab mich an ein paar Stellen blöd ausgedrückt, sorry dafür.

Also, erstens: natürlich keine 30 Zeichen, da habe ich in der Eile 
Symbolrate mit Zeichen vertan, aber Symbole hier gleich Bit.
Sehe ich das richtig, dass ein 8N1 Datenbyte bei 9600baud incl 
Start/Stop dann 1042 Mikrosekunden benötigt?

Zweitens: die Senderoutine kommt auch wieder aus dem Int raus, ist mir 
durchaus bewusst. Den Timertick habe ich ja schon. Hatte nur Probleme im 
Code und zur Fehlersuche hatte ich umgebaut.

@Falk Brunner
Ja, elektrisch gesehen eine Kette aus 100 LEDs. Mechanisch als 10x10 
Matrix aufgebaut, nicht in snakelines.
Dass der Aber feud in main nicht besser ist meinte ich in Bezug auf den 
Sende-Code, der nicht unterbrochen werden darf.

@Eric B.
Deine Idee gefällt mir eigentlich. Leider geht es nicht, die externe 
Quelle ist ein "LEDPlayer" auf den ich per Relais umschalten kann, 
dieser hat nur einen Ausgang. Für die komplexen Bilder wird der per USB 
vom PC angesteuert.

@c-hater
Wie kann man deinen Code unterbrechen? Kann man deinen asm-Code in C 
einbinden? Ich habe von Assembler keine Ahnung, werde also in C 
weitermachen. Aber soweit ich weiß ist die von mir verwendete Lib auch 
in (mindestens teilweise) in Assembler geschrieben.

@Marc Vesely
Ich muss mal schauen, ob ich noch einen Pin freiräumen kann für 
Flusskontrolle. Unterstützt denn jeder USB-RS232 Adapter die 
Flusskontrolle von Haus aus? Wenn ich mit dem com-Port verbinde, wollte 
ich nichts justieren müssen, daher auch die 9,6kbaud.
Wenn das jeder com-Port standardmäßig unterstützt wäre das ja auch eine 
saubere Lösung.

von Georg G. (df2au)


Lesenswert?

Sum schrieb:
> Flusskontrolle

Ehe du lötest oder programmierst, sieh dir mal die Spezifikation an. Es 
ist mitnichten so, dass der Sender verstummt, sobald CTS wegfällt. Je 
nach UART Bauform kann da noch einiges tröpfeln.

Flowcontrol per RTS-CTS oder per Software ist nicht trivial.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Sum schrieb:
> @Marc Vesely
> Unterstützt denn jeder USB-RS232 Adapter die
> Flusskontrolle von Haus aus?

 Nein.


> Wenn ich mit dem com-Port verbinde, wollte
> ich nichts justieren müssen, daher auch die 9,6kbaud.

 Brauchst du auch nicht, du hast ja einen Quarz.

Sum schrieb:
> Wenn das jeder com-Port standardmäßig unterstützt wäre das ja auch eine
> saubere Lösung.

 Wozu ?
Marc V. schrieb:
> Nein.
>  51Hz = 19ms - 3ms = 16ms für andere Sachen.
>
>  Also, Steuerbefehl (1 Byt) wird gesendet - nur ein Byte und dann wird
>  auf Antwort gewartet.
>  Dieses Byte landet in UART Data Register, RXC Flag wird gesetzt.
>  Nachdem Daten für WS2812 raus sind, wird RXC geprüft.
>  Falls gesetzt, hat dein uC noch 16ms Zeit um eine Bestätigung raus
>  zuschicken, kompleten Steuerbefehl zu empfangen und auszuführen.

 Du kannst es natürlich machen, wie es dir beliebt, anstatt so:
Marc V. schrieb:
> Das alles ist aber ganz einfach unnötig - es ist genügend Zeit
>  vorhanden, vor allem da man (nach Bestätigung) das Ganze mit 250KB
>  oder mit 500KB anstatt mit 4800B rausjagen kann...

 P.S.
 Deine MEGA hat mit 16MHz Quarz von 250Kbps bis 1Mbps einen Fehler
 von genau keinen, nämlich 0,0%.

: Bearbeitet durch User
von BlaBla (Gast)


Lesenswert?

Georg G. schrieb:
> Baud ist
> nicht Byte/s sondern Bit/s.

Nö.... sondern Schrittgeschwindigkeit. Also Schritte pro Sekunde. Es 
gibt Verfahren die mehrere Bits pro Schritt übertragen können. Zum 
Beispiel 8 Bits bei Bei 256-QAM.

von Georg G. (df2au)


Lesenswert?

BlaBla schrieb:
> Nö....

Bei dem hier in 99.9% aller Fälle verwendeten Verfahren besteht kein 
Unterschied. Und wenn wir schon bei kleinen Rosinen sind: Nicht Schritte 
sondern Symbole wäre korrekt.

von BlaBal (Gast)


Lesenswert?

Georg G. schrieb:
> Nicht Schritte
> sondern Symbole wäre korrekt.

Nö.... beides richtig. Nur moderner ;-)

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.