B4R Question Getting IR to work correctly with NeoPixels and fast timer interval

Robert Gately

Member
Licensed User
Greetings,
The program I want to write will have 9 timers that have code to produce different visual effects, using 60 WS2812B LEDs. I also want to use an IR remote to select (enable) the timers.

But, I'm not able to read the IR correctly when the NeoPixel Show command is used in a timer sub that has a fast interval of about 80 - 0. Everything works fine if the timer interval is slower, but I need the timer intervals to go as fast as 10-0 in order to produce the desired visual effects. I also discovered that the IR and NeoPixels works correctly if the LED strip is initialized for 8 or less LEDs, but I need to use 60 WS2812B LEDs.

I've tried using the AdafruitNeoPixel and IRremote libraries and had the same results.

------------------------------------------------------------------------

I stumbled upon a FAQ on the GitHub site that talks about the problem...
"IR does not work right when using Neopixels (aka WS2811/WS2812/WS2812B). Whether you use the Adafruit Neopixel lib, or FastLED, interrupts get disabled on many lower end CPUs like the basic arduinos. In turn, this stops the IR interrupt handler from running when it needs to. There are some solutions to this on some processors, see this page from Marc MERLIN (http://marc.merlins.org/perso/ardui...Teensy3_1-ESP8266-ESP32-IR-and-Neopixels.html)."

I was hoping to use the Pro Mini or Nano because of their low cost and small size, but I might have to upgrade to a faster board if that's what it takes to solves the IR and NeoPixels problem.

Does anyone have a recommendation for board to use with B4R that is low cost and fast?

Is there anything that can be done in code to make IR and NeoPixels work together with fast timer intervals (0 - 50) on a Pro Mini or Nano?

Thanks in advance.


B4X:
Sub Process_Globals
    Public Serial1 As Serial
   
    Private Strip1 As NSRainbow             ' rNSRainbow Library, WS2812B LED strip

    Private tmrProgram_1 As Timer        ' fast timer      
    Private tmrProgram_2 As Timer        ' slow timer
    Private tmrIR As Timer                    ' reads the IR and selects one of the program timers
   
    Private ProgNum As Int = 0            ' current program
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
   
    Strip1.Initialize(60, 8)                                 ' no problem if initialized for 8 LEDs, but I need 60 LEDs 
    Strip1.SetBrightness(100)                            
    Strip1.Clear(60)

    RunNative("enableIRIn", Null)                        ' use C code instead of library
   
    tmrProgram_1.Initialize("tmrProgram_1_Tick", 20)    ' problem when less than 80 or so
    tmrProgram_1.Enabled = False
    tmrProgram_2.Initialize("tmrProgram_2_Tick", 150)    ' no problems at this speed
    tmrProgram_2.Enabled = False
    tmrIR.Initialize("tmrIR_Tick", 100)                    ' speed doesn't seem to matter
    tmrIR.Enabled = True   
End Sub

' This timer demonstrates the problem where tmrIR can't correctly read IR
' because the timer interval is too fast (about 80 or faster).
Private Sub tmrProgram_1_tick                           
    Strip1.SetColor(1, 0, 0, 200)                        ' turn LED red
    Strip1.Show                                                ' If this line is commented out then the IR works
End Sub

' This timer demonstrates that a slower interval (80 or slower) doesn't interfere
' with tmrIR reading the IR
Private Sub tmrProgram_2_Tick
    Strip1.SetColor(1, 200, 0, 0)                        ' turn LED blue
    Strip1.Show
End Sub

Sub tmrIR_Tick
    Dim Result As UInt = RunNative("read", Null)
    If Result > 0 Then
        tmrProgram_1.Enabled = False                ' disable timers
        tmrProgram_2.Enabled = False                ' disable timers

        Select Result
            Case 41565                              ' IR button 1 was pressed
                Log("Program 1")
                ProgNum = 1
            Case 25245                              ' IR button 2 was pressed
                Log("Program 2")
                ProgNum = 2
            Case Else                                ' junk from IR
                Log("Else, Result: ", Result)
        End Select
       
        ' enable timer of the selected program
        Select ProgNum
            Case 1
                tmrProgram_1.Enabled = True
            Case 2
                tmrProgram_2.Enabled = True
        End Select
    End If
End Sub

' IR
#if C
#include "IRremote.h"
IRrecv irrecv(4); //signal pin. Change as needed
decode_results results;
B4R::Object res;
void enableIRIn(B4R::Object* o) {
   irrecv.enableIRIn();
}
B4R::Object* read(B4R::Object* o) {
   ULong result = 0;
   if (irrecv.decode(&results)) {
     irrecv.resume();
     //b4r_main::_lastread = millis();
     result = results.value;
   }
   return res.wrapNumber(result);
}
#end if
 

miker2069

Active Member
Licensed User
Could potentially the new ESP32 with two cores be useful? The tool chain is still very much in it's early stages but may be the IR and NeoPixel libs may work. Also are you really tied to using an IR remote? If wifi is an option and if you get the esp8266 it wouldnt be to much work to create a simple app to implement the equivalent remote control device functionality - then you dont have to worry about the IR interrupts firing.
 
Upvote 0

Robert Gately

Member
Licensed User
Could potentially the new ESP32 with two cores be useful? The tool chain is still very much in it's early stages but may be the IR and NeoPixel libs may work. Also are you really tied to using an IR remote? If wifi is an option and if you get the esp8266 it wouldnt be to much work to create a simple app to implement the equivalent remote control device functionality - then you dont have to worry about the IR interrupts firing.

I've never used the ESP8266 or ESP32 before and expect it to take a while to get familiar with it, but one core (80 mHz or so) should do the job. Using WIFI to control the LEDs sounds like a great idea, except that it would not be as simple to implement as IR, because I'd have to write an app (possibly one for each OS) and customers would have to download and install it on their devices. At this point, I need to keep things as simple as possible. Thanks for the suggestion
 
Upvote 0

Robert Gately

Member
Licensed User
Greetings,
After a lot of trial and error, I came across a solution that seems to work very well. The problem was that I couldn't receive IR correctly while manipulating WS2812b LEDs in a fast (0 - 80 interval) timer.

Solution: I moved the IR sensor wire to pin 2, because pin 2 has interrupt capabilities. I wrote code that is nearly identical to the button code to listen for state changes when a key is pressed on the IR remote. Now I can use any fast timer interval and get perfect results and IR responsiveness. Everything else stayed the same, so it turned out to be a very simple solution.

I looked at the ESP8266 and know that it is a great chip at a great price, but I worry that there would be too much of a learning curve or idiosyncrasies. I'm 66 and prefer to keep it ultra simple now.

B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private IR_Pin As Pin
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    IR_Pin.Initialize(2, IR_Pin.MODE_INPUT_PULLUP)
    IR_Pin.AddListener("IR_Pin_StateChanged")
End Sub

Sub IR_Pin_StateChanged (State As Boolean)
    If State = True Then         ' rising
        ' put code here to receive IR and select option
        Log("True")
    Else                        ' falling
        Log("False")
    End If
    Delay(100)                  ' wait for 100 milliseconds
End Sub
 
Last edited:
Upvote 0
Top