raspberrypi / linux

Kernel source tree for Raspberry Pi-provided kernel builds. Issues unrelated to the linux kernel should be posted on the community forum at https://forums.raspberrypi.com/
Other
11.03k stars 4.95k forks source link

lirc_rpi is sensitive to interrupt latency #906

Closed P33M closed 7 years ago

P33M commented 9 years ago

With high network traffic or an IRQ latency fuzzer, lirc_rpi starts to generate errors in the decoded stream. The root cause is that IRQ latency between the edge-triggered GPIO interrupt going off and being able to read the timestamp at which it occurred causes incorrect decoding.

The minimum pulse width that needs to be correctly recorded is 562.5uS (NEC protocol "0" bit). Sony SIRC has a slightly longer duration at 600uS. RC-5 and RC-6 are slower.

There is no scope for moving GPIO interrupts to the FIQ pin. The ARMCTRL routing only allows for a single interrupt to be wired up to the FIQ pin at any one time.

The proposed solution is to move to a polled method. On Pi 1, the FIQ is triggered reliably from a 8kHz source clock (USB start-of-frame, which is almost never masked) giving 125uS sample points. This is sufficient resolution to decode GPIO edges into mark-space bitstreams from an IR receiver. On Pi 2, the option exists to use an (as yet undocumented) local timer to trigger a FIQ on a completely independent core in the same fashion.

The Pi 1 solution makes IR decoding dependent on the use of the USB FIQ, but nearly everyone uses that anyway so the dependency should be minimal.

In either case, the polling routine would read the GPIO level register for the pin(s) in question and do a delta comparison. If a delta is found, it would then read the system time counter (STC, monotonic increase at 1uS intervals) and write both the value and the delta to a ring-buffer-like interface and then stimulate an interrupt. On Pi 1, a DMA engine with a dummy read transfer can be used to provoke an interrupt. On Pi 2, the local mailboxes can be used.

The Pi 2 solution would be a lot more robust and include other use cases such as logic analysis with reasonable (kHz) sampling rates.

P33M commented 9 years ago

BCM2836 ARM-local peripherals are now documented (which includes the independent "USB timer"): https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/README.md

Ruffio commented 8 years ago

@P33M has your issue been resolved? If yes, then please close this issue.

mattgrogan commented 7 years ago

What's the status on this? I'm having a similar issue.

julianscheel commented 7 years ago

I'd also be interested in the USB FIQ based approach on RPi1. @P33M have you ever done some coding on this?

julianscheel commented 7 years ago

@P33M I just had a quick look at it. When you say the USB FIQ shall be used, I'm a bit unsure how to that. I don't think multiple interrupt handlers can be bound to the fiq and obviously dwc_otg is already claiming the fiq, so it would have to relinquish it while lirc_rpi would be using it. How would you intend to do it?

P33M commented 7 years ago

My original idea was to cheat. Using the USB's start-of-frame interrupt, you get a guaranteed interrupt every 125uS which could be used to perform other tasks, like sample GPIOs 0-26 and stuff the result in a ring buffer. This would allow for software decode of received IR codes. The LIRC driver would then become an odd platform device registered by the USB driver (bad).

My subsequent idea, possible on Pi2/3, was to use the new "magic" oscillator-driven timer that is muxed into the FIQ/IRQ line and accomplish the same result, but with the added bonus that IR would still work in device mode with USB disconnected.

With the subsequent release of the Zero, there's no guarantee of a USB SOF interrupt source (port disconnected or in device mode) and the "magic" timer doesn't exist. As such, back to the drawing board methinks.

julianscheel commented 7 years ago

@P33M I see, that would indeed by hackish... I am actually looking for something usable on a Raspberry Pi 1, as we have quite a lot of them in the wild and IR detection rate is quite bad, while video is decoded.

Why did you close the issue? It actually still exists :)

P33M commented 7 years ago

I opened the issue with a proposed workaround - but the workaround won't be of any benefit if you're on a bcm2835 product.

The same problem also exists with Dallas 1-wire, WS2812 "smart" LEDs, DHTnn-type sensors, or anything that waggles a GPIO in a time-sensitive fashion. It's an endemic problem until we work out a way of getting microsecond-accurate GPIO sampling.

One avenue of investigation would be to use the SMI peripheral as a 1-bit logic analyser - something I need to remember to poke Luke about, since he got it working last year or so.

julianscheel commented 7 years ago

@P33M Maybe open a new bug without the proposed solution, to not forget about this issue? :) @Wren6991 any cosiderations about using SMI for this? It seems there is no public documentation for the SMI.

Wren6991 commented 7 years ago

It sounds fairly doable. SMI can sample bus widths as small as 8 bits, and by futzing with the clock sources it should be possible to go as slow as a 125us sample period. The timing is very deterministic; you set up the timing parameters, and the peripheral follows them. There's a decent-sized fifo (hundreds of bytes IIRC) to take up the slack, so at modest data rates it's quite easy for a DMA channel to keep the SMI spinning at a constant rate.

The documentation is still in the state of "the code is the documentation" unfortunately. The header file contains about as much information as I could squeeze in without actually copying and pasting from proprietary docs. The SMI NAND driver is a pretty clean example of registering an SMI client driver and pushing some data through it.

You could certainly make the hardware do your bidding by doing something like

Which would reduce the interrupt frequency by a factor of thousands. However, this wouldn't fit well on top of the existing SMI driver. The code already does most of these things, it should be possible to take the necessary parts from that driver.

P33M commented 7 years ago

Bonus feature request:

The SMI peripheral drives all its data bus pins as input or output depending on which sort of cycle is being performed - read=input, write=output. If you could use the runtime pinmux reconfiguration API to selectively mask pins that are not being actively used in the current transfer as inputs with a default pull state, you could connect arbitrary numbers of devices (n<=16) with arbitrary 1-wire communication protocols to the SMI pins.

I'm thinking of a use case where an IR receiver coexists happily with DHT22/1-wire device/whatever connected to separate data pins on the SMI bus - with data cycles implemented via a transfer queue that sets both the pinmux and timing on a per-transaction basis. It's an extension of the notional addressing that SMI already has, but for dumb devices that would otherwise require costly bitbashing.

Wren6991 commented 7 years ago

That's a great idea! Bagsy /dev/multiwire.

Only problem I see is that we are waiting for asynchronous events on some of these lines (e.g. LIRC) and we lose the ability to capture that when we are outputting. For the more common case (master-slave) that would be a great use of the peripheral.

Edit: also a great WS2812 controller

julianscheel commented 7 years ago

@Wren6991 Thanks for the insights. Unfortunately, I'm not having enough spare time right now to take care of it, nor do we have a commercial need right now (we got rid of the IR receiver in that project). So it might be a while before I would dive into it, except someone else has a major need for it and wants to sponsor the work :)

euphoria360 commented 6 years ago

I'm having the same issue too, and it's actually driving me crazy. The GPIO IR receivers are very popular in OS'es like LibreElec and OSMC which make RPi like a media Hub. Any update on this?

yaqwsx commented 6 years ago

I have the same issue on OSMC. I use IR receiver connected through GPIO. When there is a large traffic on USB, IR remote becomes unresponsive.

Is there any progress or at least workaround? Are there other possibilities to connect IR receiver to RPi to get around this issue?

horchi commented 6 years ago

Same here :(

pelwell commented 6 years ago

lirc_rpi is deprecated now. Have you tried gpio-ir instead? There is some discussion of it on this thread: https://www.raspberrypi.org/forums/viewtopic.php?t=205490

euphoria360 commented 6 years ago

I wonder why this doesn't get attention. Lot's of RPi buyers use it as Media Center and IR remotes are indistinguishable part of that.

horchi commented 6 years ago

lirc_rpi is deprecated now. Have you tried gpio-ir instead? There is some discussion of it on this thread: https://www.raspberrypi.org/forums/viewtopic.php?t=205490

should this make sense in relation tom the interrupt problem? I tested gpio-ir right now but now change. Still the problem that every time I start using the signal of an DVB-S2 USB stick gpio lirc stop working.

pelwell commented 6 years ago

The point is that you have zero chance of getting LIRC improvements, whereas a request for an optimised gpio-ir has at least a slim chance of getting some attention provided you create a new issue for it.

HiassofT commented 6 years ago

Getting rid of the interrupt latency is very tricky. As a lot of USB DVB receivers have an integrated IR receiver there's an easy workaround though, just that IR receiver instead of a GPIO IR receiver.

horchi commented 6 years ago

yes my USB DVB receivers have an integrated IR too but I don't like to use it because it is not in the visible IR range since it looks ugly with all the wires ;) In meantime I bought a FLIRC, but since it simulate 'only' a keyboard I can control the VDR with it, but not control additional script like irexec can do. Not easy this days ;)

HiassofT commented 6 years ago

Another option is to buy an MCE USB receiver, like the HP branded ones which you can get on ebay for 10-15 USD/EUR. They are very well supported in linux.