Grüße Forum,
mein kleines LED-Projekt besteht aus einem Haufen PIC12F1572, die mit
ihrem UART ge-daisy-chained sind und dem WS2812-Protokoll folgen: 6
Bytes rein, nimm 3 für RGB und schiebe 3 raus. Repeat. Synchronisation
zusätzlich über TMR2, der nach 1ms UART-Inaktivität einen Interrupt
bekommt. ISR siehe Code.
Leider passiert es etwa ab der vierten Lampe, daß Bytes sporadisch 2x
gesendet werden. Zumindest, wenn ich TXIF abfrage.
Warte ich tatsächlich, bis TRMT die Leere des TSR signalisiert, läuft's
bombig; leider aber nur mit 10 Lampen, bei 11 hängt sich die erste auf,
weil der UART RX FIFO überläuft.
Kurze Suche förderte zutage:
* http://www.microchip.com/forums/m829947.aspx
* http://www.microchip.com/forums/m608851.aspx
Hat jemand mal das gleiche Problem gehabt und eventuell einen
Work-Around? 12% Flash sind noch frei...
Danke.
In den Errata für andere Chips hab ich das hier gefunden:
> === Module: EUSART ===> ======================> In rare situations, one or more extra zero bytes have been observed> in a packet transmitted by the module operating in Asynchronous mode.> The actual data is not lost or corrupted; only unwanted (extra) zero> bytes are observed in the packet.> This situation has only been observed when the contents of the> transmit buffer, TXREG, are transferred to the TSR during the> transmission of a Stop bit. For this to occur, three things must> happen in the same instruction cycle:> • TXREG is written to;> • the baud rate counter overflows (at the end of the bit period); and> • a Stop bit is being transmitted (shifted out of TSR).Work-Around 1>> If possible, do not use the module’s double-buffer capability. Instead,>> load the TXREG register when the TRMT bit is set, indicating the TSR>> is empty.
Das scheint zu funktionieren, kostet aber natürlich ein bißchen Zeit.
Kommt nun ein kontinuierlicher Datenstrom herein, hängt sich mit obigem
Code die erste Lampe irgendwann auf ("RX Overflow"), man müßte den RX
aus- und wieder einschalten.
>> If double-buffering is used and back-to-back transmission is>> performed, then load TXREG immediately after TXIF is set, or wait>> 1-bit time after TXIF is set. Both solutions prevent writing TXREG>> while a Stop bit is transmitted. Note that TXIF is set at the>> beginning of the Stop bit transmission.
Hmmmm, das sollte ja im Interrupt-basierten Betrieb funktionieren. In
meinem Falle aber nicht, weil ja der Datenstrom von der vorigen Lampe
abhängt. In den hinteren ist der Jitter dann so groß, daß das nächste
Byte nicht rechtzeitig zur Verfügung steht und dann gehts schief.
Work-Around 2>> Use a free timer resource to time the baud period.>> Set up the timer to overflow at the end of Stop bit, then start the>> timer when you load the TXREG. Do not load the TXREG when timer is>> about to overflow.
Klingt auch machbar, hab ich nicht probiert.
Meine Lösung
Ich warte jetzt tatsächlich auf TRMT, aber nutze die RX-Ringbuffer-
Implementierung von Microchip. Damit kann ich bis zu 50 RGB-Lampen
hintereinanderschalten, das sollte reichen. Mehr Strom kann die Leitung
eh nicht. Chip zu 96% voll. RAM bei 72%.
Im Errata deines Chips hab ich das hier gefunden:
Work around
When transmitting bytes, it is common practice to
check the TXIF bit before writing to the TXREG
register. To avoid the issue of duplicate bytes
being transmitted, a NOP should be placed before
the write to the TXREG register. This changes the
timing so that the issue does not occur. The TRMT
bit can also be checked in addition to or instead of
the TXIF bit to determine if TXREG can be written
without causing a duplicate-byte transmission. If
the transmit interrupt is enabled then, inside the
ISR, testing the TRMT bit will avoid transmission of
a duplicate byte.
Hi,
Danke Dir. Wo hast du denn die Errata gefunden? Sind die speziell für
den 12F1572? Würdest Du den (PDF-)Link posten?
Und, falls Du das hier meinst (#1):
===================================
1
// Received characters twice often!
2
while(0==PIR1bits.TXIF){}
3
// Questionable nop instruction?!
4
asm("nop");
5
// Forward Byte to next light...
6
TXREG=byteRead;
hat reproduzierbar nicht funktioniert. Wie auch, das eine popelige NOP
hat eine Execution time von 0,03µs gegen die Stop-Bit-Dauer von 52µs;
das bringt also afaict nichts...
Und, falls Du das hier meinst (#2):
===================================
Interrupt-Betrieb für TX hat leider auch nichts gebracht, weil eben bei
den hinteren Lampen, so ab #5 oder #6 der Jitter der Zeiten zwischen den
einzelnen Bytes schon so groß ist, daß die Fehlerbedingung eben
sporadisch eintritt. Und dann ist es egal, ob ich busy-waite oder eben
interrupt-getrieben in die Problemzone gerate.
Leider ist auch die Bitdauer bei 19k2 mit eben 52µs im Verhältnis zur
T_cy "sehr" lang; damit renne ich potentiell wahrscheinlicher in die
Fehlervoraussetzungen hinein, nicht wahr...
Die Errata sind bei MCHP auf der gleichen Seite wie die Datenblätter.
Genau darunter!
Das Problem tritt vermutlich verstärkt auf, weil bei deiner Kette der
Abstand immer genau passt.
Du könntest testen was passiert, wenn die Daten mit 2 Stopbits
losgeschickt werden.
Die Baudrate sollte eigentlich nur am Rande eine Rolle spielen, da das
Problem laut Errata auftritt, wenn genau in dem Takt das TXREG
beschrieben wird, wenn das Schriftregister leer wird.
Ein Nop() wird wegen dem Jitter wohl zu wenig sein. Eine längere
Wartezeit (viele Nop() ) könnten helfen aus dem kritischen Bereich
heraus zu kommen.
Volker S. schrieb:> Die Errata sind bei MCHP auf der gleichen Seite wie die Datenblätter.> Genau darunter!
Danke.
> Das Problem tritt vermutlich verstärkt auf, weil bei deiner Kette der> Abstand immer genau passt. Du könntest testen was passiert, wenn die Daten> mit 2 Stopbits losgeschickt werden.
Das kann zwar der PC als Master, aber der UART des 12F1572 leider nicht.
Und an der ersten LED gibt's bisher nie Probleme :) Spannend wird's erst
ab der 5. oder 6. LED. Und wie gesagt, weder 2 Stopbits noch
automatisches Parity drin in dem Kisterl...
Man könnte natürlich noch einen Timer verbraten, der noch einmal ~1,5
Bit-Dauern abwartet, bevor nach TXIF das TXREG neu befüllt wird.
Christoph S. schrieb:> Das kann zwar der PC als Master, aber der UART des 12F1572 leider nicht.
Das kann der schon. Einfach auf 9-Bit Transmit einstellen und das neunte
Bit dauerhaft auf den gleichen Wert wie das Stop-Bit setzen. Der
Receiver bleibt bei 8 Bit.
MfG Klaus
Nur den PC auf 2 Stopbits, sonst hat man doch das gleiche Problem
wieder!
Die zwei Stopbits bewirken einfach eine relativ lange Pause zwischen den
Bytes, die auch innerhalb der Kette besten bleiben sollte. Dann fällt
das Eintreffen des neuen Bytes "vermutlich" nicht mehr mit dem Ende des
Abschicken des vorherigen überein.
Christoph S. schrieb:>> The actual data is not lost or corrupted; only unwanted (extra) zero>> bytes are observed in the packet.
Die haben wohl nen Clown gefrühstückt. Wenn in einen Datenstrom 0-Bytes
eingefügt werden, ist der sehr wohl korrumpiert. Der Empfänger weiß doch
nicht, ob die 0-Bytes echt oder Fake sind.
Peter D. schrieb:> Die haben wohl nen Clown gefrühstückt...
Soll wahrscheinlich nur das Problem näher beschreiben. Dass die
Übertragung im Ar*** ist, ist ja klar...
Peter D. schrieb:> Der Empfänger weiß doch> nicht, ob die 0-Bytes echt oder Fake sind.
Der Vorlauf und Nachlauf bei einem Lochstreifen sind alles 0x00. Damit
ist ein Teletype immer klar gekommen. So what
MfG Klaus
Und was ist mit "Mittendrinlauf"? Ich halte das für einen extremen
Major-Bug, vor allem, daß es noch keine neue Silicone-Version gibt (?),
die den behebt. Die zusätzliche Check-Logik verbraucht wertvollen Flash.
Naja, auf alle Fälle euch vielen Dank, jetzt funktioniert es für meine
Anwendung zufriedenstellend gut, und vielleicht hilft der Thread ja noch
jemandem in der Zukunft.