Skip to content

Instantly share code, notes, and snippets.

@shirriff
Last active March 16, 2024 13:51
Show Gist options
  • Save shirriff/2a7cf2f1adb37011da827f1c7f47b992 to your computer and use it in GitHub Desktop.
Save shirriff/2a7cf2f1adb37011da827f1c7f47b992 to your computer and use it in GitHub Desktop.
Example code using a timer with the BeagleBone Black's PRU microcontroller. This code generates 5 pulses with 100ns width.
/*
* Demonstration of the BeagleBone's PRU, using a timer.
* Ken Shirriff, http://righto.com
*/
#include <stdint.h>
#define DELAY_NS 100 // Use 500000000 for 0.5 second delay
#define WRITE_PIN 15 /* P8_11, Ethernet output data, pr1_PRU0_pru_r30_15 */
// PRU Interrupt control registers
#define PRU_INTC 0x00020000 // Start of PRU INTC registers TRM 4.3.1.2
#define PRU_INTC_GER ((volatile uint32_t *)(PRU_INTC + 0x10)) // Global Interrupt Enable, TRM 4.5.3.3
#define PRU_INTC_SICR ((volatile uint32_t *)(PRU_INTC + 0x24)) // Interrupt, TRM 4.5.3.6
#define PRU_INTC_GPIR ((volatile uint32_t *)(PRU_INTC + 0x80)) // Interrupt, TRM 4.5.3.11
// PRU ECAP control registers (i.e. PWM used as a timer)
#define ECAP 0x00030000 // ECAP0 offset, TRM 4.3.1.2
// Using APWM mode (TRM 15.3.2.1) to get timer (TRM 15.3.3.5.1)
#define ECAP_TSCTR ((volatile uint32_t *)(ECAP + 0x00)) // 32-bit counter register, TRM 15.3.4.1.1
#define ECAP_APRD ((volatile uint32_t *)(ECAP + 0x10)) // Period shadow, TRM 15.3.4.1.5, aka CAP3
#define ECAP_ECCTL2 ((volatile uint32_t *)(ECAP + 0x2a)) // Control 2, TRM 15.3.4.1.8
#define ECAP_ECEINT ((volatile uint16_t *)(ECAP + 0x2c)) // Enable interrupt, TRM 15.3.4.1.9
#define ECAP_ECCLR ((volatile uint16_t *)(ECAP + 0x30)) // Clear flags, TRM 15.3.4.1.11
// R30 is the GPIO register
// R31 is the interrupt register
volatile register unsigned int __R31, __R30;
// Forward definitions
void init_pwm();
void wait_for_pwm_timer();
void main() {
init_pwm();
int i;
for (i = 0; i < 5; i++) {
wait_for_pwm_timer();
__R30 = 1 << WRITE_PIN;
wait_for_pwm_timer();
__R30 = 0;
}
__R31 = 35; // Interrupt to host
__halt();
}
// Initializes the PWM timer, used to control output transitions.
// Every DELAY_NS nanoseconds, interrupt 15 will fire
inline void init_pwm() {
*PRU_INTC_GER = 1; // Enable global interrupts
*ECAP_APRD = DELAY_NS / 5 - 1; // Set the period in cycles of 5 ns
*ECAP_ECCTL2 = (1<<9) /* APWM */ | (1<<4) /* counting */;
*ECAP_TSCTR = 0; // Clear counter
*ECAP_ECEINT = 0x80; // Enable compare equal interrupt
*ECAP_ECCLR = 0xff; // Clear interrupt flags
}
// Wait for the PWM timer to fire.
// see TRM 15.2.4.26
inline void wait_for_pwm_timer() {
while (!(__R31 & (1 << 30))) {} // Wait for timer compare interrupt
*PRU_INTC_SICR = 15; // Clear interrupt
*ECAP_ECCLR = 0xff; // Clear interrupt flags
}
@mrazeja7
Copy link

Hello, how can I compile and run this snippet on my Beaglebone Black? I'm sorry for posing such a novice question. I've tried searching your blog, but couldn't find any solutions. Thanks

@Palpatineli
Copy link

Hello, how can I compile and run this snippet on my Beaglebone Black? I'm sorry for posing such a novice question. I've tried searching your blog, but couldn't find any solutions. Thanks

I'm not the author but you essentially download http://www.ti.com/tool/PRU-CGT and use a makefile from one of the PRU example such as those examples in the sdk http://www.ti.com/tool/PROCESSOR-SDK-AM335X

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment