BBB, PRUSSV2, using timer on IEP


I’m trying to use IEP timer on PRU on my BeagleBone Black, but without much luck. I would like to use it for precise timing, so I have created demo app that should demonstrate IEP timer capabilities. Demo app should work in following way:

  • first turns LED on one of GPIO pins
  • then starts timer
  • pools timer value until reaches some predefined value
  • turns LED off
  • exits

Part with runing LEDs on/off works fine, problem is with timer. From what I have tried so far, I’m not able to get it running. Here are the steps that I performed in the code to start counter:

  1. set counter value to 0
  2. enable timer clock PRU_ICSS_CFG.CGR.IEP_CLK_EN=1 (although this should be already on upon reset)
  3. // start counter IEP_GLOBAL_CFG.CNT_ENABLE = 1

Code gets stuck when pooling counter value (red bellow) - it never reaches desired value. Did I missed something in initialization? any hint?

Here is code of sample app:

.origin 0
.entrypoint START

#define AM33XX

#define GPIO0 0x44E07000 // base address of GPIO 0

#define GPIO_OE 0x134 // offset of the register that defines pin directions
#define GPIO_CLEARDATAOUT 0x190 // offset of the register used for setting pin to LOW
#define GPIO_SETDATAOUT 0x194 // offset of the register used for setting pin to HIGH
#define IEP 0x2E000 // base address of Industrial Etherne Peripheral (IEP)

#define PIN_GPIO_0_26 1<<26 // references GPIO 0 pin 26 (P8-14 on BBB headers)

#define IEP_GLOBAL_CFG 0
#define IEP_COUNT 0xc

#define rGPIO0Base r0
#define rOE r1
#define rSetDataOut r2
#define rClearDataOut r3
#define rOutPin r4
#define rIEPBase r5

#define rT1 r16
#define rT2 r17


LBCO rT1, c4, 4, 4 // Load Byte Constant Offset
CLR rT1, rT1, 4 // clears r0 and copies to destination r0
SBCO rT1, c4, 4, 4 // Store byte constant table offset

MOV rGPIO0Base, GPIO0 // setup needed address offsets
MOV rOutPin, PIN_GPIO_0_26

MOV rT1, 0x00000000 // set all pins on GPIO 0 as output
SBBO rT1, rGPIO0Base, rOE, 4

// turn led on
SBBO rOutPin, rGPIO0Base, rSetDataOut, 4

// init counter value to 0
MOV rT1, 0

// enable timer clock PRU_ICSS_CFG.CGR.IEP_CLK_EN=1
LBCO rT1, C4, 0x10, 4
SET rT1, 17
SBCO rT1, C4, 0x10, 4

// start counter IEP_GLOBAL_CFG.CNT_ENABLE = 1
SET rT1, 0

// wait until counter reaches desired value
MOV rT1, 1 // for testing only → counter never reaches this value
QBLT L1, rT1, rT2

// led off
SBBO rOutPin, rGPIO0Base, rClearDataOut, 4

MOV r31.b0, PRU0_ARM_INTERRUPT+16 //tell the c program we are done (just remove it if your c program does not handle the interrupt)




I don't immediately see anything obvious that is wrong with your code.

I have a known working example of using the IEP timers with the PRU, but
I'm using the overflow event rather than polling the count value:

I'd recommend grabbing my MachineKit SD card image and single-step
through your code using the debugger that's part of LinuxCNC. You will
probably be able to easily spot the cause of the unexpected behavior.

If you don't want to grab the whole SD image, there are some other PRU
debugging tools available, but I haven't used them recently and can't
vouch for how well they work:

Thx. I already found example you mention (glad to know it’s yours) and used it as guideline how to use compare registers on IEP. Did reworked the example and now it’s running fine. I suspect that issue in my initial example was with following piece of code

QBLT L1, rT1, rT2

My expectation was that “quick branch” instructions does comparison of complete registers (all 32 bits), but in fact it compares only 8 bits (you can chose if it’s B0,B1,B3 or B4). In my case I think it was working only rT1.b0 and rT2.b0. For sure that contributed to unexpected execution flow, maybe there was also something else.

Although reworked example works just fine, will debug this one as I don’t want to leave open ends :slight_smile: Also will try debugger you mentioned, as writing apps blindly and debug them only with LED attached to GPIO is bit of pain :slight_smile:


Hm, I have to correct my self. After throwing a second look into instruction format for quick arithmetic test and branch, where register is Op2, QBNE supports comparisons of all bits in both registers (didn’t read tables Rs2Sel and Rs1Sel to the end). My mistake…

Yet, this than makes my first code not working even a bigger misery. Will have to take a much deeper look at the code.



You should check again the QBLT usage.
The code will stay in your loop when rT2 < rT1 i.e. IEPcount < 1.
Try QBLT L1, rT2, rT1


I think the existing QBLT is correct, it should loop while the counter
(rT2) is less than the timeout value (rT1). The timeout is set to one
for testing, right?

I loaded up the code in the single-step debugger and it ran as expected,
so perhaps there is something wrong other than the code. How are you
loading the device-tree overlay for the PRU, and which overlay are you
using? What are you using to load the code into the PRU, reset it, and
set the operating mode? I ran my test on a system that had been
actively running LinuxCNC, so I know the PRU was already setup, and I
know the PRU program loading code works.


Ignore my comment - the order of parameters always confuses me :slight_smile:


It has bitten me more than once as well! I always have to double-check
in the PRU reference guide, and even then it seems like I still get it
wrong about 1/2 the time! :slight_smile:

Well, call me crazy, but I copied the same code as posted in first mail and now works fine. Kill me if I know whats is/was going on.

I enable PRU with following command:

echo “BB-BONE-PRU-01” > $SLOTS

For load I use Python PRU library called “pypruss”, and here it it how it looks like:

import sys
import pypruss

pypruss.modprobe() # This only has to be called once pr boot
pypruss.init() # Init the PRU # Open PRU event 0 which is PRU0_ARM_INTERRUPT
pypruss.pruintc_init() # Init the interrupt controller
pypruss.exec_program(0, “./” + sys.argv[1]) # Load firmware on PRU 0
pypruss.wait_for_event(0) # Wait for event 0 which is connected to PRU0_ARM_INTERRUPT
pypruss.clear_event(0) # Clear the event
pypruss.pru_disable(0) # Disable PRU 0, this is already done by the firmware
pypruss.exit() # Exit, don’t know what this does.

I don’t know: maybe I was just tired or there is some hidden glitch. Anyway thx guys for the help - if nothing, I did learned few new things :slight_smile: I appreciate it…


Well, call me crazy, but I copied the same code as posted in first mail and
now works fine. Kill me if I know whats is/was going on.

We'll let you live for now... :slight_smile:

<snip device tree loading and pypruss>

...that all looks OK. I haven't used pypruss, but others have and I
don't know of any serious problems with it.

I don't know: maybe I was just tired or there is some hidden glitch. Anyway
thx guys for the help - if nothing, I did learned few new things :slight_smile: I
appreciate it...

It was just broken until you asked for help! Complex devices seem to
self-generate properties like this that border on the mystical. :slight_smile:

Personally, I blame quantum mechanics. Ever since they came up with the
quantum theory, my favorite writing pencil has exhibited a half-life
that continues to shrink. At the moment it's down to about a week and a
half, but at least the pencil seems to re-appear mysteriously several
days after vanishing. Probably some law about the conservation of
energy or something...


I think I have to take a bit slower pace - until one month ago I did not even knew about BBB not A8 and now I’m already trying to conquer mystical powers of PRU-ICSS V2 :slight_smile:

And now onto to PRU debuggers challenge - yummy :)))

hi guys,

Thanks for the informative discussion… I am new to Beaglebone… can you suggest me the best place to learn the asm program for pruss …??? Also I am not able to find any documentations regarding the instruction sets … i have used asm in pic but am335x asm code looks way too different… Any help …??