Beaglebone black PRU - counting pin state changes

Im trying to get my BB PRU counting ping state changes on four inputs P8-11 P8-12 P8-15 and P8-16 and share in memory to be read for external code (running in main arm cpu of BB black).
I read every info on the web, cooking pru book, exploring bb book, etc, no luck at all. Im lost i have background on assembler on microchips pics but cant get this working, even the samples for output led dont work.

AFAIK i must produce a remoteproc firmware , load onto PRU, and go on. Again, the easiest sample for led blinking dont works and i lost two weeks on this.
Theres anyone here helping me with this task? I can pay for the job.
Please contact me. I have the hardware ready on my desk.

best regards.

these pins specifically? … would be easier if you picked 4 pins that are ‘pruin’ for the same PRU. If not, you’ll have to use OCP, and potentially on different GPIO banks. still easily done, but not as easy as ‘pruin’.

gomer@bbb42:~$ config-pin -l p8-11
default gpio gpio_pu gpio_pd gpio_input qep pruout
gomer@bbb42:~$ config-pin -l p8-12
default gpio gpio_pu gpio_pd gpio_input qep pruout
gomer@bbb42:~$ config-pin -l p8-15
default gpio gpio_pu gpio_pd gpio_input qep pru_ecap pruin
gomer@bbb42:~$ config-pin -l p8-16
default gpio gpio_pu gpio_pd gpio_input qep pruin

how fast are these inputs going to change state? Are they going to change as a set (like parallel input) or independently?

The time span of your method of detection must be less than the time that the input could change twice.

At high speeds, even if you put in the best interrupt code, you could miss some changes.

But assume that the input changes will take place at minimum 1ms (1Khz) apart. Then there are at least two ways to reliably detect the changes. Even at 100Khz it could be done reliably. The fastest input that could be done reliably might be 1Mhz. That is the max speed that I would attempt this.

good luck,

This is a a hardware already in field, so cant change the pins.
Thanks for the indications for setup the pin.

1Khz is the fastest it will change so is ok.

Thanks . Can please help me with pru c (or asm code)? I know to upload firmware and run but, as i say, the code i test in examples seems is not working.

Just need a free counter for each input put in a shared memory variable to be read from linux.

I will pay for your help, off course.

Best regards.

Sorry to ask again, i dont see how to config this pins to be muxed. Can please give me an example?

best regards

No, but in the spirit of ‘The proof of the pudding is in the eating’, I will describe one way to do it. It might take me 5 to 10 hours to code, test, and deploy a project like this, but only 5 to 10 minutes to describe it.

so, the overall outline of the project:

  1. set up pwm signal of duration 1us, duty cycle 20% (200ns) … this will be your application clock that will govern the timing of the pin states. I have the details of how to set up a pwm if you need them. do you have an oscilloscope to verify the timings of this project?

  2. you will need 7 (seven) general purpose registers
    a) one for each pin to keep count of the changes (so 4)
    b) one to keep the current state of each pin (say the lower 4 bits as in a binary switch)
    c) one to record the ‘time’ of the change… if you increment this register every time your pwm signal goes high, it will last 68 minutes and 15 seconds before rolling over. (4G/1M = 4k … 4k seconds ~= 68 min, 15 seconds)
    d) one register to indicate that a change of one or more of the pin status has been made in this iteration of the loop (I leave to you any optimization that makes a separate register unnecessary)

  3. set up a ring buffer between the pru and the linux ‘c’ program. This will serve as the communication link for reporting (to linux). A ring buffer assures that all changes will be reported as opposed to a ‘c’ program polling for current state and potentially missing some changes. A good example of how to do this is here Turnkey PRU deskclock application for BBB … the example uses the pru as the reader, and the ‘c’ program as the writer, but this is easily reversed.

  4. Main loop:
    a) wait for pwm signal to go high, increment register used for timing … set change indicator to 0
    b) check the state of p8-11, if changed from saved state: 1) update current state … 2) increment counter for p8-11 … 3) increment indicator that change has been made
    c) same as b) for p8-12
    d) same as b) for p8-15
    e) same as b) for p8-16
    f) if any pin changed, write to ring buffer which will be read by ‘c’ program
    g) repeat from step a)
    this assumes that you can do steps b thru f in 1us which is about 200 instructions… use oscilloscope to VERIFY.

  5. you’ll need the ‘c’ linux program set up to run as root so that you access to /dev/mem … again see Turnkey PRU deskclock application for BBB for example of how to do this… This program would simply read the ring buffer, and report the changes.

5a) report:
a) 1 word … timer register … for determining how fast this change came after the previous one
b) 4 words … one for the count of each pin
c) 1 word … with the current state of each pin
the format of your report I leave to you.

good luck

1 Like

the pins are already ‘muxed’… you need to demux them.

config-pin -a p8-11 gpio_input

this is one example.

good luck

1 Like

Sorry. i dont get why is needed pwm signal duration? Why dont just poll the state change for then pin and , if this change, count a pulse? I need to count changes. I dont need frecuencey details or pulse duration, because it can be variable. It can move at 10hz and then at 1khz.

Can this just write the counter to a file in linux system?

This dont matter in my project.

Best regards.

the frequency details will give you and your user confidence that all changes have been counted. whether they happen at 10hz or 1khz might be important to know for some… if not, do it your way.

you can do anything that a ‘c’ program can do … but you didn’t mean to write to the linux file system from the pru … did you?

Thanks a lot for your help, i will analyze your project. maybe hijack this and get the creature working. Im lost, honestly. :grimacing:


All your pins are at the same GPIO-1 subsystem. Two of them can get muxed as fast PRU-GPIO (P8-15, P8_16), but the others (P8_11, P8_12) are only available as GPIO input. I wouldn’t mix both input methods.

I recommend using the GPIO-1 subsystem over L3 bus (OCP) either by polling the state of the GPIO-DATAIN register, or by counting the events in an interrupt (using registers LEVELDETECT0, LEVELDETECT1, RISINGDETECT, FALLINGDETECT, DEBOUNCENABLE and DEBOUNCINGTIME accordingly).

Find example code (PASM, C, Fb, Python) in the libpruio project. Using libpruio you could test both concepts on ARM CPU. Later switch to the second PRU.

A possible pit fall: libpruio is based on the old uio_pruss driver, which isn’t available in newer kernels. So installing libpruio may be an issue (it’s running fine on kernel 4.19.x).


I will try to use just this two input. Thanks

Will investigate the library, the interrupt mode sound like what im using with microchips PICS for years. Hope can reuse this knowledge in some way.

best regards