Allocating a timer for the PRU

I need to get a hardware timer routed to the PRU, so I looked at the
PRU example PRU_timer2Interrupt to see how they did it.

They mmap /dev/mem and manipulate the timer directly.

There has to be a better way. The kernel must have some hardware
timer allocation mechanism already as part of the platform support.
Ideally this would be done without having to fork uio_pruss but I'm
not 100% convinced that's possible. I'm thinking that the kernel
driver for the pruss needs to do the actual work of allocating (and
subsequently freeing) the timer.

Any other design approaches anybody can think of?

I found dmtimer.c with two interesting methods:

   struct omap_dm_timer *omap_dm_timer_request_specific(int id)
   struct omap_dm_timer *omap_dm_timer_request(void)

Is this the interface I am supposed to do to grab a hardware timer
from a kernel module?

--Chris

Hi,

I’ve tried to use those functions from my driver some time ago . However every call to any of them throws an error, something with 32KHz clk.

If you manage to make it work pleas post a short how to.
I also tried to access timers directly(io remap), but I got kernel exception something with “120X …”.

A new friend found this:

http://omappedia.org/wiki/Timer

which describes how it's all supposed to work. All I really want to
do is allocate the timer in a way that nobody else will attempt to use
it; then have the PRU itself do the rest (including configuring its
rate and connecting events).

I'll try this and let you know how it works out.

Hi,

Any progress here?
I didn't power up my bone for some time (due to Final Fantasy XIII-2
release :slight_smile: ) and didn't investigate the issue, however when I'll
return to it I want to allocate one timer for pruss.
I was wondering how this driver works, because I am going to generate
interrupt(Overflow) every 10us so if it puts interrupt handler
somewhere it will kill linux. I need it only to configure the timer
and forget that timer with such ID ever existed:)

Thanks

Hi,

Any progress here?

Yes, some. I’ll document it here for posterity.

With the kernel I’m currently using (it’s an Angstrom 3.2.0 something) allocating a timer from the kernel driver works and is easy:

struct omap_dm_timer *timer1;

struct omap_dm_timer *t = omap_dm_timer_request();

printk(KERN_INFO DRV_NAME “: Allocated timer %d, irq %d, base address %p\n”, t->id, t->irq, t->io_base);

On my system, this returned timer0 for the first call, and timer3 for the second call (I allocated two timers). One thing that does bother me is that the “base address” returned is all wrong … it looks like a virtual memory address. What I did was to ignore that address and simply pass the PRU the t->id then let the PRU figure out where that lived.

I seemed to be on the right path, but remember: my point here was to get a timer running continuously generating an event visible to the PRU. That last part turns out to be a problem on the AM335x.

The timers on the AM335x map to:

Timer 0: IRQ66

Timer 1: IRQ67

Timer 2: IRQ68

Timer 3: IRQ69

Timer 4: IRQ92

Timer 5: IRQ93

Timer 6: IRQ94

Timer 7: IRQ95

However, take a look at the PRU chapter of the TRM, in the Functional Description of the PRUSS interrupt controller:

The PRUSS INTC supports up to 64 system interrupts from different peripherals …

Interrupts on the PRU get mapped from IRQ to Channel to Host (see TRM section 4.6.2). The first level of mapping (IRQ to channel) is controlled by registers CMR0 through CMR15, and if you look at the last one it confirms the above statement. The highest interrupt that can be mapped to a PRUSS INTC channel is 63.

Big problem. There is no way to map a DMTIMER event to a PRUSS interrupt that I can tell. I asked the E2E forums and they concurred.

There are a couple of ways around this:

  1. Don’t use DMTIMERs at all. More on this in a second

  2. If you’ve got control of the hardware, turn on the DMTIMER’s output pin, and wire it back to an input that the PRU can see directly through an EGPIO pin. This stinks, though, because GPIO pins to the PRUSS are fairly prescious (you only get 6 inputs and 6 outputs for the entire subsystem, and if your PRUs are doing some communications-related job then you probably need them for other things)

  3. Set up the timer in userspace, and have an ISR (on the MPU side) that signals an event visible to the PRU. This is means introducing latency, and imposing a bit of a real-time requirement on the MPU (the whole point of the PRU is to relieve the MPU of real time requirements, so this is a fairly bad solution)

  4. You could have the timer run without interrupts, and have the PRU poll for the interrupt status bit (or overflow bit or anything else you wanted) in the timer directly, via L3/L4. The PRU machine doesn’t really have ‘interrupts’ per se - waiting for an interrupt is a busywait process from the PRU’s perspective, so busywaiting for the timer overflow flag isn’t that different, EXCEPT that you’re doing so over the interconnect. I don’t know enough about the implications of this to say whether or not that’s a good idea. Intuition tells me “bad” – if you’re making requests over L3/L4 in a busy loop at 200 MHz, I have to think that’ll have a negative impact on anybody else trying to use that bus, possibly even starving the MPU. I really don’t have good insight into how this works, though. If somebody else out there in beagleland understands this better than me please let me know - I would like to learn from you.

Now, fortunately, not all hope is lost here. Someone on the E2E forums gave me another idea, and I tried it (and it works). There’s an eCAP hooked directly to the PRUSS, and it’s capable of generating a periodic timer. What you do is put the eCAP into APWM mode, and set registers TCAP1 and TCAP2 for a fixed period of your choosing. At that point, you can decide to either map that interrupt (which is within the mapping range of the PRUSS INTC) to an event (HOST0 or HOST1, meaning the event is visible as a bit in R31) … OR … you can just poll the eCAP’s interrupt flag to see when it wrapped. The internal eCAP is on the LOCAL PRU bus, so you’re polling it over the internal 32-bit interconnect SCR, but I think that’s OK (at least better than polling an external one over L3/L4). There’s not a lot of detail on how that 32-bit internal interconnect works, so I’m not sure if you could possibly starve the other PRU if you poll eCAP in a tight loop. I guess it’s possible. If that’s the case, then maybe mapping eCAP to a HOST interrupt channel would be more efficient. Again, though – those are a limited resource (there are two channels that map to the event register). You can map multiple interrupts to them, but as soon as you do that, you have to implement some kind of polling strategy to figure out which one was the cause.

So, there are lots of choices, but none of them seem like they are as clean as the approach in the L138 OMAP, where the timers are in an IRQ range that’s mappable to the PRUSS. I am perplexed why the designers chose to do it this way, because having flexible timers feed into the PRUSS seems to me to be critical to the PRUSS’s primary intended use case (custom communications). They say, for example, that PRUSS is a good way to build custom UARTs. Well, that’s not a particularly easy thing to do without a clock :slight_smile:

Finally … I’m not an expert at PRU, but for the things I have tried, I’m definitely a fan. People seem to be complaining a lot about “Why didn’t they put in some M3 cores instead!” but there’s a certain beauty in the simplicity of the PRU and its clean little assembly language. Maybe if most people are perplexed by it we can use this new found knowledge to get higher paying jobs. :slight_smile:

Good luck,

–Chris

Thanks. It looks like it was fixed in the later kernels I think I have
3.1kernel and mentioned code was failing. I'll try to refresh bitbake
and see if it helps.
I was considering pooling the interrupt status, however proposed eCAP
solution seems to be better, because it will use only PRUSS resources.
I'm also not an expert in pru, but I also prefer pru over cortex Mx,
because it's simple and more RISC than cortex. If I want to have
interrupt ever 10us and pru is working at 200MHz this gives me only
2000 cycles. This gives me 2000 instructions(except external resources
access) on pru, on cortex many instructions take more than 1 cycle.
Pru is simpler, faster and more predictable than cortex and is more
suitable for real time tasks.

Thanks
/\/\arek Porwisz

W dniu 7 marca 2012 15:42 użytkownik Christopher Piggott
<cpiggott@gmail.com> napisał:

Earlier, I wrote:

You could have the timer run without interrupts, and have the PRU poll for the interrupt status bit (or overflow bit or anything else you wanted) in the timer directly, via L3/L4. The PRU machine doesn’t really have ‘interrupts’ per se - waiting for an interrupt is a busywait process from the PRU’s perspective, so busywaiting for the timer overflow flag isn’t that different, EXCEPT that you’re doing so over the interconnect. I don’t know enough about the implications of this to say whether or not that’s a good idea. Intuition tells me “bad” – if you’re making requests over L3/L4 in a busy loop at 200 MHz, I have to think that’ll have a negative impact on anybody else trying to use that bus, possibly even starving the MPU. I really don’t have good insight into how this works, though. If somebody else out there in beagleland understands this better than me please let me know - I would like to learn from you.

I received an e-mail on the E2E forums, and since I know a number of folks are following this discussion on the beagle list I want to share it here as well:

It is okay to poll external timers. It will be few tens of cycles of latency per such poll. But I would prefer using internal timer over external timer.

The interconnect is switched - there is no sharing of interconnect resources if the source and target for a transaction do not overlap with source and target of another concurrent transaction. There could be congestion if, for example, a bridge is present on the way to L4 for transactions from two different initiators on L3 accessing addresses beyond L4 at the same time. Determinism can usually not be guaranteed for transactions on L3/L4 in a busy system.



>





Those things explained, keep in mind the routing. See the TRM figure 10-1 (L3) and note that the PRU is the initiator on L3F. The target of the request, if it’s a timer, is L4_PER (specifically, P4_PERPort0). Anything else trying to access something in that path would result in a small delay.

Doesn’t sound as gloomy as I predicted it would be.

–Chris

I read something wrong, it’s L4_PER port 1 for the PRU, not Port 0.

Hi Chris,

Thanks for keeping us up-to-date. Most PRU programs will probably need a cyclic timer of some sort. So your information is very usefull.
A while ago I looked into using a dmtimer from the PRU (DMTIMER2 is in the PRU constants table), but the kernel I was using at that time couldn’t get a proper clock for the timer (nor for any other). As time would probably solve that problem, I’ve been doing busy loop timing in the meantime. A very accurate, zero-latency timer could always be made using the ‘other’ PRU (remember we’ve got two!). Or maybe one could use an internal timer in the IEP (it seems to have many), but I’ve seen no documentation thus far, so that might be a problem.
I’ll look into the eCAP solution within a couple of days and will post my findings here.

— Bas

[…]

  1. If you’ve got control of the hardware, turn on the DMTIMER’s output pin, and wire it back to an input that the PRU can see directly through an EGPIO pin. This stinks, though, because GPIO pins to the PRUSS are fairly prescious (you only get 6 inputs and 6 outputs for the entire subsystem, and if your PRUs are doing some communications-related job then you probably need them for other things)

Sure you’ve counted them all? I’m using 14 outputs mapped to R30 on PRU1… Exactly enough to do the job :slight_smile:

— Bas