Styra digital LED strip med PIC (måste gå fort)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

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?
H.O
Inlägg: 5917
Blev medlem: 19 mars 2007, 10:11:27
Ort: Ronneby

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av H.O »

> 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.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av jesse »

Vad är det för kommunikationsprotokoll? Låter märkligt att den ska ha en sådan hög hastighet.
Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

>En instruktion tar fyra klockcykler vilket gör 250ns med 16MHz klocka.
Och det gjorde ju saken ännu bättre :P

>Vad är det för kommunikationsprotokoll?
Nått special tror jag, se databladet http://www.deskontrol.net/descargas/dat ... TM1809.pdf
Användarvisningsbild
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)

Inlägg av Lennart Aspenryd »

Data transmission speed have two selected mode ( 400Kbps and 800Kbps )
Vad väljer du?
Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

>Vad väljer du?
Tiderna jag beskrev ovan är för low speed (400Kbps)
Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

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.
victor_passe
Inlägg: 2436
Blev medlem: 28 januari 2007, 18:45:40
Ort: Kungsbacka

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av victor_passe »

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.
Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

>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.
victor_passe
Inlägg: 2436
Blev medlem: 28 januari 2007, 18:45:40
Ort: Kungsbacka

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av victor_passe »

ws2812.c

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
ws2812.h

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 */

Pajn
Inlägg: 1160
Blev medlem: 6 juni 2008, 19:14:29
Ort: Nyköping
Kontakt:

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Pajn »

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 :doh:

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.
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av Icecap »

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.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av jesse »

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" :oops:
Det här ska vi väl fixa enkelt! :foliehatt:

(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...
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Re: Styra digital LED strip med PIC (måste gå fort)

Inlägg av vfr »

Det finns även 14.7456MHz i det intervallet.
Skriv svar