This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/PROCESSOR-SDK-AM335X: PRU as a standalone microcontroller

Part Number: PROCESSOR-SDK-AM335X


Tool/software: TI C/C++ Compiler

Hello,

I am using the PRU of the AM335x SItara Processor from Linux on the Beaglebone Black and I have a few doubts about the PRU itself.

I would resume my question with: is it possible to use the PRU as a standalone micro-controller ?

To explain better what I mean, I will show the following example which performs the following tasks:

  1. 1 - Toggle the P9_27 GPIO
  2. 1 - Read the P9_28 GPIO
  3. 3 - Send an interrupt event to a Linux program if the P9_28 is at logic state 0.

The PRU Assembly code is the following:

// start of program in pru memory
.origin 0

// program entry point (for a debugger)
.entrypoint start

// 5ns per instruction
#define ins_per_us   200

// two instructions per delay loop
#define ins_per_delay_loop 2

#define delay 1 * (ins_per_us / ins_per_delay_loop) 

// allows notification of program completion
#define PRU0_R31_VEC_VALID 32

// the event number that is sent back
#define PRU_EVTOUT_0 3

#define GER 0x00020010
#define SECR0 0x00020280
#define SECR1 0x00020284

start:
    // turn on the output pin (led on)
    set    r30.t5
    // store the length of the delay in reg0
    mov    r0, delay
    
delayon:

    // decrement reg0 by 1
    sub    r0, r0, 1
    // loop to delayon, unless reg0=0
    qbne delayon, r0, 0
    
ledoff: 

    // clear the output bin (led off)
    clr    r30.t5
    // reset reg0 to the length of the delay
    mov    r0, delay
    
delayoff:
    // decrement reg0 by 1
    sub    r0, r0, 1
    // loop to delayoff, unless reg0=0
    qbne delayoff, r0, 0

    // is the button pressed? if not, loop
    qbbc start, r31.t3

exec_int:

    // notify the calling app that finished
    mov r31.b0, PRU0_R31_VEC_VALID | PRU_EVTOUT_0
    jmp    start

and the C program which uses the prussdrv libraries is:

/** Program to load a PRU program that flashes an LED until a button is
*   pressed. By Derek Molloy, for the book Exploring BeagleBone
*   based on the example code at:
*   processors.wiki.ti.com/.../PRU_Linux_Application_Loader_API_Guide
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <prussdrv.h>
#include <pruss_intc_mapping.h>

#define PRU_NUM	0   // using PRU0 for these examples

typedef enum
{
    false, true
} bool;

int main (void)
{
    int n = 0;
    int res = 0;

    if(getuid()!=0)
    {
        printf("You must run this program as root. Exiting.\n");
        exit(EXIT_FAILURE);
    }

    // Initialize structure used by prussdrv_pruintc_intc
    // PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h
    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;

    // Allocate and initialize memory
    res = prussdrv_init ();
    printf("prussdrv_init = %d\n", res);

    res = prussdrv_open (PRU_EVTOUT_0);
    printf("prussdrv_open = %d\n", res);
    // Map PRU's interrupts
    
    prussdrv_pru_reset (0);
res = prussdrv_pruintc_init(&pruss_intc_initdata); printf("prussdrv_pruintc_init = %d\n", res);
// Load and execute the PRU program on the PRU prussdrv_exec_program (PRU_NUM, "./ledButton.bin"); while (true) { // Wait for event completion from PRU, returns the PRU_EVTOUT_0 number n = prussdrv_pru_wait_event(PRU_EVTOUT_0); printf("EBB PRU program completed, event number %d.\n", n); // prussdrv_exec_program (PRU_NUM, "./ledButton.bin"); } // Disable PRU and close memory mappings prussdrv_pru_disable(PRU_NUM); prussdrv_exit (); return EXIT_SUCCESS; }

The program itself works, the GPIO toggles and the interrupt is sent from the PRU and it's catched from the Linux program, but:

  1. 2 - The PRU is performing a polling on the P9_28 GPIO.
  2. 2 - After one interrupt event is sent from the PRU to Linux, I am not able to sent it again. I have to reload the firmware to the PRU if I want to re-send the interrupt event.

So the final questions are:

  1. 3 - Is it possible to generate an hardware interrupt (like GPIO state change) from the PRU before sending a notification to Linux ? In other words let the PRU in a infinite loop and jump to the interrupt vector if an hardware interrupt is generated.
  2. 3 - Is it possible to re-send the interrupt event to Linux without having to reload the PRU firmware ?

Could you confirm is tasks 1.3 and 2.3 are possible or not ? 

If they are possible I am of course missing some information from the AM335x Techincal Reference manual. In this case could you point me to the right sections or give me some suggestion ?

Thank you.

Regards,

Simon

  • The PRU experts have been notified. They will respond here.
  • Simon,

    1.3 The PRU has to use its interrupts/events as flags. It does not have the ability to jump the program counter to an interrupt vector when an interrupt event occurs. What most PRU firmwares do is similar to how you have your code structured: run in an infinite loop while performing a background task (LED toggling in your case) and then at the top (or bottom) of the loop check the interrupt/event flags to see if other code needs to be run based on external events. Depending on the response rate needed you could also split the background task up and check for the flag several times throughout your program.

    2.3 As I said in the other post that I responded to today, the prussdrv and the Linux driver that goes along with it are no longer supported by TI. However, I think you should be able to clear and then re-enable the interrupt from the PRU using the 'prussdrv_pru_clear_event' function from the API. This should allow the PRU to send the event once again without needing to be reloaded.

    Jason Reeder

    P.S. It is my understanding that the prussdrv API is still fairly widely used over in the BeagleBoard community if you'd like to check over there as well: http://beagleboard.org/discuss