Styra digital LED strip med PIC (måste gå fort)
Styra digital LED strip med PIC (måste gå fort)
Jag har en digital LED strip som har legat ett tag som jag tänkte att det var dags
att göra något med. Kontrollerkretsen är TM1809 så jag drar ner databladet för
att se hur den ska styras. Uppenbarligen måste det gå väldigt fort då en etta är
hög i 1200ns samt låg i 600ns, nolla är motsatt. En vanlig PIC gör väl en instruktion
på fyra klockcyklar, vilket betyder att varje instruktion tar 25ns i 16MHz.
Uppenbarligen finns det tid till att bitbanga, men det känns väl pressat om jag dessutom
ska göra någon styrning också.
Finns det bättre sätt att styra dessa än vad jag kommer på på rak arm?
att göra något med. Kontrollerkretsen är TM1809 så jag drar ner databladet för
att se hur den ska styras. Uppenbarligen måste det gå väldigt fort då en etta är
hög i 1200ns samt låg i 600ns, nolla är motsatt. En vanlig PIC gör väl en instruktion
på fyra klockcyklar, vilket betyder att varje instruktion tar 25ns i 16MHz.
Uppenbarligen finns det tid till att bitbanga, men det känns väl pressat om jag dessutom
ska göra någon styrning också.
Finns det bättre sätt att styra dessa än vad jag kommer på på rak arm?
Re: Styra digital LED strip med PIC (måste gå fort)
> En vanlig PIC gör väl en instruktion på fyra klockcyklar, vilket betyder att varje instruktion tar 25ns i 16MHz.
Ja och nej..... En instruktion tar fyra klockcykler vilket gör 250ns med 16MHz klocka.
Ja och nej..... En instruktion tar fyra klockcykler vilket gör 250ns med 16MHz klocka.
Re: Styra digital LED strip med PIC (måste gå fort)
Vad är det för kommunikationsprotokoll? Låter märkligt att den ska ha en sådan hög hastighet.
Re: Styra digital LED strip med PIC (måste gå fort)
>En instruktion tar fyra klockcykler vilket gör 250ns med 16MHz klocka.
Och det gjorde ju saken ännu bättre
>Vad är det för kommunikationsprotokoll?
Nått special tror jag, se databladet http://www.deskontrol.net/descargas/dat ... TM1809.pdf
Och det gjorde ju saken ännu bättre

>Vad är det för kommunikationsprotokoll?
Nått special tror jag, se databladet http://www.deskontrol.net/descargas/dat ... TM1809.pdf
- Lennart Aspenryd
- Tidigare Lasp
- Inlägg: 12607
- Blev medlem: 1 juli 2011, 19:09:09
- Ort: Helsingborg
Re: Styra digital LED strip med PIC (måste gå fort)
Data transmission speed have two selected mode ( 400Kbps and 800Kbps )
Vad väljer du?
Vad väljer du?
Re: Styra digital LED strip med PIC (måste gå fort)
>Vad väljer du?
Tiderna jag beskrev ovan är för low speed (400Kbps)
Tiderna jag beskrev ovan är för low speed (400Kbps)
Re: Styra digital LED strip med PIC (måste gå fort)
Det borde gå att missbruka SPI till detta tycker jag. Med en SPI frekvens på 8MHz
så är varje bit 125ns lång, korrekt?
125*4=500, 500ns är inom gränsen för den korta pulsen i low speed.
125*9=1125, 1125ns är inom gränsen för den långa pulsen i low speed.
Det bör t.o.m. gå med en frekvens på 4MHz tycker jag
250*2=500
250*5=1250, 1250 är också inom gränsen.
Det dumma är bara att varje "LED bit" blir 13 respektive 7 "SPI bitar", om detta blir
ett problem vet jag inte än
Ska handla innan affären stänger men måste testa detta så fort jag kommer hem.
så är varje bit 125ns lång, korrekt?
125*4=500, 500ns är inom gränsen för den korta pulsen i low speed.
125*9=1125, 1125ns är inom gränsen för den långa pulsen i low speed.
Det bör t.o.m. gå med en frekvens på 4MHz tycker jag
250*2=500
250*5=1250, 1250 är också inom gränsen.
Det dumma är bara att varje "LED bit" blir 13 respektive 7 "SPI bitar", om detta blir
ett problem vet jag inte än

Ska handla innan affären stänger men måste testa detta så fort jag kommer hem.
-
- Inlägg: 2436
- Blev medlem: 28 januari 2007, 18:45:40
- Ort: Kungsbacka
Re: Styra digital LED strip med PIC (måste gå fort)
Du kan använda uart(inverterad).
Jag har gjort det på ws2812, det ser ut att vara samma protokoll.
Du sätter upp den på 4Mbps och utnyttjar start och stop bit.
Du skickar 2 bit i varje byte(10bit) på uarten.
Jag har kod om du vill ha.
Jag har gjort det på ws2812, det ser ut att vara samma protokoll.
Du sätter upp den på 4Mbps och utnyttjar start och stop bit.
Du skickar 2 bit i varje byte(10bit) på uarten.
Jag har kod om du vill ha.
Re: Styra digital LED strip med PIC (måste gå fort)
>Jag har gjort det på ws2812, det ser ut att vara samma protokoll.
Dock lite olika timings om jag förstått det rätt.
Tar gärna koden, borde ju gå att anpassa den om det inte funkar direkt.
Dock lite olika timings om jag förstått det rätt.
Tar gärna koden, borde ju gå att anpassa den om det inte funkar direkt.
-
- Inlägg: 2436
- Blev medlem: 28 januari 2007, 18:45:40
- Ort: Kungsbacka
Re: Styra digital LED strip med PIC (måste gå fort)
ws2812.c
ws2812.h
Kod: Markera allt
#include "ws2812.h"
#include "htc.h"
#ifdef RGB888
unsigned char pixels[NUMBER_OF_LEDS * 3];
#endif
#ifdef RGB565
unsigned char pixels[NUMBER_OF_LEDS * 2];
#endif
unsigned char reverse(unsigned char in) {
in = ((in & 0xF0) >> 4) | ((in & 0x0F) << 4);
in = ((in & 0xCC) >> 2) | ((in & 0x33) << 2);
return ((in & 0xAA) >> 1) | ((in & 0x55) << 1);
}
#ifdef RGB888
RGB_TYPE getLed(unsigned char led) {
RGB_TYPE rgb;
rgb.G = pixels[led * 3 + 0];
rgb.R = pixels[led * 3 + 1];
rgb.B = pixels[led * 3 + 2];
rgb.R = reverse(rgb.R);
rgb.G = reverse(rgb.G);
rgb.B = reverse(rgb.B);
return rgb;
}
void setLed(unsigned char led, RGB_TYPE rgb) {
rgb.R = reverse(rgb.R);
rgb.G = reverse(rgb.G);
rgb.B = reverse(rgb.B);
pixels[led * 3 + 0] = rgb.G;
pixels[led * 3 + 1] = rgb.R;
pixels[led * 3 + 2] = rgb.B;
}
void setLeds() {
unsigned char bitTable[4] = {0xEF, 0xE8, 0x0F, 0x08}, color;
unsigned char gieState, leds = NUMBER_OF_LEDS;
unsigned char *data = pixels;
gieState = GIE;
GIE = 0;
while (leds--) {
color = *data++;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color = *data++;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color = *data++;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
color >>= 2;
while (!TXIF);
TXREG = bitTable[color & 0x03];
}
//Just delay
for (color = 0; color < 150; color++);
GIE = gieState;
}
#endif
#ifdef RGB565
RGB_TYPE getLed(unsigned char led) {
RGB_TYPE rgb;
unsigned short rgb565;
rgb565 = pixels[led * 2 + 0];
rgb565 |= pixels[led * 2 + 1] << 8;
rgb565 = ((rgb.B & 0b00011111) << 11) | ((rgb.R & 0b00011111) << 6) | ((rgb.G & 0b00111111));
rgb.G = rgb565 & 0b00111111;
rgb.R = (rgb565 >> 6) & 0b00011111;
rgb.B = (rgb565 >> 11) & 0b00011111;
rgb.R = reverse(rgb.R);
rgb.G = reverse(rgb.G);
rgb.B = reverse(rgb.B);
return rgb;
}
void setLeds() {
const unsigned char bitTable[4] = {0xEF, 0xE8, 0x0F, 0x08};
unsigned char gieState, leds = NUMBER_OF_LEDS;
unsigned short rgb565;
unsigned short *data = (unsigned short*) pixels;
gieState = GIE;
GIE = 0;
while (leds--) {
rgb565 = *data++;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x01];
while (!TXIF);
TXREG = bitTable[rgb565 & 0x01];
rgb565 >>= 1;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x03];
rgb565 >>= 2;
while (!TXIF);
TXREG = bitTable[rgb565 & 0x01];
while (!TXIF);
TXREG = bitTable[rgb565 & 0x01];
}
//Just delay
for (rgb565 = 0; rgb565 < 150; rgb565++);
GIE = gieState;
}
void setLed(unsigned char led, RGB_TYPE rgb) {
unsigned short rgb565;
rgb.R = reverse(rgb.R);
rgb.G = reverse(rgb.G);
rgb.B = reverse(rgb.B);
rgb565 = ((rgb.B & 0b00011111) << 11) | ((rgb.R & 0b00011111) << 6) | ((rgb.G & 0b00111111));
pixels[led * 2 + 0] = ((rgb565)&0xFF);
pixels[led * 2 + 1] = ((rgb565 >> 8)&0xFF);
}
#endif
Kod: Markera allt
#ifndef WS2812_H
#define WS2812_H
#define RGB888
//#define RGB565
//#define RGB332
#define NUMBER_OF_LEDS 34
extern unsigned char pixels[];
typedef struct {
unsigned char R;
unsigned char G;
unsigned char B;
} RGB_TYPE;
void setLeds();
void setLed(unsigned char, RGB_TYPE);
RGB_TYPE getLed(unsigned char);
#endif /* WS2812_H */
Re: Styra digital LED strip med PIC (måste gå fort)
Tackar för koden.
Jag kunde tyvärr inte få UART att funka, framförallt då jag har lite svårt att få
matten att gå ihop när det gäller frekvens, pulslängd och bithastighet.
Men din kod fick mig att tänka om en del då du stänger av intrerrupt. Tanken var
först att jag skulle hinna göra saker mellan pixlarna men det förstår jag nu att
det inte går. Så med den upplysningen gick jag tillbaka till att bitbanga. Delayen
mellan nivåskillnaderna är en respektive två NOP, undra vad jag skulle kunna göra
för kul på den tiden
Koden för att uppdatera vad som visas på slingan ska ju såklart köras mellan
skanningarna. Med en uppdateringsfrekvens på 30FPS har jag 1/30~= 33ms
mellan skanningarna och uppdateringstiden på slingan är (0,5+1,25)*8*3*60 = 2520µs.
Alltså har jag ungefär 30ms att göra annat mellan skanningarna, liite större möjligheter.
Jag kunde tyvärr inte få UART att funka, framförallt då jag har lite svårt att få
matten att gå ihop när det gäller frekvens, pulslängd och bithastighet.
Men din kod fick mig att tänka om en del då du stänger av intrerrupt. Tanken var
först att jag skulle hinna göra saker mellan pixlarna men det förstår jag nu att
det inte går. Så med den upplysningen gick jag tillbaka till att bitbanga. Delayen
mellan nivåskillnaderna är en respektive två NOP, undra vad jag skulle kunna göra
för kul på den tiden

Koden för att uppdatera vad som visas på slingan ska ju såklart köras mellan
skanningarna. Med en uppdateringsfrekvens på 30FPS har jag 1/30~= 33ms
mellan skanningarna och uppdateringstiden på slingan är (0,5+1,25)*8*3*60 = 2520µs.
Alltså har jag ungefär 30ms att göra annat mellan skanningarna, liite större möjligheter.
Re: Styra digital LED strip med PIC (måste gå fort)
Det finns två lösningar som jag rent omedelbart kommer på:
* Göra en hårdvara som skickar rätt pulståg och som triggas an en synkron sändning med UART'en. Det motsvarar ju en bithastighet på 555kHz som typisk hastighet och 475kHz som lägst. Det gör att data kan fyllas i UART'en med 59,375kHz, en fullt överkomlig hastighet ved 16MHz.
* Välj en snabbare processor eller öka kristallfrekvensen ordentligt.
Det finns ju även det alternativ att du kan välja en annan styrkrets men jag förstår att den redan är köpt...
EDIT: Om man utgår ifrån 16MHz som styrsignal ska pulserna vara 8 hhv. 16 klockpulser långa, trevliga "digitala" värden om man bygger en hårdvara för sändningen.
* Göra en hårdvara som skickar rätt pulståg och som triggas an en synkron sändning med UART'en. Det motsvarar ju en bithastighet på 555kHz som typisk hastighet och 475kHz som lägst. Det gör att data kan fyllas i UART'en med 59,375kHz, en fullt överkomlig hastighet ved 16MHz.
* Välj en snabbare processor eller öka kristallfrekvensen ordentligt.
Det finns ju även det alternativ att du kan välja en annan styrkrets men jag förstår att den redan är köpt...
EDIT: Om man utgår ifrån 16MHz som styrsignal ska pulserna vara 8 hhv. 16 klockpulser långa, trevliga "digitala" värden om man bygger en hårdvara för sändningen.
Re: Styra digital LED strip med PIC (måste gå fort)
Det var ett intressant och lite ovanligt sätt att skicka data på 
Det besvärliga är ju att varje bit är uppdelad i tre delar. Första delen är alltid "etta", andra delen innehåller databiten och tredje delen är alltid "nolla".
Jag tänkte också först SPI. Det innebär att du måste lagra databitarna ojämnt i tre bytes åt gången (24 bitar), vilket då kan överföra 8 bitar.
Du vill skicka åtta bitar åt gången. Vi kallar dem ABCDEFGH.
De läggs då in på olika unika positioner inuti tre bytes som skickas med SPI med bitfrekvensen 1.66 MHz:
1A01B01C - 01D01E01 - F01G01H0
Vi behöver alltså en SPI-frekvens på 1.66MHz. Det betyder att du behöver köra med ca 13.33 MHz klocka och dela med 8 för att få rätt SPI-frekvens. (Maximal avvikelse 12%). Man kan alltså köra med något mellan 11.95 - 14.90 MHz kristall. 14.31 MHz är troligtvis den vanligaste bland dessa udda, om man inte vill tänja gränserna och lägga sig på 12.00 MHz.
För att göra detta tror jag det enklaste är att använda en mall för de tre byten, där "databitarna" först är nollor:
10010010 - 01001001 - 00100100
flyttar sedan "manuellt" varje bit dit de ska vara.... hm... vi har alltså 8*8*3 = 192 instruktioner på oss att utföra alltihop innan nästa tre bytes ska skickas ut. Under tiden måste vi bevaka när nästa byte ska laddas in i SPI-bufferten. Alltså 64 instruktioner per skickad "byte"
Det här ska vi väl fixa enkelt!
(pseudo-assembler):

Det besvärliga är ju att varje bit är uppdelad i tre delar. Första delen är alltid "etta", andra delen innehåller databiten och tredje delen är alltid "nolla".
Jag tänkte också först SPI. Det innebär att du måste lagra databitarna ojämnt i tre bytes åt gången (24 bitar), vilket då kan överföra 8 bitar.
Du vill skicka åtta bitar åt gången. Vi kallar dem ABCDEFGH.
De läggs då in på olika unika positioner inuti tre bytes som skickas med SPI med bitfrekvensen 1.66 MHz:
1A01B01C - 01D01E01 - F01G01H0
Vi behöver alltså en SPI-frekvens på 1.66MHz. Det betyder att du behöver köra med ca 13.33 MHz klocka och dela med 8 för att få rätt SPI-frekvens. (Maximal avvikelse 12%). Man kan alltså köra med något mellan 11.95 - 14.90 MHz kristall. 14.31 MHz är troligtvis den vanligaste bland dessa udda, om man inte vill tänja gränserna och lägga sig på 12.00 MHz.
För att göra detta tror jag det enklaste är att använda en mall för de tre byten, där "databitarna" först är nollor:
10010010 - 01001001 - 00100100
flyttar sedan "manuellt" varje bit dit de ska vara.... hm... vi har alltså 8*8*3 = 192 instruktioner på oss att utföra alltihop innan nästa tre bytes ska skickas ut. Under tiden måste vi bevaka när nästa byte ska laddas in i SPI-bufferten. Alltså 64 instruktioner per skickad "byte"

Det här ska vi väl fixa enkelt!

(pseudo-assembler):
Kod: Markera allt
läs in databyte i r20.
ladda r16 med värdet 0b10010010; startvärde
; nu ska positionerna 6,3 och 0 fyllas med bitarna 0,1 och 2.
sätt T-flagga med värdet i r20.0;
ld r16.6,T-flagga;
sätt T-flagga med värdet i r20.1;
ld r16.3 med T;
sätt T-flagga med värdet i r20.2;
ld r16.0 med T;
loop: Wait until SPI-buffer är ledig; (läs av flagga och branch if bit is cleared)
skicka första SPI-byte (r16);
ladda r16 med 0b01001001;
; nu ska positionerna 5 och 2 fyllas med bitarna 3 och 4.
sätt T-flagga med värdet i r20.3;
ld r16.5 med T;
sätt T-flagga med värdet i r20.4;
ld r16.2 med T;
loop: Wait until SPI-buffer är ledig; (läs av flagga och branch if bit is cleared)
skicka första SPI-byte (r16);
ladda r16 med 00100100;
; nu ska positionerna 7, 4 och 1 fyllas med bitarna 5,6 och 7.
sätt T-flagga med värdet i r20.5;
ld r16.7,T-flagga;
sätt T-flagga med värdet i r20.6;
ld r16.4 med T;
sätt T-flagga med värdet i r20.7;
ld r16.1 med T;
loop: Wait until SPI-buffer är ledig; (läs av flagga och branch if bit is cleared)
skicka första SPI-byte (r16);
läs in nästa databyte eller avbryt...
Re: Styra digital LED strip med PIC (måste gå fort)
Det finns även 14.7456MHz i det intervallet.