Cash Bounty for IRRemote IRrecv Port! :) [SOLVED]

It works great! :smile: Thanks @mdoan7 and @peekay123 for getting this working! And thanks @Jerware for putting up the cash and getting someone to port it! I would be willing to chip in on the bounty, just let me know.

2 Likes

I may have spoken too soonā€¦ It works great while driving APA102 LEDs, but not with WS28xx. I get a different IR code every time I press the same button on the remote.

Iā€™m using the FastLED library, which disables interrupts while writing to WS28xx LEDs. I know trying to use FastLED and IRremote isnā€™t possible on slower AVR (Arduino) boards, but works fine on faster ARM boards, like the Teensy 3.1. Hereā€™s more information on the topic: https://github.com/FastLED/FastLED/wiki/Interrupt-problems

"Writing out WS2812 data requires some pretty tight timing. Tight enough that FastLED disables interrupts while it is writing out led data. This means that while the led data is being written out, any interrupts that happen will be delayed until all the led data is written out. How long will that be for? Depends on the number of leds. WS2812 led data takes 30Āµs per pixel. If you have 100 pixels, then that means interrupts will be disabled for 3000Āµs, or 3ms."

And, further down:

"As long as those interrupt handlers don't take more than 5Āµs to run, everything will be happy. As long as your interrupt handlers don't need to run more frequently than once every 30Āµs, that is."

I assume this is the problem Iā€™m experiencing. Any thoughts/suggestions?

@jasoncoon, the current FastLED library uses bit-banging for driving LEDs so as long as interrupts are disabled, the 50us IR receive timer interrupt risks being affected.

One option is to use the Neopixel library which doesnā€™t seem to block interrupts. However, I am not sure how the IR receive timer interrupt will affect its operation. Another, is a DMA-based APA102 library from @Pixelmatix which works with FastLED. Youā€™ll need to locally compile to get it working. :grinning:

Thanks for the response and suggestions, @peekay123! Itā€™s interesting that the FastLED + IRremote combo works fine on the Teensy, which has a similar ARM processor as the Photon.

Iā€™ve been too spoiled by FastLED to go back to the Neopixel library. :smile:

APA102 work fine on the Photon as-is, with FastLED and the new port of IRremote, because interrupts are not disabled for SPI-based LED chipsets.

@jasoncoon, donā€™t forget that the photon is running FreeRTOS, doing wifi and cloud, etc. The teensy is doing none of that. :wink:

@peekay123 Good point! Iā€™lI try it with an ESP8266 for a more fair comparison. :slight_smile:

1 Like

@peekay123 Happy to report that everything works fine on an ESP8266. Running 100 8mm WS2811 RGB LEDs with FastLED, a web site (in SPIFFS), REST services, and IR remote: https://github.com/jasoncoon/esp8266-fastled-webserver

Thatā€™s using this ESP8266 port of the IRremote library, Iā€™ll try diffing it with @mdoan7ā€™s port the next time I get a chance.

2 Likes

which pin is this referring to on the Photon?

int RECV_PIN = 11;

I think it maps to A1ā€¦ but you can change that to whatever pin you need (be careful of the 3.3v only pins).

@mdoan7
I have attempted to compile the demo app, IRrecvDemo.ino, from https://github.com/babean/IRRemote on the web IDE and it presents some issues. I am probably doing something silly. I presume this is the latest version of the IRremote fork.

any ideas?

the Web IDE (0.5.1) compiler output follows:

SparkIntervalTimer.cpp: In member function 'void IntervalTimer::interrupt_SIT(action)':
SparkIntervalTimer.cpp:360:15: warning: variable 'TIMx' set but not used [-Wunused-but-set-variable]
  TIM_TypeDef* TIMx;
               ^
SparkIntervalTimer.cpp: In member function 'void IntervalTimer::start_SIT(intPeriod, bool)':
SparkIntervalTimer.cpp:276:23: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIM_Cmd(TIMx, ENABLE);
                       ^
SparkIntervalTimer.cpp: In member function 'void IntervalTimer::stop_SIT()':
SparkIntervalTimer.cpp:346:18: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIM_DeInit(TIMx);
                  ^
SparkIntervalTimer.cpp: In member function 'void IntervalTimer::resetPeriod_SIT(intPeriod, bool)':
SparkIntervalTimer.cpp:476:23: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIMx->PSC = prescaler;
                       ^
SparkIntervalTimer/SparkIntervalTimer.cpp: In member function 'void IntervalTimer::interrupt_SIT(action)':
SparkIntervalTimer/SparkIntervalTimer.cpp:360:15: warning: variable 'TIMx' set but not used [-Wunused-but-set-variable]
  TIM_TypeDef* TIMx;
               ^
SparkIntervalTimer/SparkIntervalTimer.cpp: In member function 'void IntervalTimer::start_SIT(intPeriod, bool)':
SparkIntervalTimer/SparkIntervalTimer.cpp:276:23: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIM_Cmd(TIMx, ENABLE);
                       ^
SparkIntervalTimer/SparkIntervalTimer.cpp: In member function 'void IntervalTimer::stop_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:346:18: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIM_DeInit(TIMx);
                  ^
SparkIntervalTimer/SparkIntervalTimer.cpp: In member function 'void IntervalTimer::resetPeriod_SIT(intPeriod, bool)':
SparkIntervalTimer/SparkIntervalTimer.cpp:476:23: warning: 'TIMx' may be used uninitialized in this function [-Wmaybe-uninitialized]
  TIMx->PSC = prescaler;
                       ^
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::isAllocated_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:66: multiple definition of `Wiring_TIM3_Interrupt_Handler_override'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:66: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `__static_initialization_and_destruction_0':
SparkIntervalTimer/SparkIntervalTimer.cpp:75: multiple definition of `Wiring_TIM4_Interrupt_Handler_override'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:75: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::stop_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:84: multiple definition of `Wiring_TIM5_Interrupt_Handler_override'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:84: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `Wiring_TIM6_Interrupt_Handler_override':
SparkIntervalTimer/SparkIntervalTimer.cpp:93: multiple definition of `Wiring_TIM6_Interrupt_Handler_override'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:93: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `Wiring_TIM7_Interrupt_Handler_override':
SparkIntervalTimer/SparkIntervalTimer.cpp:102: multiple definition of `Wiring_TIM7_Interrupt_Handler_override'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:102: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::start_SIT(unsigned long, bool)':
SparkIntervalTimer/SparkIntervalTimer.cpp:190: multiple definition of `IntervalTimer::start_SIT(unsigned long, bool)'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:190: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::allocate_SIT(unsigned long, bool, TIMid)':
SparkIntervalTimer/SparkIntervalTimer.cpp:160: multiple definition of `IntervalTimer::allocate_SIT(unsigned long, bool, TIMid)'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:160: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::stop_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:294: multiple definition of `IntervalTimer::stop_SIT()'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:294: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::beginCycles(void (*)(), unsigned long, bool, TIMid)':
SparkIntervalTimer/SparkIntervalTimer.cpp:124: multiple definition of `IntervalTimer::beginCycles(void (*)(), unsigned long, bool, TIMid)'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:124: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::end()':
SparkIntervalTimer/SparkIntervalTimer.cpp:285: multiple definition of `IntervalTimer::end()'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:285: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::interrupt_SIT(action)':
SparkIntervalTimer/SparkIntervalTimer.cpp:358: multiple definition of `IntervalTimer::interrupt_SIT(action)'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:358: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::resetPeriod_SIT(unsigned long, bool)':
SparkIntervalTimer/SparkIntervalTimer.cpp:426: multiple definition of `IntervalTimer::resetPeriod_SIT(unsigned long, bool)'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:426: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::isAllocated_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:487: multiple definition of `IntervalTimer::isAllocated_SIT()'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:487: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::isAllocated_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:66: multiple definition of `IntervalTimer::SIT_CALLBACK'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:66: first defined here
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o): In function `IntervalTimer::isAllocated_SIT()':
SparkIntervalTimer/SparkIntervalTimer.cpp:66: multiple definition of `IntervalTimer::SIT_used'
../../../build/target/user/platform-6/libuser.a(SparkIntervalTimer.o):SparkIntervalTimer.cpp:66: first defined here
collect2: error: ld returned 1 exit status
make: *** [5e1ea5d6d9e745813ae9346b187465c1907f7400bba6a6f38c2ab39b68a4.elf] Error 1

    Error: Could not compile. Please review your code.

The repo assumes you are compiling locally (i.e., everything flat in one dir). If you import these into the web IDEā€¦ you might want to make sure all the library includes are referencing the correct lib directories.

2 Likes

@mdoan7 - thank you very much for this! Saved me a lot of time (for attempting a) porting this library for use in my first Photon project!

Both send and receive are working just fine for me from your repo. I would love to see you publish this as a library for everyone to quickly import.

This looks as if there were two includes for SparkIntervalTimer.h and that header doesnā€™t protect against multiple inclusion.

It is discouraged that one library brings its own copy of a third party library for exactly that reason!

1 Like

@mdoan7 @ScruffR

Thanks for the tipsā€¦

I replaced the libary include to
#include "SparkIntervalTimer/SparkIntervalTimer.h"
in IRRremote.cpp

and removed the copies of SparkIntervalTimer.h & SparkIntervacppTimer.h included with the github files and it compiled OK on the WEB IDE

Now on to do some actual testing

tnx

2 Likes

Coolā€¦

Testing worked out fine.

I have verified IR receiving & sending (including carrier frequency) work with this version.

I used our A.IR shield Photon for the tests - just had to change the rx & tx pins to match the shield.
[In our case I used 2 (aka D2) for IR receive & TX for IR transmit]

Only other issue noticed was that the Web IDE complained that IRremoteInt.h was not used. This occured when flashing, but not when verifying. I just went ahead and flashed and it was fine.

More details on our A.IR Shield Photon click here

Tips for anyone maintaining this library/fork in future:

  • The current version of IRremote has more features than the fork used here and gets regular support
  • The latest version has more protocols supported
  • In the mark function it is advisable to turn off the carrier before exit (otherwise the space function must always be called to finish a signal)
  • Most of the original examples provided with the library should work seemlessly with this fork.

For reference, the latest/primary IRremote (does not support photon at this point) is available here:

Excuse me, I got the same ā€œmultiple definitionā€ errors as you, I tried your suggestions not really understanding how they worked and had no success.

I donā€™t understand why you need to use ā€˜#include ā€œSparkIntervalTimer/SparkIntervalTimer.hā€ā€™ ? Why canā€™t you just include ā€œSparkIntervalTimer.hā€ ?
I am in the web IDE and added each .h and .cpp file and pasted all the code in. All the files seem to be in the same folder - there are no folders in the web IDE.
I have tried #include ā€œSparkIntervalTimer/SparkIntervalTimer.hā€ but the compiler said ā€œno such directoryā€.

Also, what do you mean by ā€œand removed the copies of SparkIntervalTimer.h & SparkIntervacppTimer.h included with the github filesā€? Surely these files are needed.

Thanks

That is exactly the reason for your "multiple definition" errors.
I suspect you've also got that library or another lib that comes with its own copy of it (which is bad style) imported and that will conflict with your own copy.

That's also the explanation for the path in the include statement.
When you import a lib, it will live in its own subdirectory and hence you need to provide the location.
Files in the editors file tabs however live in the same directory as your .ino file and hence don't require a path specification.

Nope, they are not needed in the repo, since that lib should be imported - bringing your own copy of 3rd party libs is bad style and will pose untreatable issues if everybody would do that.

OK thanks ScruffR.

So if I understand correctly, the SparkIntervalTimer library is added by clicking the Libraries button on the left hand side and searching for it in the list of Community Libraries.
But the IRremote and IRremoteInt libraries, since they are not in the list of Community Libraries, they must be added by copying and pasting?
Is that right?
Thanks

Does not work for me. Not sure what I did wrong this time.
Hereā€™s what I did:

Went to https://github.com/babean/IRRemote

used code from IRrecvDemo for my new app.

Included SparkIntervalTimer by searching for it in the Web IDE.

Added a file to project called IRremote.h and pasted code in.
Line #include ā€œIRremote.hā€ was automatically added to project into file.
Saved file
Added the code for IRremote.cpp
Saved file

Added a new file called IRRemoteInt
Pasted the .h code
Saved file
Pasted the .cpp code
Saved file

Went back to .ino file and checked to see include statements as follows:

// This #include statement was automatically added by the Particle IDE. 
#include "IRRemoteInt.h" 
// This #include statement was automatically added by the Particle IDE. 
#include "IRRemote.h" 
// This #include statement was automatically added by the Particle IDE. 
#include "SparkIntervalTimer/SparkIntervalTimer.h"

Verified code
Error

IRRemote.cpp:21:34: fatal error: SparkIntervalTimer.h: No such file or directory
   #include "SparkIntervalTimer.h"

So I went to the line 21 in IRRemote.cpp and replaced it with

#include "SparkIntervalTimer/SparkIntervalTimer.h"

Verified code again

IRRemote.cpp:28:22: fatal error: IRremote.h: No such file or directory
 #include "IRremote.h"

Figured it was the capital letter I had clumsily used in IRRemote instead of IRremote. Fixed all of these occurrences.

Verified code again

IRremoteInt.cpp:21:34: fatal error: SparkIntervalTimer.h: No such file or directory
   #include "SparkIntervalTimer.h"

Replaced line 21 with

#include "SparkIntervalTimer/SparkIntervalTimer.hā€

Verified code

And got piles of errors:

In file included from ir.cpp:2:0:
IRremoteInt.h: In function 'int MATCH(int, int)':
IRremoteInt.h:183:41: error: 'USECPERTICK' was not declared in this scope
 #define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
                                         ^
IRremoteInt.h:187:58: note: in expansion of macro 'TICKS_LOW'
 int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
                                                          ^
IRremoteInt.h: In function 'int MATCH_MARK(int, int)':
IRremoteInt.h:188:96: error: 'MARK_EXCESS' was not declared in this scope
 int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us + MARK_EXCESS));}
                                                                                                ^
IRremoteInt.h: In function 'int MATCH_SPACE(int, int)':
IRremoteInt.h:189:97: error: 'MARK_EXCESS' was not declared in this scope
 int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH(measured_ticks, (desired_us - MARK_EXCESS));}
                                                                                                 ^
IRremoteInt.h: At global scope:
IRremoteInt.h:205:23: error: 'RAWBUF' was not declared in this scope
   unsigned int rawbuf[RAWBUF]; // raw data
                     ^

Seems like a scope problem but why?

There is no .cpp file matching that.
When copying the files from github and placing them in their respectively named new tabs, followed by adding the intervaltimer library and changing the includes, the example compiles for me. You might want to redo the process to make sure you haven't forgotten/messed up a step :slight_smile: