element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
BeagleBoard
  • Products
  • Dev Tools
  • Single-Board Computers
  • BeagleBoard
  • More
  • Cancel
BeagleBoard
Blog BeagleBone PRU - Timer Functionality
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join BeagleBoard to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 12 Aug 2019 6:23 PM Date Created
  • Views 9076 views
  • Likes 9 likes
  • Comments 26 comments
  • timer
  • pru
  • BeagleBone
Related
Recommended

BeagleBone PRU - Timer Functionality

Jan Cumps
Jan Cumps
12 Aug 2019

The PRU modules of the BeagleBone's Sitara controller have a timer.

In this short post, I'm trying if I can get it to work.

 

image

 

The future plan is to use it in an algorithm for stepper motor control.

I'd like to make a smart algorithm that recalculates acceleration/deceleration of the stepper motor while that motor is running.

 

 

PRU Timer

 

It's a component of the unit's Industrial Ethernet Peripheral but can be repurposed as a generic timer within the real time unit.

I took the example timer project from TI that sets the timer for 10 seconds, waits for it to expire and then exits.

I added two line of code: set an output low when the PRU starts, then toggle it after 10 seconds. That lets me validate the timer without a debugger.

 

The output I chose is P9_29. The only reason I chose that one is because I have a PRU cape with a LED on that pin.

This cape is not required. You could just put a +-1K resistor with a LED in series between that pin and GND. Or a scope probe or voltmeter.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Code

 

The main part of the code is setting all registers and initialising the timer. The original TI code with license can be found here.

 

volatile register uint32_t __R30;
volatile register uint32_t __R31;

void main(void)
{
  /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
  CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

  /* Disable counter */
  CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 0;

  /* Reset Count register */
  CT_IEP.TMR_CNT = 0x0;

  /* Clear overflow status register */
  CT_IEP.TMR_GLB_STS_bit.CNT_OVF = 0x1;

  /* Set compare value */
  CT_IEP.TMR_CMP0 = 0x77359400; // 10 seconds @ 200MHz

  /* Clear compare status */
  CT_IEP.TMR_CMP_STS_bit.CMP_HIT = 0xFF;

  /* Disable compensation */
  CT_IEP.TMR_COMPEN_bit.COMPEN_CNT = 0x0;

  /* Enable CMP0 and reset on event */
  CT_IEP.TMR_CMP_CFG_bit.CMP0_RST_CNT_EN = 0x1;
  CT_IEP.TMR_CMP_CFG_bit.CMP_EN = 0x1;

  /* Clear the status of all interrupts */
  CT_INTC.SECR0 = 0xFFFFFFFF;
  CT_INTC.SECR1 = 0xFFFFFFFF;

 

 

Then I set the GPIO pin (all pins, this is just a tryout), wait for the timer to expire and toggle the GPIO pin.

 

#define PIN    1

// set all GPIOs low
    __R30 = 0x0;

  /* Enable counter */
  CT_IEP.TMR_GLB_CFG = 0x11;

  /* Poll until R31.31 is set */
  do {
    while ((__R31 & 0x80000000) == 0) {
    }
    /* Verify that the IEP is the source of the interrupt */
  } while ((CT_INTC.SECR0 & (1 << 7)) == 0);

  //toggle
   __R30 ^= 1UL << PIN;

 

After that, the program clears up and stops. It's not a blinky, just an output that switches high after 10 seconds. Sorry.

 

  /* Disable counter */
  CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 0x0;

  /* Disable Compare0 */
  CT_IEP.TMR_CMP_CFG = 0x0;

  /* Clear Compare status */
  CT_IEP.TMR_CMP_STS = 0xFF;

  /* Clear the status of the interrupt */
  CT_INTC.SECR0 = (1 << 7);

  /* Halt the PRU core */
  __halt();
}

 

Run It

 

I've reused the TI project PRU_IEP and just added my lines to the source. See this blog for getting started with PRU code compilation in CCS.

Once the code is compiled, move it over to the BB's Linux file system (I'm assuming you moved it to /home/debian/bin).

Then execute these commands to prepare the PRU:

 

# set pin 29 as PRU GPIO out
config-pin P9_29 pruout

#load the firmware to PRU
cp /home/debian/bin/PRU_IEP.out /lib/firmware/PRU_IEP.out
echo 'PRU_IEP.out' > /sys/class/remoteproc/remoteproc1/firmware

#start the program
echo 'start' > /sys/class/remoteproc/remoteproc1/state

 

 

image

image: capture of the timer controlled pin with an ocilloscope

 

If you want to retry, stop the PRU and start it again:

 

echo 'stop' > /sys/class/remoteproc/remoteproc1/state
echo 'start' > /sys/class/remoteproc/remoteproc1/state

 

When finished, set the BB back to default.

 

echo 'stop' > /sys/class/remoteproc/remoteproc1/state
config-pin P9_29 default

.

Attachments:
bb_PRU_TIMER.zip
  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps over 6 years ago +3
    @self-documentation on the part where the timer timeout is detected: This part: /* Poll until R31.31 is set */ do { while ((__R31 & 0x80000000 ) == 0 ) { } The __R31 bit 31 is local interrupt 1: and "…
  • shabaz
    shabaz over 6 years ago +2
    Hi Jan, This is very useful information! It's new to me that the PRU could access a 32-bit timer clocked at 200MHz. That's fantastic.
  • grondak
    grondak over 6 years ago +2
    I last was interested in these PRUs over 5 years ago. They are just as you said: the key to unlock determinism in a Linux system. My application needed to start the timer, then later read the timer value…
  • Jan Cumps
    Jan Cumps over 6 years ago in reply to Jan Cumps

    ... because I need two events to generate a pulse (my own choice - the width duty cycle of a pulse for stepper motor controllers doesn't change the speed - as long as it is long enough),

    and the PRU clock runs 200 MHz,

    If I use a count to 1000 timer:

        CT_IEP.TMR_CMP0 = 0x3E8;

    then I get a 100 kHz timer, with loads of program time to spend on instructions between each slope of the pulse train.

     

    The PRU is different than an interruptible controller.

    It supports interrupts, but they don't change the control flow. That would kill the real-time part, if the controller is asked to spend time in an interrupt handler instead of in the guaranteed tightly timed process.

     

    The trick with the timer in this case is that you can neatly time your code without having to calculate the clock ticks spent in each command in a loop.

    And without having to re-do that each time you change the logic in the loop.

    As long as the time spent by commands executed within one "count" run faster than one count, the timer will act as the guardrail that makes the next loop start nicely on the right tick of the clock. Like old railway clocks.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • clem57
    clem57 over 6 years ago

    Setting a timer for a SBC without a RTC could solve many issues. Thanks for the post Jan Cumps image!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 6 years ago

    @self-documentation #2:

     

    When changing the code to the below snippet, the timer controls the cadence of the code.

    Polling for timer rollover is done in a while loop, and after polling, the interrupt and compare status are reset.

    This causes the timer to control the speed of the program.

    As long as the lines of code after the 2 clear statements and the toggle line don't overrun the period of one timer count, the code runs pitch perfect.

     

    And the runtime of the logic&code added after the toggle will determine the maximum frequency we can afford.

     

     

        while(1) {
    
    
            /* Poll until R31.31 is set */
            do {
                while ((__R31 & 0x80000000) == 0) {
                }
                /* Verify that the IEP is the source of the interrupt */
            } while ((CT_INTC.SECR0 & (1 << 7)) == 0);
    
    
            /* Clear Compare0 status */
            CT_IEP.TMR_CMP_STS = 0x1;
            __delay_cycles(2);
            /* Clear the status of the interrupt */
            CT_INTC.SECR0 = (1 << 7);
    
    
            //toggle
            __R30 ^= 1UL << PIN;
        }

     

    With the 200 MHz clock, I should have enough time to calculate the stepper profile for the remaining steps...

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 6 years ago

    @self-documentation on the part where the timer timeout is detected:

     

    This part:

    1. /* Poll until R31.31 is set */
    2. do { 
    3. while ((__R31 & 0x80000000) == 0) { 
    4.     } 

    The __R31 bit 31 is local interrupt 1:

    image

    and "Host Interrupt 1 is connected to bit 31 in register 31 for PRU0 and PRU1"

    Code is waiting until there's a local interrupt fired.

     

    This part:

    1. /* Verify that the IEP is the source of the interrupt */
    2.   } while ((CT_INTC.SECR0 & (1 << 7)) == 0); 

     

     

    image

    source: https://elinux.org/PRUSSv2_Interrupts

    It also seems to be possible to sleep instead of poll: "and use sleep instruction instead of polling"

    (need to read section 5.3 in the PRU reference and set WAKEUP_EN register).

    I don't know if sleeping is a good idea if multiple motors need to be catered for image

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz over 6 years ago

    Hi Jan,

     

    This is very useful information! It's new to me that the PRU could access a 32-bit timer clocked at 200MHz. That's fantastic.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
<>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube