Possible conflict between IRremote and fastspi libraries

Am trying to use both libraries to control a WS2801 based LED display. The latest version of fastspi works with WS2801's on an UNO running 1.0.1. I also have IRremote running as well.

The challenge is that when I try and integrate them, IRremote only returns '0' values. If I comment out FastSPI_LED.show() on line 31 below, IRremote works as expected. Not sure how to approach the authors of these libraries. Will get to debugging, but their code is pretty much over my head at this point. Am open to suggestions.

Here's some sample code using Arduino 1.0.1 and the lastest available versions of their libraries:

#include <FastSPI_LED.h>                           // The clock is on pin 13, while the data is on pin 11
#include <IRremote.h>

int RECV_PIN = 7;                                    // A nice out of the way pin to connect the receiver to
IRrecv irrecv(RECV_PIN);                           // Initialize which pin we are receiving on
decode_results results;                              // Define the variable for storing 'results'

#define NUM_LEDS 32

struct CRGB { unsigned char b; unsigned char g; unsigned char r; };

struct CRGB *leds;

void setup()
{
  
  Serial.begin(9600);
  irrecv.enableIRIn();                             // Start the receiver
  
  FastSPI_LED.setLeds(NUM_LEDS);
  FastSPI_LED.setChipset(CFastSPI_LED::SPI_WS2801);
  FastSPI_LED.setDataRate(2);
  FastSPI_LED.init();
  FastSPI_LED.start();

  leds = (struct CRGB*)FastSPI_LED.getRGBData(); 
}

void loop() { 
  keyb();                                          
  FastSPI_LED.show();                                // if I comment this line out, the IR works as expected -------------------------------------
} // end of loop()


void keyb(void) {
 if (irrecv.decode(&results)) {                   // If there is a result . . 
    Serial.println(results.value, HEX);           // Print the value
    irrecv.resume();				  // Receive the next value
  }
} // end of keyb()

Update: Have already enabled debug in the IRremote libraries and I suspect the problem has to do with interrupt conflicts, so I'm going to try and wrap a few things with interrupts(); and noInterrupts();.

I cannot see any direct problem in this code because basically this code is executed:

    setDirty();
    if(FastSPI_LED.m_eChip == CFastSPI_LED::SPI_WS2801)
    {
        cli();
        register byte *p = m_pData;
        register byte *e = m_pDataEnd;

        // If we haven't run through yet - nothing has primed the SPI bus,
        // and the first SPI_B will block.  
        if(!run) { 
          run = 1;
          SPI_A(*p++);
          SPI_B; SPI_A(*p++);
          SPI_B; SPI_A(*p++);
        }
        while(p != e) { 
          SPI_B; SPI_A(*p++);
          SPI_B; SPI_A(*p++);
          SPI_B; SPI_A(*p++);
        }
        m_nDirty = 0;
        sei();
    }

where

#define SPI_A(data) SPDR=data;
#define SPI_B while(!(SPSR & (1<<SPIF)));

This leads me to the assumption that the problem is the relatively long time the interrupts are disabled. The IRremote code is quite time critical so this probably causes too much delay resulting in a faulty detection. Do you need the fastSPI_LED speed? Does the standard ws2801 library's speed not fulfill your needs?

pylon asks: Does the standard ws2801 library's speed not fulfill your needs?

A: The Sparkfun code I was using fills my needs adequately, however the fastSPI library is light years faster, thus giving me more flexibility in developing cool visual displays.

Thanks for the response!

Update 1: Hmmm, disabling that cli(); command in the library seems to have a good effect. Time for more research. . .

Update 2: Oooh, it's working in my updated code so far, but a lot more testing is required.

OMG, the FastSPI library is blazing fast, as seen in the last 5 seconds:

I just found the same conflict, though my project uses tm1809. If I disable FastSPI show() (or even just the cli() call in show()), IR works as expected. But disabling cli() breaks the LED output (result: just some glitchy stuff on the first few LEDs of the strip) Is disabling the cli() call all you needed to do to fix it?

One thing I tried was throttling the FastSPI show() function to 5hz or so. Then some of my remote commands were detected correctly. But it would still lose like half of the button presses :stuck_out_tongue: Not to mention that throttling show() that hard won't work for the project.

IRRemote and FastSPI both seem like the most well supported libs of their respective classes, it would be great to shed some more light on how to integrate them. Having IR control of custom LED arrays seems like a common use case. Thanks for any suggestions!

Yeah - while there's SPI in the name of the library, and while, for most chipsets (tm1809 and ucs1903 excluded) it uses the SPI pins/hardware SPI support on the arduino, most of those led chipsets are not good SPI 'citizens'. They don't support a channel select line so they always read/react to things that come over the SPI lines. It's irritating, and to work around this i'm working on adding support for using pins other than the SPI pins, it'll be a little bit slower (but hopefully not by much!) than the native spi work, and will let you work around these things. I don't know when i'll have that finished yet, though.

Unfortunately - on the tm1809 and the ucs1903 side, because the timings there are so tight, interrupts -have- to be disabled. Those chipsets have signal requirements that expect 1 bit of data every 2 (or for the ucs1903, 2.5) microseconds - no negotiation, and if the line is silent for, 24 microseconds all the chips reset back to a listening state.

Daniel,
Do you think there is a way to write it so that is could:

cli() <- disable all interrupts
secret sauce <- enable the interrupt for the IRRemote. If the user interrupts, let's not worry about FAST_SPI and let's just figure out what the user is trying to say. Then we can go back to FAST_SPI
do the magic for the TM1809
sei() <- enable all interrupts

If the user is trying to input via the remote, it's not important what FAST_SPI is trying to push to the LEDs, it's important to capture that information. Then after we know what button the user has pressed, we can make some change to some global variable, and then go back to running FAST_SPI.

Sorry I don't really know much about why this can/can't work. :slight_smile: I feel like there must be a way to ignore all interrupts except for when the IRRemote wants to do something, and at those rare instances it's acceptable for FAST_SPI to momentarily 'fail'

Please tell me what I'm totally wrong about. :smiley:

You cannot use cli() to disable interrupts and then selectively enable some of them again. But you can disable these interrupts, that are annoying you most. On the Arduino platform this is probably the timer 0 interrupt (responsible for the internal time-keeping as millis() or micros()). If you disable the timer 0 interrupt you still have other interrupt sources, the serial (USART) interface for example but that's the responsibility of the programmer then.

Then you have to rewrite IRremote because the current implementation uses timer 2 to interrupt the processor every 0.5us. Change it that way so that the external interrupt is used (on the UNO only pin 2 and 3 are then available as IR receiver pins) and one of the timers (preferably a 16bit) is used only for measuring the time between two edges. I guess this results in a completely new library.

Thanks for the ideas, pylon.

Pylon would you happen to know 'how' to disable timer0? :slight_smile: I'm googling and googling but....

To disable timer 0 overflow interrupt:

cbi(TIMSK0, TOIE0);

or disable all timer 0 interrupts:

TIMSK0 = 0;

Wow, ok, thanks for your reply. :slight_smile:

Hey all,

I know this thread is way old, but in case anyone else bumps in to this problem and doesn't want to lose performance on the LEDs or drop remote commands , I came up with a solution using a pair of connected arduinos.

More details here: http://industriumvita.com/arduino-ir-remote-controled-ws2811-addressable-leds/

Hope it helps someone!

After struggling a whole evening to add IR to a existing FastLed project (wtf are the readings randomly!?) i start search for troubles with FastLed and IR on Arduino. After a couple forum threats i was frustrated, close to give up. While i did a coffee break i got the idea using 2 arduino's but first thoughts: 'Ups that unprofessional… using 2 controllers… using IO pins for communication…'

Then i found your post with the TX/RX connection and the buffer! Really great!!!! Works here with a Uno and a Mini Pro 5V

thx to Mishaux!

To use FastLED 3.1 for WS2811 strips while running animations with IRLremote in PinChangeInterrupt mode on an Uno, I edited FastLED to ignore Timer0 Interrupts by replacing "cli;" with "TIMSK0 = 0;" and "sei;" with "TIMSK0 = 1;" in clockless_trinket.h I also set "#define FASTLED_ALLOW_INTERRUPTS 1"

This means that instead of ignoring all interrupts, FastLED will just ignore timer0 interrupts. IR signals will still interrupt the strips. The strip will flicker slightly during IR events but it ensures that nothing will be missed.

In my case this was an acceptable trade off.

Swap_File:
To use FastLED 3.1 for WS2811 strips while running animations with IRLremote in PinChangeInterrupt mode on an Uno, I edited FastLED to ignore Timer0 Interrupts by replacing "cli;" with "TIMSK0 = 0;" and "sei;" with "TIMSK0 = 1;" in clockless_trinket.h I also set "#define FASTLED_ALLOW_INTERRUPTS 1"

This means that instead of ignoring all interrupts, FastLED will just ignore timer0 interrupts. IR signals will still interrupt the strips. The strip will flicker slightly during IR events but it ensures that nothing will be missed.

In my case this was an acceptable trade off.

I tried this solution but for some reason, and after LOTs of different tries i still can't make it work. So let me go over the steps to see if i missed something:

  • edited clockless_trinket.h and replaced the "cli();" with "TIMSK0 = 0;" and "sei();" with "TIMSK0 = 1;"
  • edited fastled_config.h and uncommented "#define FASTLED_ALLOW_INTERRUPTS 1"
  • used IRL Remote instead of IR Remote library, based on the PinChangeInterrupt example:
void setup() {

  // power-up safety delay
  delay( 1000 ); 
  
  Serial.begin(9600);
  
  // IR Receiver setup
  attachPCINT(digitalPinToPCINT(IR_RECEIVE_PIN), IRLinterrupt<IR_NEC>, CHANGE);

  // Neopixel setup
  FastLED.addLeds<NEOPIXEL, NEOP_DATA_PIN_CENTER>(ledsCenter, NUM_LEDS_CENTER);
  FastLED.addLeds<NEOPIXEL, NEOP_DATA_PIN_EDGE>(ledsEdge, NUM_LEDS_EDGE);
  FastLED.setBrightness(50);
  FastLED.show();

}

void loop() {

  receiveIrCommand();

  FastLED.show();
}

void receiveIrCommand(){
  
  // temporary disable interrupts and print newest input
  uint8_t oldSREG = SREG;
  cli();
  
  if (IRProtocol) {
    // print as much as you want in this function
    // see readme to terminate what number is for each protocol

    IRCommandToAction (IRCommand);
        
    // reset variable to not read the same value twice
    IRProtocol = 0;
  }
  SREG = oldSREG;
}

I've tried positioning the FastLED.show(); in several places, before the procedure do read the IR code, somewhere in between, after it, etc. Doesn't matter where i put it, when i uncomment FastLED.show(); i can no longer read IR codes, and i do see some flicker in the leds when i press the remote buttons.

So Please can you tell me where i am failing? this is super frustrating since i want to have a compact and simple solution to control the lets with a remote, so i don't want a second arduino just for the IR interaction, and i already bought lots of Neopixels, it would be a waste to now have to use Dotstar. Also, i can make it work if i do a .show() only when a button is pressed, however if i can to create LED animations i need a constant update, not just when i press the button

I struggled with this same problem for the past few days. The best solution I came up with was to only update the LEDs when not handling an IR command. That way, when the IR code is actually waiting for subsequent bits, it gets all the CPU time it needs with no interruption. In practice, I don't see any LED flicker when processing the IR code, even when spamming it, but, technically, it probably is hurting the framerate.

Here's the simplified code:

void loop()
{
  if ( irReceiver.decode( &irResults ) )
  {
    // Handle a received IR command...
  }
  
  if ( irReceiver.isIdle() )
  {
    // Update LEDs here...
    
    FastLED.show();
  }

  delay( 16 ); // ~60 fps
}

Hope it helps some people!