-
Notifications
You must be signed in to change notification settings - Fork 832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Carrier frequency inaccurate #62
Comments
Hey. Thanks for that. I've noticed there can be delays that can cause sub-optimal frequency matching. Rather than make the 500 -> 465 change, which I admit is a great match for 32.5kHz, have you tried using enableIROut(38) for 38kHz? or 33 etc? |
I am not sure if you got me right. I did not try to match 32.5 kHz.
I mean, I guess just switching to 38kHz would have given me a smaller but working frequency. What I actually did after writing this bug report is putting in different delays and try to do a linear regression. I did not find any reasonable offset >1µs, though. The fix I suggested above gave decent values over the whole order of magnitude in the frequency. I find that strange too, but it was what I got on the oscilloscope. If I had gotten something reasonable there, I would have written a PR. I start to suspect that there is more going on than a delay. It is not the only strange timer related effect I have found on the ESP recently:
|
You are right. I was too quick and failed on the math. I calculated 465/500*35000 = 32550Hz. Instead of 500/465*35000 = 37634Hz. I'm not sure allowing for a 7% slew for everything (changing 500->465) is wise as it may stuff up other protocols and assumptions others have made. Using 38 for Panasonic limits the changes. |
Well, changing 500 to 465 leads to the ESP outputting 35kHz physically, that is: measured with an oscilloscope. If anybody relies on a function claiming to output 35kHz outputting something else than 35kHz, then I guess that is their fault, isn't it? People will CERTAINLY rely on enableIROut(35) outputting 35kHz, which it does not, at the moment, at least not on my ESP. |
can you add this nice uart hack? In my tests it worked very well. |
That's an interesting solution. I'm not sure I follow it completely, but does it work on any arbitrary PIN/GPIO that are capable of PWM, or just the combo D4/GPIO2? |
Since it is a hack for UART1, I am pretty sure it only works on GPIO2. |
it works only with the second serial line GPIO2/D4 and you have to add an 4k7 ohm pullup resistor between GPIO2 and 3,3V to avoid ESP boot issues. it is not pwm modulated, it is modulated by the serial baudrate and a serial character like 0xF0 (50% duty cycle). The baudrate rate must be 10 times the carrier frequency. you can also change the duty cycle if you send an other character like 0xFC 30% duty cycle or 0xFF 10% duty cycle. |
Yeah, that's what I figured it might be doing. Wasn't sure. As the current library works on any digital GPIO, I don't think coding a specific solution just for this particular case is the best course of action at this point. |
Apologies for the accidental close. Fat fingered/trackpad'ed. |
@kvoit Your ground truth data pointed me to an oops in the upstream library and ours. I checked multiple sources and yes, you are most correct. That protocol uses 36.7kHz. @AnalysIR FYI. Confirmation (via oscilloscope) of the Panasonic freq, and that it's for old devices, and, that some people still use that part of the library. |
Thanks for looking into this. I'll try to test this next weekend. |
I suggest to improve the timing by taking into account an extra delay due to the IRsend::mark() loop. #include <IRremoteESP8266.h> void loop() { The obtained periods T were: irsend.enableIROut(5); // T = 203 µs The correction could be performed by changing the calculation of the period return (1000000UL + hz/2) / hz - 3; |
@WStille Hey thanks for that. That looks great. I'll prep a change to do just that. Can I ask how you measured it? e.g. With an oscilloscope? If so, I assume the 3 µs was from leading edge of a pulse to the next pulse. If you don't mind me asking for extra data, what was the time for the actual pulse? i.e. time for the leading edge to the trailing edge? Also for the non-pulse portion of the period. Oh, I assume you were triggering on the GPIO signal, not the output of the LED, because some LEDs may introduce an appreciable lag. |
Apply an external offset for the period calculation so we allow for code/execution time in producing the software based PWM signal in mark(). For Issue #62
@crankyoldgit Thanks for your quick response. I first used a very simple oscilloscope (DSO138), but its performance was not sufficient to return (1000000UL + hz/2 - 34 * hz/10) / hz; |
@WStille Thanks for the detailed reply. I don't have an oscilloscope, so any brand/make/model is better than no oscilloscope IMHO. ;-) I like the idea of improving the rounding, but if we get within < 1µs with the simple -3 implementation, I'll be happy enough. Honestly, I'd prefer a more robust solution that automatically catered for instruction time (i.e. later modification) and if someone chooses to over clock the ESP. e.g. default is 80MHz, but 160MHz is an available option. Note to self: Add a calibration step to calculate the instruction time as part of the IRsend class setup. |
@crankyoldgit Self calibration would be really great! |
- First check in of a routine to calculate the execution delays in mark() and create an offset based on that for future mark() calls. Note: Requires a user to call IRsend.calibrate() before sending a signal. If not, defaults to '-3' as determined experimentally in Issue #62 WARNING: The calibrate() routine will generate a PWM pulse when called, thus it is left as an optional step for users who are interested.
@WStille Want to try this branch out for me? And do some calcs/measurements? All you should need to do is add
If you don't add the calibrate() call, it should default to the -3 usec offset you discussed. |
- First check in of a routine to calculate the execution delays in mark() and create an offset based on that for future mark() calls. Note: Requires a user to call IRsend.calibrate() before sending a signal. If not, defaults to '-3' as determined experimentally in Issue #62 WARNING: The calibrate() routine will generate a PWM pulse when called, thus it is left as an optional step for users who are interested.
Apply an external offset for the period calculation so we allow for code/execution time in producing the software based PWM signal in mark(). For Issue #62
- First check in of a routine to calculate the execution delays in mark() and create an offset based on that for future mark() calls. Note: Requires a user to call IRsend.calibrate() before sending a signal. If not, defaults to '-3' as determined experimentally in Issue #62 WARNING: The calibrate() routine will generate a PWM pulse when called, thus it is left as an optional step for users who are interested.
@crankyoldgit calibrate() seems to work fine! irsend.enableIROut(5); // T = 200 µs |
\ o / |
- Apply an external offset for the period calculation so we allow for code/execution time in producing the software based PWM signal in mark(). - Add a simple calibrate() method to IRsend(). - First check in of a routine to calculate the execution delays in mark() and create an offset based on that for future mark() calls. Note: Requires a user to call IRsend.calibrate() before sending a signal. If not, defaults to '-3' as determined experimentally in Issue #62 WARNING: The calibrate() routine will generate a PWM pulse when called, thus it is left as an optional step for users who are interested.
- Apply an external offset for the period calculation so we allow for code/execution time in producing the software based PWM signal in mark(). - Add a simple calibrate() method to IRsend(). - First check in of a routine to calculate the execution delays in mark() and create an offset based on that for future mark() calls. Note: Requires a user to call IRsend.calibrate() before sending a signal. If not, defaults to '-3' as determined experimentally in Issue #62 WARNING: The calibrate() routine will generate a PWM pulse when called, thus it is left as an optional step for users who are interested.
I think this issue is effectively closed now with that last commit to the v2.0 branch. |
First release candidate of v2.0 has been published. So I am going to mark this closed, as it includes a large number of timing improvements, some of which discussed here. |
I am just setting up an MQTT-to-IR bridge using a Wemos D1 Mini, but was unable to control our old Panasonic CRT TV. Hooking up the oscilloscope, I found out that the actual carrier frequency was about 32.5kHz instead of the configured 35kHz. The actual remote even uses 36.5kHz. This discrepancy was apparently enough so that the TV did not react at all.
As a quick and dirty fix, I changed the timing in IRsend::enableIROut(int khz) from 500/khz to 465/khz. This gave me a pretty accurate carrier frequency for 35 and the TV works, but I expect that the issue is rather related to additional delays, so an offset would be more appropriate to get accurate results on other frequencies.
The text was updated successfully, but these errors were encountered: