Re: Aw: IR-blasting 455 kHz with the new upstream kernel modules gpio-ir-tx and pwm-ir-tx

[email protected] Mon, 3 Jun 2019 20:51:56 +0200
Newsgroups gmane.comp.hardware.lirc
Message-ID <trinity-4bf5c50c-122e-4f72-9559-33e1ea475f08-1559587916568@msvc-mesg-gmx122>
Am 03.06.19 um 12:14 schrieb Bengt Martensson

> On 5/31/19 1:17 PM, [email protected] wrote:
>
> >> My appliance (a heater) stopped responding reliably to sent IR signals after upgrading the Raspberry Pi 3 to raspbian 4.19.42. I tried both new kernel modules: gpio-ir-tx and pwm-ir-tx (new kernel modules from upstream for software and hardware Pulse Width Modulation PWM). Very occasionally, maybe once in a hundred, the heater picks the IR signal up. Prior to the upgrade, the system worked nicely; as the IR signal has a high carrier frequency (455 kHz) I had used a lirc-rpi module that I had modified for hardware PWM. I measured the signal at the GPIO pin with a picoscope and noted that the carrier frequency was a bit too high when using pwm-ir-tx (around 475 - 480 kHz) and much too low when using gpio-ir-tx.
> >>
> ...
> > Investigating the above 455 kHz issue further:
> > - for testing purposes: lirc and the pwm-ir-tx module reliably blasts to a DVD player using the default carrier frequency (38 kHz).
> > - a hardcoded c program using pigpio (thus avoiding all of lirc and the pwm-ir-tx module) works nicely at 455 kHz (accuracy also confirmed using picoscope).
> >
> > I conclude that indeed pwm-ir-tx or its dependencies are not accurate enough for 455 kHz blasting, at least not for my heater (other appliances might be less picky). I will let the author of pwm-ir-tx know.
>
> Hallo Andreas,
>
> thank you very much for sharing your experiences. Some thoughts (sorry
> if these are not immediately useful):
>
> Some years ago (pretty many really), some thought (B&O obviously) that
> 455 kHz would be a big deal, since it would allow to transfer data over
> IR with a higher data rate. This appears to completely have died out.
> For example, Vishay has no demodulating IR receivers in their program
> since around 10 years. (See
> http://www.vishay.com/whatsnew/doc/ff_FastFacts_CounterfeitTSOP7000_Dec72018.pdf
> for the discontinued TSOP7000.) So I am a bit surprised that you have
> found such a thingy. Can you give some more details? Can you see if you
> can identify the IR receiver?
>
>  > I conclude that indeed pwm-ir-tx or its dependencies are not accurate
> enough for 455 kHz blasting, at least not for my heater (other
> appliances might be less picky). I will let the author of pwm-ir-tx know.
>
> Was it modulation frequency or the timing of the bursts that were not
> accurate?
>
> Generally speaking, I am a bit allergic to the idea of using a
> non-realtime general-purpose multi-user OS like Linux for generating the
> precise timing required to send IR signals. (This is more-or-less the
> Lirc concept, at least with simple hardware.) Using "intelligent"
> sending hardware (or you may prefer to call it a slave processor) is the
> obvious alternative. Maybe this:
> https://www.watterott.com/en/RPi-UNO-HAT would be an idea?? (Somewhere I
> have heard that an Arduino Uno/Nano (Atmel328p) CAN generate 455kHz in
> PWM, but I have not tried it myself.)
>
> Please keep us posted.
>
> Greetz,
>
> Bengt

Hi Bengt, all

The radiator is from Zehnder (https://www.zehnder-systems.ch/de/produkte-und-systeme/design-heizkoerper/zehnder-yucca), also the electrical heater (IRVAR 900 Heizpatrone) that is inserted into the radiator. The actual receiver within the IRVAR 900 is likely from a third party and used also in other devices; at least that was given as reason when Zehnder declined (years ago) to provide me IR details.

My workaround, a hard-coded c program (copied below), is very accurate (it loses only 0-3 microseconds for the entire IR signal and 455 kHz carrier by pwm) and reliably switches the heater. I am very happy with using the RPi3 for this; no need for an Arduino or so.

Issue with pwm-ir-tx: The frequency is a bit too high; Sean has meanwhile identified the error in the source code (drivers/pwm/pwm-bcm2835.c): a rounding error at low periods (= high frequencies) and submitted a patch. Only now, after your mail, I also checked the durations; and indeed, also inaccurate, notably the pulses that should be 30 microseconds. Thus, I do not know whether frequency or pulse/space lengths or both are responsible for the malfunctioning.

Best regards, Andreas

Appendix: my workaround using pigpio, not lirc

> #include <pigpio.h>
> #include <unistd.h>
> #include <stdio.h>
> #include <errno.h>
>
> // compile: gcc -Wall -pthread -o pigpio_pwm pigpio_pwm.c -lpigpio -lrt
>
>
> int main() {
>
> const unsigned int gpiopin = 18;
> const unsigned int pulse = 30;
> #define SpaceN 19
> const unsigned int zero = 650;
> const unsigned int one = 830;
> const unsigned int spaces[ SpaceN ] =
> {1000, // lead
> one, zero, one, one, one, zero, zero, zero, // constant IR signal prefix
> // one, one, one, one, one, one, one, one, // encoded key (KEY_8)
> zero, zero, zero, zero, one, one, zero, one, // encoded key (KEY_0)
> 470, // tail
> 100}; // reasonably >0 to measure success
>
> // *** startup
> // some calculations
> uint32_t durationCalc = SpaceN * pulse;
> for ( int s = 0; s < SpaceN; ++s ) durationCalc += spaces[s];
> // lower nice to get priority
> errno = 0;
> nice(-50);
> if (errno != 0) return -2; // failed to increase priority
> // initialize library
> int result = gpioInitialise();
> if ( result < 0 ) return -1; // pigpio initialisation failed
> // gpioTick must not be close to wrapping
> if ( gpioTick() > (0xFFFFFFFF - (2 * durationCalc)) ) usleep( 2 * durationCalc );
>
> // *** send the IR signal
> uint32_t startPulse;
> uint32_t startSpace;
> int s = 0;
> int notDone = (1==1);
> gpioHardwarePWM( gpiopin, 455000, 0 );
> // this is the section sensitive to timing
> uint32_t start = gpioTick();
> startPulse = gpioTick();
> while (notDone) {
> // a pulse
> gpioHardwarePWM( gpiopin, 455000, 500000 );
> startPulse += pulse;
> do startSpace = gpioTick();
> while (startPulse > startSpace);
> // a space (spaces are relatively long, thus we have time for housekeeping)
> gpioHardwarePWM( gpiopin, 455000, 0 );
> startSpace += spaces[s];
> ++s;
> notDone = (s < SpaceN);
> do startPulse = gpioTick();
> while (startSpace > startPulse);
> }
> uint32_t end = gpioTick();
>
> // *** cleanup
> // close library
> gpioTerminate();
> // measure success (as interrupts could have led to a prolonged pulse or space)
> uint32_t durationEff = end > start ? end - start : 0xFFFFFFFF - end + start;
> // checking for a delay >3 us off per period (better check for an absolute value?)
> int exitvalue = (durationEff > durationCalc + 3 * 2 * SpaceN) ? 2 : 0;
> // report
> fprintf(stderr, "Summary of sent IR signal\n");
> fprintf(stderr, "- start at %u us\n", start);
> fprintf(stderr, " end at %u us\n", end);
> fprintf(stderr, "- duration %u us (should be %u us; delta %u us)\n", durationEff, durationCalc, durationEff - durationCalc);
> fprintf(stderr, "- exit code %d (0 - success, >0 - should repeat, <0 - failure)\n", exitvalue);
>
> return exitvalue; }