2008-10-08 03:44:04

by [email protected]

[permalink] [raw]
Subject: Toggling GPIO at 38Khz

I'm working on getring the LIRC IR subsystem integrated into the
kernel. One common IR hardware implementation is based on standard
serial ports. It uses the serial port's DCD and DTR as GPIO pins.
This common IR hardware does not have a transmit modulator and is
modulating the IR signal in software. Luckily is has hardware
demodulation.

There are four common IR frequencies - 36Khz, 38Khz, 40Khz, 56Khz. I
need to create these frequencies in software. Data is then transmitted
as 400-600us burst of these frequencies. Around 10-30 clock pulses.

So how do I reliably generate 38Khz without destroying latency in the
system? I also don't want to measure the speed of the code I'm
executing - same code has to run on 90Mhz ARM and 3Ghz Core2. If a do
a loop with nanosleep() I need to know how fast my code is to subtract
it's execution time form the sleep time. The existing LIRC code works
this way and measures it's timing loop.

hrtimers look promising, but hrtimers doesn't have a periodic API. Is
there a technique for creating periodic timing that doesn't accumulate
error caused by rescheduling the timers? If I need to send 30 pulses
of 38Khz, it is more important that the total time be (1/38000)*30 =
0.7894ms than it is for each pulse to be generated at exactly 26.3us
intervals.

Are there other techniques for generating pulse trains in the 36-56Khz
range on a simple GPIO pin? Anyone have some sample code?

--
Jon Smirl
[email protected]


2008-10-08 06:40:44

by Eric Miao

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

On Wed, Oct 8, 2008 at 11:43 AM, Jon Smirl <[email protected]> wrote:
> I'm working on getring the LIRC IR subsystem integrated into the
> kernel. One common IR hardware implementation is based on standard
> serial ports. It uses the serial port's DCD and DTR as GPIO pins.
> This common IR hardware does not have a transmit modulator and is
> modulating the IR signal in software. Luckily is has hardware
> demodulation.
>
> There are four common IR frequencies - 36Khz, 38Khz, 40Khz, 56Khz. I
> need to create these frequencies in software. Data is then transmitted
> as 400-600us burst of these frequencies. Around 10-30 clock pulses.
>
> So how do I reliably generate 38Khz without destroying latency in the
> system? I also don't want to measure the speed of the code I'm
> executing - same code has to run on 90Mhz ARM and 3Ghz Core2. If a do
> a loop with nanosleep() I need to know how fast my code is to subtract
> it's execution time form the sleep time. The existing LIRC code works
> this way and measures it's timing loop.
>

This isn't easy, 38KHz is quite a high frequency, I'd prefer to
use an interrupt or fiq based on a accurate clock event source,
but that will have impact on the system anyway.

> hrtimers look promising, but hrtimers doesn't have a periodic API. Is
> there a technique for creating periodic timing that doesn't accumulate
> error caused by rescheduling the timers? If I need to send 30 pulses
> of 38Khz, it is more important that the total time be (1/38000)*30 =
> 0.7894ms than it is for each pulse to be generated at exactly 26.3us
> intervals.
>

Make sure your clock source is accurate enough to generate
this interval.

> Are there other techniques for generating pulse trains in the 36-56Khz
> range on a simple GPIO pin? Anyone have some sample code?
>

With a PWM possibly.

> --
> Jon Smirl
> [email protected]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>



--
Cheers
- eric

2008-10-08 12:04:40

by Bodo Eggert

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Jon Smirl <[email protected]> wrote:

> I'm working on getring the LIRC IR subsystem integrated into the
> kernel. One common IR hardware implementation is based on standard
> serial ports. It uses the serial port's DCD and DTR as GPIO pins.
> This common IR hardware does not have a transmit modulator and is
> modulating the IR signal in software. Luckily is has hardware
> demodulation.
>
> There are four common IR frequencies - 36Khz, 38Khz, 40Khz, 56Khz. I
> need to create these frequencies in software. Data is then transmitted
> as 400-600us burst of these frequencies. Around 10-30 clock pulses.
[...]

The ALSA PC-Speaker sound driver might do something similar ...

2008-10-08 12:34:12

by Bill Gatliff

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Jon Smirl wrote:

>
> Are there other techniques for generating pulse trains in the 36-56Khz
> range on a simple GPIO pin?
>

Yes.

Use the GPIO pin to enable the output of an external circuit. Or, hope that the
GPIO pin in question is multiplexed with a timer/counter or PWM peripheral.

But somehow, I don't think either answer is what you were looking for. :)

36 KHz bit-banging is a reach for any processor running Linux, methinks. Maybe
you could launch an FIQ (assuming ARM) and then do the bit-bang as a burst in
there, so that you would have more control over the timing. But that kind of
code isn't going to play well with the rest of the kernel...

If the hardware design isn't set, you might want to consider using that GPIO
line as a quasi-SPI link to a small, AVR-type microcontroller that does the
bit-banging on your behalf. Long-term, that's going to be a more reliable and
flexible solution I think.


b.g.
--
Bill Gatliff
[email protected]

2008-10-08 13:06:42

by [email protected]

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

On Wed, Oct 8, 2008 at 8:01 AM, Bill Gatliff <[email protected]> wrote:
> Jon Smirl wrote:
>
>>
>> Are there other techniques for generating pulse trains in the 36-56Khz
>> range on a simple GPIO pin?
>>
>
> Yes.
>
> Use the GPIO pin to enable the output of an external circuit. Or, hope that the
> GPIO pin in question is multiplexed with a timer/counter or PWM peripheral.
>
> But somehow, I don't think either answer is what you were looking for. :)

The existing LIRC driver for a serial port is here:
http://lirc.cvs.sourceforge.net/viewvc/lirc/lirc/drivers/lirc_serial/lirc_serial.c?view=markup

An example of serial based hardware is here:
http://iguanaworks.net/product2.psp

These are external boards people buy to use with MythTV. They are most
commonly used on the x86, but the NSLU2 has been modified to use them
too.

The hardware can't be changed, people have bought thousands of these devices.

Many people cut up a serial cable and solder it themselves...
http://www.lirc.org/transmitters.html

The problems with these devices are obvious, I use a USB one for my
own system. It has a PIC chip in it with PWM out.


>
> 36 KHz bit-banging is a reach for any processor running Linux, methinks. Maybe
> you could launch an FIQ (assuming ARM) and then do the bit-bang as a burst in
> there, so that you would have more control over the timing. But that kind of
> code isn't going to play well with the rest of the kernel...
>
> If the hardware design isn't set, you might want to consider using that GPIO
> line as a quasi-SPI link to a small, AVR-type microcontroller that does the
> bit-banging on your behalf. Long-term, that's going to be a more reliable and
> flexible solution I think.
>
>
> b.g.
> --
> Bill Gatliff
> [email protected]
>



--
Jon Smirl
[email protected]

2008-10-08 17:00:31

by Chris Friesen

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Jon Smirl wrote:

> The existing LIRC driver for a serial port is here:
> http://lirc.cvs.sourceforge.net/viewvc/lirc/lirc/drivers/lirc_serial/lirc_serial.c?view=markup

That driver basically does busy-wait bitbanging, using rdtsc on x86 if
available or udelay() if not.

Your best bet is probably to use hrtimers combined with high res
timestamps to correct for accumulated error.

Chris

2008-10-08 18:57:41

by Remy Bohmer

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Hello Jon,

> So how do I reliably generate 38Khz without destroying latency in the
> system? I also don't want to measure the speed of the code I'm
> executing - same code has to run on 90Mhz ARM and 3Ghz Core2. If a do
> a loop with nanosleep() I need to know how fast my code is to subtract
> it's execution time form the sleep time. The existing LIRC code works
> this way and measures it's timing loop.
> hrtimers look promising, but hrtimers doesn't have a periodic API. Is

Hm, 38 kHz is a period time of 26us, for a simple clock you need at
least a twice this frequency, so you need a interrupt every 13us.
Looking at a 200MHz ARM processor (AT91 for example), the HRtimer
framework causes about 100-150us of work after each interrupt. So,
that will probably not work on a 90MHz processor...
nanosleep has similar effects in the system, so that will not work either.
Looking at a worst case interrupt latency of about 50us (still at
200MHz ARM) you still won't get an accurate 13us interval, and then we
are not talking about the execution time of the code you want at this
frequency...

So, if you want such things use a FIQ on ARM, or handle the whole
burst on a busy-idle base, while polling some accurate timer routine
(like sched_clock() for example if its implementation is accurate
enough, and do it in a non-preemptable section, 1 preemption and you
might be preempted for 50us or more), but then you will also run into
problems because of the lengthy execution time (0.79ms)...
Notice that on X86 this is not doing much better, on preempt-RT, the
worst case latency on X86 is about 30us...

So, this will not be an easy job... You probably know by now why it is
implemented this way currently in LIRC...


Good luck ;-)


Remy


> there a technique for creating periodic timing that doesn't accumulate
> error caused by rescheduling the timers? If I need to send 30 pulses
> of 38Khz, it is more important that the total time be (1/38000)*30 =
> 0.7894ms than it is for each pulse to be generated at exactly 26.3us
> intervals.
>
> Are there other techniques for generating pulse trains in the 36-56Khz
> range on a simple GPIO pin? Anyone have some sample code?
>
> --
> Jon Smirl
> [email protected]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2008-10-08 21:58:45

by Krzysztof Halasa

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

"Jon Smirl" <[email protected]> writes:

> These are external boards people buy to use with MythTV. They are most
> commonly used on the x86, but the NSLU2 has been modified to use them
> too.
>
> The hardware can't be changed, people have bought thousands of these devices.
>
> Many people cut up a serial cable and solder it themselves...

Sure but you only need to bit-bang at 36 or so kHz while transmitting,
right? The receive side is a slow one as the receiver chip has an
integrated "demodulator".

If so then personally... I'd abandon the simple TX circuit, and use
a hardware ~36 kHz oscillator, gated by the serial output signal.
I don't think such transmitters are in thousands. Tens, maybe - the
cost of replacing/modifying them all should be insignificant. I guess
one could design and produce such a TXer in less than 20 minutes.
--
Krzysztof Halasa

2008-10-08 22:24:37

by Dave Hylands

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

>> So how do I reliably generate 38Khz without destroying latency in the
>> system? I also don't want to measure the speed of the code I'm
>> executing - same code has to run on 90Mhz ARM and 3Ghz Core2. If a do
>> a loop with nanosleep() I need to know how fast my code is to subtract
>> it's execution time form the sleep time. The existing LIRC code works
>> this way and measures it's timing loop.
>> hrtimers look promising, but hrtimers doesn't have a periodic API. Is

The 38 kHz decoders will actually work across a range of frequencies
usually about +/- 4 kHz.

If you have a spare UART, you could configure it at 76800 baud and
just send out an appropriate bit pattern (taking into consideration
start bit, stop bit, parity, etc.

115200 baud might also work (3 bit times per 1/38400 of a second). It
won't be a perfect square wave, butI think it would still work.

You could also do something similar if you have a SPI interface. Just
set the clock to the right frequency and use the bits sent out to
generate your pulses.

--
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/

2008-10-09 02:26:49

by Bill Gatliff

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Dave Hylands wrote:

> You could also do something similar if you have a SPI interface. Just
> set the clock to the right frequency and use the bits sent out to
> generate your pulses.

Good point. I have seen that very thing done before, albeit for something other
than IRDA. SPI is particularly nice for that, because you don't have to deal
with the start/stop bits imposed by UART protocols.


b.g.
--
Bill Gatliff
[email protected]

2008-10-09 09:06:35

by Andy Green

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

Eric Miao wrote:

> This isn't easy, 38KHz is quite a high frequency, I'd prefer to
> use an interrupt or fiq based on a accurate clock event source,
> but that will have impact on the system anyway.

Many SoC can elevate PWM interrupt to FIQ. It's definitely possible to
run a FIQ ISR at >50kHz on a slow system; you'd need 2 x the actual
modulation frequency on the PWM though in order to be able to put it on
and off in one cycle.

Then with the PWM regulating the clock rate, you will definitely get
consistent overall timing, and with FIQ service you will get very low
jitter on individual clock issue. In the meanwhile the CPU will
continue servicing interrupts and running foreground code normally in
the cycles left inbetween FIQ service, so it is pretty friendly.

I have an implementation for sc32442 on Openmoko Freerunner kernel that
allows a FIQ ISR written in C, I wrote it to implement HDQ (1-bit
battery protocol that is time based) just using a GPIO and no hardware.
I'm interested in making this more general for ARM to allow wider use
of FIQ stuff and try to get it upstream, but because FIQ itself has some
"special needs" I am not sure what changes are needed to make it more
palatable.

The main guts of it are here:

http://git.openmoko.org/?p=kernel.git;a=blob;f=arch/arm/mach-s3c2440/fiq_c_isr.h;h=e92b103cdfbf115947df5acb4312ef9fc39e1f6e;hb=andy-tracking
http://git.openmoko.org/?p=kernel.git;a=blob;f=arch/arm/mach-s3c2440/fiq_c_isr.c;h=c47d1630081f69dcb82a52a3db18765b10f35384;hb=andy-tracking

...and the FIQ ISR we use with those wrappers is here:

http://git.openmoko.org/?p=kernel.git;a=blob;f=arch/arm/mach-s3c2440/mach-gta02.c;h=cdf2a33b553157208457d1139307c83591d14704;hb=andy-tracking#l136

-Andy

2008-10-09 17:53:34

by linux-os (Dick Johnson)

[permalink] [raw]
Subject: Re: Toggling GPIO at 38Khz

On Wed, 8 Oct 2008, Dave Hylands wrote:

>>> So how do I reliably generate 38Khz without destroying latency in the
>>> system? I also don't want to measure the speed of the code I'm
>>> executing - same code has to run on 90Mhz ARM and 3Ghz Core2. If a do
>>> a loop with nanosleep() I need to know how fast my code is to subtract
>>> it's execution time form the sleep time. The existing LIRC code works
>>> this way and measures it's timing loop.
>>> hrtimers look promising, but hrtimers doesn't have a periodic API. Is
>
> The 38 kHz decoders will actually work across a range of frequencies
> usually about +/- 4 kHz.
>
> If you have a spare UART, you could configure it at 76800 baud and
> just send out an appropriate bit pattern (taking into consideration
> start bit, stop bit, parity, etc.
>
> 115200 baud might also work (3 bit times per 1/38400 of a second). It
> won't be a perfect square wave, butI think it would still work.
>
> You could also do something similar if you have a SPI interface. Just
> set the clock to the right frequency and use the bits sent out to
> generate your pulses.
>
> --
> Dave Hylands
> Shuswap, BC, Canada
> http://www.DaveHylands.com/

MIDI runs at 31.25 kBaud PC/AT machines do TX/RX through the
audio boards. Drivers for programming these boards are available
for Linux.

These might work fine.

Cheers,
Dick Johnson
Penguin : Linux version 2.6.25.17 on an i686 machine (4786.81 BogoMips).
My book : http://www.AbominableFirebug.com/
_


****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to [email protected] - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.