warthog618 / go-gpiocdev

A native Go library for accessing GPIO lines on Linux platforms using the GPIO character device

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Microseconds precise timings

miathedev opened this issue · comments

commented

More like a question.

I would like to send Infrared packages via NEC. Looks like a timing of 1mS seems to be the absolute limit. Any ways to archive at least 500 uS precise timing?

for {
		select {
		case <-time.After(500 * time.Microsecond):
			v ^= 1
			l.SetValue(v)
			//fmt.Printf("Set pin %d %s\n", offset, values[v])
		case <-quit:
			return
		}
	}

Outputs a signal like ~ 400Hz, that wasnt expected. (Tbh it was even better then i expected using a character device)

Maybe you know i nice workaround.

You have two APIs in play here - time and gpiod.

The SetValue() should not be the limiting factor here - in the benchmarks I ran on a Raspberry Pi Zero the SetValue() typically takes 12531 ns/op - well within the 500us range you are after, though that obviously depends on your platform.

You are probably hitting the granularity limit of the time API - golang/go#29485.
With this test code:

	for i := 0; i < 10; i++ {
		a := time.Now()
		b := <-time.After(500 * time.Nanosecond)
		fmt.Println(b.Sub(a))
	}

I get:

176.874µs
39.167µs
19.218µs
20.261µs
21.198µs
19.479µs
31.666µs
239.791µs
218.593µs
38.646µs

i.e. the timer is less than the tick granularity and appears to expire immediately - the time difference being less than the requested delay.

but with 500us:

	for i := 0; i < 10; i++ {
		a := time.Now()
		b := <-time.After(500 * time.Microsecond)
		fmt.Println(b.Sub(a))
	}

I get:

1.296507ms
1.190414ms
1.257601ms
1.174737ms
1.271872ms
1.156039ms
1.194372ms
1.165362ms
1.161403ms
1.223278ms

Here is appears to wait at least one kernel timer tick, which is typically ~1ms.

So I'd be looking at the timer to confirm if the problem is there, or removing the timer from your example and toggling the line as fast as possible, similar to the benchmark code, to determine the maximum SetValue() rate on your platform.

Not sure what the best workaround would be if the timer granularity is your problem.

commented

Actually those are pretty bad results. Thats not precise enough at all 😆

Thank you very much for your help! I think theres no way around a kernel driver. But tbh i almost expected that. Using the userspace cant be as fast.