Monthly Archives: December 2015

Some christmas leds

By   December 1, 2015

Working on a sort of secret-santa gift for members of my truck club, I decided to do something with the WS2812B RGB LED’s. There’s a metric buttload of blog articles about these so I thought I would try to add something.

From what I can see, people are spending a lot of time dealing with timing. Nodemcu can do it but not if WIFI is enabled; or at least reliably anyway.. Since I’d had some success with the hardware SPI on the ESP8266 talking to a thermocouple amplifier, I thought I would try to get the SPI hardware to do my bitbanging for me. Turns out it’s actually quite trivial and ‘just worked’. Thanks to Joost Damad for the pattern which saved me the effort of figuring it out myself. Isn’t the internet amazing? Whenever you get a bright idea, turns out someone’s already done it.

First initialize the hardware SPI interface per David Ogilvy’s blog:

bool
ICACHE_FLASH_ATTR
ws2812b_init(void)
{
        if (initialized || sysCfg.board_id != BOARD_ID_PHROB_WS2812B)
                return true;
        spi_init_gpio(SPI_DEV, SPI_CLK_USE_DIV);
        spi_clock(SPI_DEV, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
        spi_tx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        spi_rx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        SET_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_CS_SETUP|SPI_CS_HOLD);
        CLEAR_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_FLASH_MODE);
        initialized = 1;
        pcfg.stringlen = 16;
        pcfg.ms_delay = 500;
        os_timer_setfn(&PatternTimer, PatternTimerHandler, NULL);
        return true;
}

Then simply load the bit in question into the SPI data register:

ws2812b_send_zero(void)
{

        int xtemp;
        xtemp = spi_transaction(1, 8, 0x80, 0, 0, 0, 0, 0, 0);
}

ws2812b_send_one(void)
{
        int xtemp;
        xtemp = spi_transaction(1, 8, 0xe0, 0, 0, 0, 0, 0, 0);
}

and that’s it. To send an RGB sequence for a single LED:

static inline void
ws2812b_send_color(uint8_t c)
{
        uint8_t bit=0x80;
        while(bit) {
                if (c&bit)
                        ws2812b_send_one();
                else
                        ws2812b_send_zero();
                bit>>=1;
        }
}

void
ws2812b_send_rgb(uint8_t r, uint8_t g, uint8_t b)
{
        ws2812b_send_color(g);
        ws2812b_send_color(r);
        ws2812b_send_color(b);
}

I haven’t really put any effort into optimizing this. I suppose it might be possible to pre-generate a pattern and blow the whole thing out the SPI but I wasn’t in the mood. What I’ve got works fairly well.

Here it is in action

Code is available here