Help with PRU

Hi,

I need a simple PRU code:
  1. Wait until a start event or a counter value shared from code running on CPU
  2. Flicker 2 LEDs using 2 GPIOs using a timer expiration logic. For
example the CPU code
      decided to flicker one LED with 10Hz and the other one with
18Hz. Seen that a
      single instruction completes in 5ns, the code running in CPU may
calculate two expiration
      counters and pass them through the shared memory. (Any other
easier solution is appreciated)
  3. If a stop event or a specific counter value shared from CPU
arrives, stop flickering and goto 1

The logic can be implemented for example in Python like this though I
don't know if this is the most efficient/precise way of doing this:
    while 1:
        tic = time.time()
        if previous_ts_1 + period_1 <= tic:
            led1 ^= 1
            GPIO.output(PIN_LEFT, led1)
            previous_ts_1 = time.time()
        if previous_ts_2 + period_2 <= tic:
            led2 ^= 1
            GPIO.output(PIN_RIGHT, led2)
            previous_ts_2 = time.time()

I enabled the virtual PRU cape using device tree overlay and
successfully compiled and launched the blink code I found on the
internet but I'm quite confused in finding out which GPIO pins are
accessible/available from PRU. There are a lot of documents, specs,
pin names, gpio offsets, pinmuxes, etc. Do I need to apply a dtbo for
having 2xGPIO or are there already available ones that the PRU can
access?

I'll be controlling the PRU using PyPruss from Python. The python code
should do this:
1. Send a start event and some information related flickering periods
2. Do something else
3. Send a stop signal.
4. Do something else and goto 1

If anyone can help me on the assembly side about timing logic, I'd be
happy. Maybe we can arrange an IRC session to talk about this.

Thanks!

I enabled the virtual PRU cape using device tree overlay and
successfully compiled and launched the blink code I found on the
internet but I'm quite confused in finding out which GPIO pins are
accessible/available from PRU. There are a lot of documents, specs,
pin names, gpio offsets, pinmuxes, etc. Do I need to apply a dtbo for
having 2xGPIO or are there already available ones that the PRU can
access?

The PRU can control all GPIO pins, just write directly to the set and
clear registers.

If you want to see an actual I/O pin twiddle, you should export the
appropriate GPIO pin or otherwise setup the pin multiplexing and
direction register.

I'll be controlling the PRU using PyPruss from Python. The python code
should do this:
1. Send a start event and some information related flickering periods
2. Do something else
3. Send a stop signal.
4. Do something else and goto 1

If anyone can help me on the assembly side about timing logic, I'd be
happy. Maybe we can arrange an IRC session to talk about this.

There are many ways to create a delay. The easiest would just be a
software loop, or you can use the IEP timer documented in the latest PRU
reference manual, or many other options. More detail about exactly what
you're trying to do, what you've tried, and your design constraints will
probably get you more useful help.

I enabled the virtual PRU cape using device tree overlay and
successfully compiled and launched the blink code I found on the
internet but I'm quite confused in finding out which GPIO pins are
accessible/available from PRU. There are a lot of documents, specs,
pin names, gpio offsets, pinmuxes, etc. Do I need to apply a dtbo for
having 2xGPIO or are there already available ones that the PRU can
access?

The PRU can control all GPIO pins, just write directly to the set and
clear registers.

So are the pr_pru[01]_* modes for some pins are just for faster GPI/GPO access?

There are many ways to create a delay. The easiest would just be a
software loop, or you can use the IEP timer documented in the latest PRU
reference manual, or many other options. More detail about exactly what
you're trying to do, what you've tried, and your design constraints will
probably get you more useful help.

Thanks for the pointers. A timer will be much easy if it is easy to implement :slight_smile:

What I'm trying to do is to flicker 2 LEDs with different flickering
rates, say 15Hz and 18Hz or 18Hz and 19Hz (but not much than ~25Hz).
A userspace code will trigger this flickering and do another stuff.
Once it decides to stop the flickerings, it will notify the PRU and
the PRU will stop flickering/driving the LEDs.
But after some while the userspace code may again decide to start
flickering. So one possibility is to launch and terminate the firmware
each time but I don't know if loading the firmware and executing it
has a big overhead or not. Another is to use some busy waiting in the
firmware so that the code just does nothing unless the userspace code
tells him to start flickering.

I don't know which one is easier though.

Thanks again.

25Hz for PRU? :slight_smile:
hope its for educational purposes

I enabled the virtual PRU cape using device tree overlay and
successfully compiled and launched the blink code I found on the
internet but I'm quite confused in finding out which GPIO pins are
accessible/available from PRU. There are a lot of documents, specs,
pin names, gpio offsets, pinmuxes, etc. Do I need to apply a dtbo for
having 2xGPIO or are there already available ones that the PRU can
access?

The PRU can control all GPIO pins, just write directly to the set and
clear registers.

So are the pr_pru[01]_* modes for some pins are just for faster GPI/GPO access?

Yes, those are the direct PRU I/O, and have virtually no delay. It
takes about 100 nS to write to an arbitrary GPIO pin using the PRU to
talk to the GPIO registers.

There are many ways to create a delay. The easiest would just be a
software loop, or you can use the IEP timer documented in the latest PRU
reference manual, or many other options. More detail about exactly what
you're trying to do, what you've tried, and your design constraints will
probably get you more useful help.

Thanks for the pointers. A timer will be much easy if it is easy to implement :slight_smile:

What I'm trying to do is to flicker 2 LEDs with different flickering
rates, say 15Hz and 18Hz or 18Hz and 19Hz (but not much than ~25Hz).
A userspace code will trigger this flickering and do another stuff.
Once it decides to stop the flickerings, it will notify the PRU and
the PRU will stop flickering/driving the LEDs.
But after some while the userspace code may again decide to start
flickering. So one possibility is to launch and terminate the firmware
each time but I don't know if loading the firmware and executing it
has a big overhead or not. Another is to use some busy waiting in the
firmware so that the code just does nothing unless the userspace code
tells him to start flickering.

I don't know which one is easier though.

I would suggest you leave the PRU code running all the time, but have
settings for always off and always on as well as "blink rate". Then
once everything is setup your application can do whatever it wants
without having to worry about (re)loading the PRU code.

Also, for 25 Hz pulse rates, you can get pretty good performance without
using the PRU, unless your blinking needs to be very precise or low
jitter for some reason. Using the PRU for this really seems like overkill.

As for timers, I've got example code using the IEP timer to blink some
LED's in my LinuxCNC repository:

https://github.com/cdsteinkuehler/linuxcnc/blob/MachineKit-ubc/configs/ARM/PRU-Debugger/pruexample.p

Also, for 25 Hz pulse rates, you can get pretty good performance without
using the PRU, unless your blinking needs to be very precise or low
jitter for some reason. Using the PRU for this really seems like overkill.

Well the thing is that at the same time I have to acquire data from a
USB device with a rate of 129 packets/second and the device doesn't
have an internal buffer. So if because of some OS jitter, I miss a
packet from the USB, or because of some jitter the flickering pattern
is delayed, my experiment will be invalid.

I have two separate Python programs for these tasks. If I run them
concurrently, RaspPi can miss some packets or miss flickering rate but
BBB seems to perform much better but I don't want to take risks as
I'll also want to do some signal processing in the acquisition loop,
etc.