Last active
March 16, 2024 13:51
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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