cnlohr / esp8266ws2812i2s

ESP8266-based I2S-output WS2812(B) Driver
Other
538 stars 121 forks source link

Add APA104 #14

Open imShara opened 8 years ago

imShara commented 8 years ago

I'm trying to add APA104 support with another timings (T0H: 0.35µs, T0L: 1.36µs, T1H: 1.36µs, T1L: 0.35µs).

Can you explain your I²S frequency setup formula?

12000000 / (div * bestbck * 2)

WS2812B timings is T0H: 0.4µs, T0L: 0.85µs, T1H: 0.8µs, T1L: 0.45µs 1,25µs per led / 3 sample = 0,416 µs per sample

Default settings is

define WS2812_THREE_SAMPLE

define WS_I2S_BCK 22

define WS_I2S_DIV 4

Then.. 12000000 Hz — system frequency 2 — I²S frequency (half of system frequency) 4 — I²S frequency divider 22 — secondary I²S frequency divider

12000000 / (4 * 22 * 2) = 68181,81 Hz I²S bit speed 68181,81 / 1000000 = 0,0681 µs per bit

Aw, but there is 0,416 µs per sample.. Something goes wrong.

And why you need bitpattern arrays?

cnlohr commented 8 years ago

I think the comment is wrong as the actual system frequency is 160MHz and I don't know where the other 2 came from. 160/(22*4) = 909kHz or .55us per line bit, or 1.65us per actual bit (3 line bits make an LED bit) WILL HAVE TO EXPERIMENT TO VERIFY!!!

This is concerning as .55us is right on the hairy edge for a logical '0.' I don't know how I didn't revisit this earlier. I think you should be using foursample based on your numbers, though. Foursample works a lot better and makes more sense. In fact, just selecting FOURSAMPLE will probably give you the right timings.

imShara commented 8 years ago

@cnlohr, 160Mhz you mean

160000000 / (22 * 4) = 1818181,81818 Hz 1818181,81818 / 1000000 = 1,81 µs per bit

Right?

Ok, for FOURSAMPLE mode:

There is 4 I²S bits for each WS2812 bits, then we need I²S speed 1,25µs / 4 = 0,3125 µs per bit

160000000 / (17 * 4) = 2352941,17647 Hz 2352941,17647 / 1000000 = 2,35 µs per bit

In fact, just selecting FOURSAMPLE will probably give you the right timings.

Nope, tried

cnlohr commented 8 years ago

Your divisors are backwards on your math. IT would be 1,000,000 / 1,818,181 = 0.55 us per bit for the first and .425us per bit on the second.

imShara commented 8 years ago

Oh, you are right, thanks. Wait a commit.

imShara commented 8 years ago

Nope, it's not working proper with four sample mode with BCK = 14 (0.35µs per i2s bit, 1,4µs per led bit). Other numbers not helps too. Then, I think I need 5 bit mode (0.35µs per i2s bit, 1.75 per led bit). This is nearest numbers to datasheet values.

What is your bitpattern arrays? Array elements are led byte representation e.g 100 110 110 100 for three byte mode and e.g 1000 1110 1000 1110 for four byte mode. But why you use it? For converting received HEX value representation directly to i2s representation?

#ifdef WS2812_THREE_SAMPLE

    static const uint16_t bitpatterns[16] = {
        0b100100100100, 0b100100100110, 0b100100110100, 0b100100110110,
        0b100110100100, 0b100110100110, 0b100110110100, 0b100110110110,
        0b110100100100, 0b110100100110, 0b110100110100, 0b110100110110,
        0b110110100100, 0b110110100110, 0b110110110100, 0b110110110110,
    };

#elif defined(WS2812_FOUR_SAMPLE)

    //Tricky, send out WS2812 bits with coded pulses, one nibble, then the other.
    static const uint16_t bitpatterns[16] = {
        0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110,
        0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110,
        0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110,
        0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
    };

#endif
#elif defined(WS2812_FOUR_SAMPLE)

    uint16_t * bufferpl = (uint16_t*)&i2sBlock[0];

    if( buffersize * 4 > WS_BLOCKSIZE ) return;

    for( place = 0; place < buffersize; place++ )
    {
        uint8_t btosend = buffer[place];
        *(bufferpl++) = bitpatterns[(btosend&0x0f)];
        *(bufferpl++) = bitpatterns[(btosend>>4)&0x0f];
    }

#endif
imShara commented 8 years ago

@cnlohr, what data should be in the bufferpl array at the out of ws2812_push function?

Trying to make manual-filled 5-sample led sequence, but it's so laggy - is it right data?

void ws2812_push(uint8_t *buffer, uint16_t buffersize) {
    uint8_t *bufferpl = (uint8_t*) & i2sBlock[0];

    // LED 0 OFF
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // LED 0

    // LED 1 GREEN
    // \xFF
    *(bufferpl++) = 0b11110111;
    *(bufferpl++) = 0b10111101;
    *(bufferpl++) = 0b11101111;
    *(bufferpl++) = 0b01111011;
    *(bufferpl++) = 0b11011110;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // LED 1

    // LED 2 RED
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \xFF
    *(bufferpl++) = 0b11110111;
    *(bufferpl++) = 0b10111101;
    *(bufferpl++) = 0b11101111;
    *(bufferpl++) = 0b01111011;
    *(bufferpl++) = 0b11011110;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // LED 2

    // LED 3 BLUE
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \x00
    *(bufferpl++) = 0b10000100;
    *(bufferpl++) = 0b00100001;
    *(bufferpl++) = 0b00001000;
    *(bufferpl++) = 0b01000010;
    *(bufferpl++) = 0b00010000;
    // \xFF
    *(bufferpl++) = 0b11110111;
    *(bufferpl++) = 0b10111101;
    *(bufferpl++) = 0b11101111;
    *(bufferpl++) = 0b01111011;
    *(bufferpl++) = 0b11011110;
    // LED 3
}
imShara commented 8 years ago

Selfanswer — yes, I'm right. But I doubt in frequency formula. Need oscilloscope.

cnlohr commented 8 years ago

Hey, sorry, just getting back to this now. I recommend use of a logic analyzer on this one. You can pick up pretty good ones for $15 or so. I really think you should be able to use the 4-timing though the clock divisors might need to be different. Also, you'll need to check a bunch of other things like making sure the voltage is good etc. I guess you could use a scope to make sure there signal looks clear and you don't have ground loops, etc.