Show me the code!
Sure, it's here: https://github.com/marcmerlin/Neopixel-IR (but go to the end of this page for more details).See also the newer https://github.com/marcmerlin/NeoMatrix-FastLED-IR (from http://marc.merlins.org/perso/arduino/post_2018-07-30_Building-a-64x64-Neopixel-Neomatrix-_4096-pixels_-running-NeoMatrix-FastLED-IR.html )
Why my pants needed IR controlled neopixels :)
I mean, don't everyone's pants need neopixels? :)I started with a silver shirt, I added a few LEDs, and then more I got from a swap meet, and later added some LED shoes I hacked to last 12H instead of 4
The end goal was adding neopixel strips on my shirt sleeves and pant legs:
Here is a 6mn clip showing the shoes and shirt if you'd like the details:
The problem with my shirt, though, is that the colors you see on the picture are actually due to broken traces, causing the colors you see. It's better than nothing, but not what I was trying to do, and no way to create streaming effects. This is of course where neopixels come in.
I'm not going to repeat the excellent Adafruit Neopixel Uberguide here, but I have a 3mn video clip showing a standard IR RGB LED controller, compared to a neopixel strip. It also shows how I use standard remote control servo cables to wire neopixels, and how to watch out for:
Why IR and Neopixels at the same time, is hard
So, the main point of this page is however to look into the issues of controlling Neopixels and receiving IR signals at the same time.It's easy to listen for IR, and then change neopixels, leave them alone, and listen for IR again. It's hard (or near impossible on some chips) to actively update neopixel strips for animations and listen for IR commands at the same time.
Why? This video explains the issue:
What's going on is on low end arduino chips (328p, leonardo, or even AT mega and all other 16 bit AVRs), neopixels are controlled by stopping chip interrupts and sending a very precisely timed signal to the neopixels. If the timing is off just a little bit, the wrong colors get sent, or nothing works at all. This is why interrupts must be disabled
Now, there are actually many other addressable multicolor LED types. The nice ones are 4 wire and work via SPI, which allows the CPU to control the timing and the clock, removing this exact bit banging timing issue. The cheaper 3 wire ones have a set clock and require that the CPU sends a very precisely timed signal, usually done while disabling interrupts. See https://github.com/FastLED/FastLED/wiki/Overview
But since neopixel strips (aka WS2811/WS2812/WS2812B) is what I already had, I now had to deal with this precise timing issue. As you can guess, disabling interrupts causes issues with the IRRemote library because it has its on interrupt handler timer that also requires being run at a special timing, or it doesn't capture proper IR signals.
The end result is that you cannot disable interrupts and receive IR signals, and if you don't disable interrupts, the neopixel signal is unstable and the colors flicker (demonstrated int the video above).
So, unless you use some special hardware to drive neopixels strips on an AVR chip, concurrent IR + neopixels is just not going to work.
an arduino nano v3 running neopixel strips
my 328p arduiny chip (equivalent to arduino nano) and anti plug backwards toothpicks :)
because my 328p chip was unprogrammed, I had to figure out direct ISP programming pinout for it and I flashed a bootloader on it
Concurrent IR + Neopixels solution #1: be fast (Teensy 3.1)
a few chips for comparison (uno, leostick, nano v3, arduiny, and Teensy 3.1 in green)
Thanks to better FastLED hardware support, when I moved my code to a Teensy 3.1 32 bit ARM CPU, the CPU was fast enough that it had time to re-enable interrupts in the middle of updating neopixels. This in turns allowed the IR Remote interrupt handler to just barely run in between pixel updates, and capture IR codes. Success!
See this video for details:
The magic code that makes this work, is here: https://github.com/FastLED/FastLED/blob/master/platforms/arm/k20/clockless_arm_k20.h#L34
sei(); delayMicroseconds(WAIT_TIME); cli();
Thanks to this re-enabling of interrupts, things work.
So at this point, someone sensible would have declared victory. However, I felt bad wasting a Teensy 3.1 on something as simple as driving a single neopixel strip (it can drive 8 in parallel) and reading from an IR receiver, when it has around 32 I/O ports. This is why I checked if I could get this to work on ESP8266 chips which are even cheaper and have much fewer I/O pins (but add Wifi)
Concurrent IR + Neopixels solution #2: don't use the CPU for neopixels (ESP8266 (I2S) and ESP32 (RMT))
I had more 32bit chips, so I thought I would give them a try. I tried the ESP8266 and ESP32:
First, the ESP8266 mostly worked with FastLED + IRRemote, but not quite. The FastLed code, just like on Teensy, is nice enough to re-enable interrupts for a short while: https://github.com/FastLED/FastLED/blob/master/platforms/esp/8266/clockless_esp8266.h#L45
os_intr_unlock();
delayMicroseconds(WAIT_TIME);
os_intr_lock();
However in my tests, the IRremoteESP8266 library was maybe a little bit too slow and caused occasional visible neopixel glitching (this has been fixed in FastLED since I originally wrote this). This is where I found this interesting library: https://github.com/JoDaNl/esp8266_ws2812_i2s/ which manages to drive the neopixels without doing bit banging with interrupts disabled ((ab)-using the I2S hardware support). It's not a very fancy library in what it offers, but it works perfectly with interrupts enabled.
There is another DMA library using the UART instead of I2S interface, that also works without affecting interrupts: https://github.com/Makuna/NeoPixelBus
Same thing for ESP32. Actually ESP32 is even more difficult to get a perfect timing out of using bit-banging given that it's a dual core CPU running on top of an RTOS, and no matter how precise your code is, you just cannot guarantee that it'll run perfectly at the timing you need all the time. I did add ESP32 support to the Adafruit Neopixel library, but it only works most of the time, which isn't really good enough.
This where its built in RMT support comes in. It can generate 8 precise signal waves, which are perfect for neopixels, so this is the way to go to animate neopixels without disabling interrupts (making IR receiving trivial). IRremote was missing ESP32 receive support, but I added it recently, so it's all working.
FastLED now supports RMT on ESP32, so you can run interrupts while talking to Neopixels.
Here's a video summary of ESP8266 and ESP32:
Software and Libraries
So, here's a summary of all the libraries I went through, 2 for IR, and 4 for Neopixels:And here is my code again: https://github.com/marcmerlin/Neopixel-IR
The big plus from that example code is that it supports 4 different Neopixel backends and abstracts them so that the adafruit (and other) demos can run on all 4 libs. See how it does it here: https://github.com/marcmerlin/Neopixel-IR/blob/v1.0/Neopixel-IR.ino#L275
New ESP32 FastLED drivers
As of 2018, FastLED now has 2 ESP32 drivers: a software one, and an RMT driver one. See my page on ESP32 8 or 16 Parallel output and driver.Video with the whole story and details
This is a 25mn mashup of all the video clips, including a section on flashing the arduiny via ISP (AVR 328p):I also have a video showing the evolution of lights on my shirt from v1 (single non controllable color) to v2 (tri color, but not pixel addressable), to neopixels with cool patterns (jump to 3:50 if you'd like that):