{"id":48,"date":"2015-12-01T03:59:46","date_gmt":"2015-12-01T03:59:46","guid":{"rendered":"http:\/\/www.beer.org\/beerblog\/?p=48"},"modified":"2015-12-30T04:00:11","modified_gmt":"2015-12-30T04:00:11","slug":"some-christmas-leds","status":"publish","type":"post","link":"https:\/\/www.beer.org\/blog\/index.php\/2015\/12\/01\/some-christmas-leds\/","title":{"rendered":"Some christmas leds"},"content":{"rendered":"<p>Working on a sort of secret-santa gift for members of my truck club, I decided to do something with the WS2812B RGB LED&#8217;s. There&#8217;s a metric buttload of blog articles about these so I thought I would try to add something.<\/p>\n<p>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&#8217;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&#8217;s actually quite trivial and &#8216;just worked&#8217;. Thanks to <a href=\"https:\/\/productize.be\/driving-ws2812-programmable-rgb-leds-using-hardware-spi\/\">Joost Damad<\/a> for the pattern which saved me the effort of figuring it out myself. Isn&#8217;t the internet amazing? Whenever you get a bright idea, turns out someone&#8217;s already done it.<\/p>\n<p>First initialize the hardware SPI interface per <a href=\"http:\/\/d.av.id.au\/blog\/esp8266-hardware-spi-hspi-general-info-and-pinout\/\">David Ogilvy&#8217;s blog<\/a>:<\/p>\n<pre>bool\r\nICACHE_FLASH_ATTR\r\nws2812b_init(void)\r\n{\r\n        if (initialized || sysCfg.board_id != BOARD_ID_PHROB_WS2812B)\r\n                return true;\r\n        spi_init_gpio(SPI_DEV, SPI_CLK_USE_DIV);\r\n        spi_clock(SPI_DEV, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);\r\n        spi_tx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);\r\n        spi_rx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);\r\n        SET_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_CS_SETUP|SPI_CS_HOLD);\r\n        CLEAR_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_FLASH_MODE);\r\n        initialized = 1;\r\n        pcfg.stringlen = 16;\r\n        pcfg.ms_delay = 500;\r\n        os_timer_setfn(&amp;PatternTimer, PatternTimerHandler, NULL);\r\n        return true;\r\n}\r\n<\/pre>\n<p>Then simply load the bit in question into the SPI data register:<\/p>\n<pre>ws2812b_send_zero(void)\r\n{\r\n\r\n        int xtemp;\r\n        xtemp = spi_transaction(1, 8, 0x80, 0, 0, 0, 0, 0, 0);\r\n}\r\n\r\nws2812b_send_one(void)\r\n{\r\n        int xtemp;\r\n        xtemp = spi_transaction(1, 8, 0xe0, 0, 0, 0, 0, 0, 0);\r\n}\r\n<\/pre>\n<p>and that&#8217;s it. To send an RGB sequence for a single LED:<\/p>\n<pre>static inline void\r\nws2812b_send_color(uint8_t c)\r\n{\r\n        uint8_t bit=0x80;\r\n        while(bit) {\r\n                if (c&amp;bit)\r\n                        ws2812b_send_one();\r\n                else\r\n                        ws2812b_send_zero();\r\n                bit&gt;&gt;=1;\r\n        }\r\n}\r\n\r\nvoid\r\nws2812b_send_rgb(uint8_t r, uint8_t g, uint8_t b)\r\n{\r\n        ws2812b_send_color(g);\r\n        ws2812b_send_color(r);\r\n        ws2812b_send_color(b);\r\n}\r\n<\/pre>\n<p>I haven&#8217;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&#8217;t in the mood. What I&#8217;ve got works fairly well.<\/p>\n<p>Here it is in <a href=\"https:\/\/goo.gl\/photos\/AtqHCpn5ApGSTZhs9\">action<\/a><\/p>\n<p>Code is available <a href=\"https:\/\/github.com\/hpeyerl\/ESP8266_Relay_Board\/blob\/master\/firmware\/driver\/spi_ws2812b.c\">here<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Working on a sort of secret-santa gift for members of my truck club, I decided to do something with the WS2812B RGB LED&#8217;s. There&#8217;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&#8230; <a class=\"moretag\" href=\"https:\/\/www.beer.org\/blog\/index.php\/2015\/12\/01\/some-christmas-leds\/\">Continue reading &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-48","post","type-post","status-publish","format-standard","hentry","category-tech-stuff"],"_links":{"self":[{"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/posts\/48","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=48"}],"version-history":[{"count":1,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/posts\/48\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/posts\/48\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=48"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=48"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.beer.org\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=48"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}