Ich habe ein kleines Programm zur Ansteuerung einesFarb-LED-Streifens
geschrieben. Das Ding stammt vom Chinesen und enthält laut Beschreibung
LEDs vom Typ WS2812B. Ich nutze den UART eines Pic32 zur Ansteuerung.
Der UART ist auf eine Baudrate von 4 MBaud und auf 8bit + 1 Start- und
Stopbit eingestellt. Jeweils 5 UART-Bits erzeugen 1 bit für die WS2812B.
Pro Byte werden daher 2 Bits für die LEDs gesendet. Der Ausgang TX des
UARTs ist über einen Transistor als Pegelwandler und Inverter mit DIN
der ersten LED verbunden (s. Anhang).
Nun funktioniert das Ganze prima, wenn ich den LED-Streifen das erste
Mal beschreibe. Sende ich unmittelbar danach einen zweiten Datenstring,
kommen die Farben durcheinander und es leuchten LEDs auf, die gar nicht
angesteuert wurden.
Interessanterweise lässt sich das Problem lösen, wenn ich die
Reset-Pause zwischen zwei Schreibvorgängen von 50 auf 100µs erhöhe. Ich
dachte zunächst, dass ich mich verrechnet habe, aber Nachmessen mit dem
Oszilloskop zeigte, dass das Timing stimmt. Es sieht so aus, als dass
die nach der 50µs-Pause gesendeten neuen Daten an die folgenden LEDs
weitergereicht werden anstatt von der ersten LED "geschluckt" zu werden.
Alles spricht dafür, dass 50µs nicht als Reset-Signal ausreichen.
In der Praxis ist das nicht allzu schlimm, denn es macht wenig Sinn,
nach 50µs gleich wieder ein neues Farbmuster zu senden.
Kann es sein, dass hier LEDs mit abweichendem Timingverhalten verbaut
wurden?
1 | #define SYS_FREQ 48000000 // 48 MHz
|
2 | #define DELAY_US 50 // 50 us gap delay
|
3 | void ws2812(unsigned int* grb, unsigned int numLeds)
|
4 | {
|
5 | unsigned int timer;
|
6 | unsigned int i,j;
|
7 | unsigned int ledColor;
|
8 | //UART codes for bit pairs 00, 01, 10, 11
|
9 | const unsigned char ColorCode[4] = {0xEF,0x8F,0xEC,0x8C};
|
10 |
|
11 | while (BusyUART1()); //wait until previous write operation has terminated
|
12 | while ((ReadCoreTimer()-timer) < (SYS_FREQ/2000000UL)*DELAY_US); //delay 50µs
|
13 |
|
14 | for (i=0;i < numLeds;i++)
|
15 | {
|
16 | ledColor = grb[i];
|
17 | for (j=0;j<12;j++)
|
18 | {
|
19 | ledColor &= 0x00FFFFFF; //mask out last 24 bits
|
20 | ledColor <<=2 ; //shift 2 bits
|
21 |
|
22 | while (BusyUART1());
|
23 | WriteUART1(ColorCode[ledColor>>24]); //send 2 bits to LED
|
24 | }
|
25 | }
|
26 | timer = ReadCoreTimer(); // beginning of 50µs reset period
|
27 | }
|