PRU Linux Application Loader API Guide

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

The PRUSSDRV User Space Library contains APIs that support the following:

  • Basic PRU control (i.e. enable/disable/reset PRU)
  • Helper functions (i.e. load and execute code in PRU)
  • Memory mapping of PRU/L3/External memories
  • PRU and Host event management (i.e. map sys_evt/channel/hosts in PRU INTC, generate interrupts, wait for occurrence of an event, and acknowledge interrupts)


The source code for the PRUSSDRV library is included in the PRU_SW Project (under pru_sw/trunk/app_loader/interface/prussdrv.c).


API Descriptions

The functions provided by the PRUSSDRV library are described below.

prussdrv_init

Initializes and allocates memory for the PRU Subsystem driver. This is a required function call.

    Function declaration:         int prussdrv_init (void) 
        
    Example function call:        prussdrv_init ( ); 

prussdrv_open

Opens an event out and initializes memory mapping. This is a required function call. The input is a pru_evtout_num (PRU_EVTOUT_0 - PRU_EVTOUT_7) corresponding to Host2 - Host9 of the PRU INTC. If no events are required for the user code, choose PRU_EVTOUT_0 for the input parameter. Otherwise, call this function for each event required by the user code. Note if multiple events are used, this function is called multiple times.

    Function declaration:         int prussdrv_open (unsigned int pru_evtout_num) 
        
    Example function call:        prussdrv_open ( PRU_EVTOUT_0 );  

prussdrv_pru_reset

Resets the PRU by invoking a soft reset in the PRU Control Register.

    Function declaration:         int prussdrv_pru_reset (unsigned int prunum)  
        
    Example function call:        prussdrv_pru_reset ( 0 );  //Resets PRU0      

prussdrv_pru_disable

Disables the PRU by writing 0 to the enable bit of the PRU Control Register.

    Function declaration:         int prussdrv_pru_disable (unsigned int prunum);  
        
    Example function call:        prussdrv_pru_disable ( 0 );  //Disables PRU0 

prussdrv_pru_enable

Enables the PRU by writing 1 to the enable bit of the PRU Control Register.

    Function declaration:         int prussdrv_pru_enable (unsigned int prunum);  
        
    Example function call:        prussdrv_pru_enable ( 0 );  //Enables PRU0 

prussdrv_pru_write_memory

Writes to either PRU Data RAM or Instruction RAM. Selects type of memory writing to and writes content at memarea pointer into memory. This function requires the input parameters described below:

1. pru_ram_idis defined within PRUSSDRV as:
#define PRUSS0_PRU0_DATARAM 0
#define PRUSS0_PRU1_DATARAM 1
#define PRUSS0_PRU0_IRAM 2
#define PRUSS0_PRU1_IRAM 3
2. wordoffset is the offset from *memarea.
3. *memarea is a pointer to the starting address where data/ content is stored.
4. bytelength is the size of the content being written to memory.
    Function declaration:         int prussdrv_pru_write_memory (unsigned int pru_ram_id, unsigned int wordoffset, unsigned int *memarea,  unsigned int bytelength); 
       
    Example function call:        prussdrv_pru_write_memory(PRUSS0_PRU0_IRAM, 0, (unsigned int *) fileDataArray, fileSize); 

prussdrv_pruintc_init

Initializes and enables the PRU interrupt controller. The input is a structure of arrays that determine which system events are enabled and how each is mapped to a host event. This structure (PRUSS_INTC_INITDATA) is defined in pruss_intc_mapping.h and can be modified by the user. Below is the PRUSS_INTC_INITDATA definition and description of each array in the structure:

#define PRUSS_INTC_INITDATA { \
{ PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT, -1 }, \
{ {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0},
{ARM_PRU1_INTERRUPT, CHANNEL1}, {-1,-1}}, \
{ {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} }, \
(PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \
} \
Array 1: enables the system event numbers listed
Array 2: assigns system event numbers to channel numbers
Array 3: links channel numbers to host numbers
Array 4: creates mask to enable host interrupts (or event out numbers)
    Function declaration:         int prussdrv_pruintc_init (tpruss_intc_initdata *prussintc_init_data); 
        
    Example function call:        #include <pruss_intc_mapping.h>
                                  void main (void) { ...
                                       tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
                                       prussdrv_pruintc_init(&pruss_intc_initdata);
                                  }	

prussdrv_map_l3mem

Maps the L3 memory to input pointer. Memory is then accessed by an array.

    Function declaration:         int prussdrv_map_l3mem (void **address);  
        
    Example function call:        unsigned int *l3mem;
                                  prussdrv_map_l3mem(&l3mem); 


prussdrv_map_extmem

Maps the DDR external memory to input pointer. Memory is then accessed by an array. Note the base address of prussdrv_map_extmem is 0xC1000000 (not 0xC0000000).

    Function declaration:         int prussdrv_map_extmem (void **address);  
        
    Example function call:        unsigned int *extmem;
                                  prussdrv_map_extmem(&extmem); 

prussdrv_map_prumem

Maps the PRU DRAM memory to input pointer. Memory is then accessed by an array. Minimum one event needs to be opened to access memory map. Call this function (prussdrv_map_prumem()) after the prussdrv_open(PRU_EVTOUT_x) function.

    Function declaration:         int prussdrv_map_prumem (unsigned int pru_ram_id, void **address);  
        
    Example function call:        unsigned int *pruDataMem;
                                  prussdrv_map_prumem (&pruDataMem); 

prussdrv_get_phys_addr

Pass in a PRU/L3/external memories pointer, and returns the corresponding physical address.

    Function declaration:         unsigned int prussdrv_get_phys_addr (void *address);  
        
    Example function call:        unsigned int phys_addr;
                                  phys_addr = prussdrv_get_phys_addr (l3mem); //l3mem is a mmap returned value 

prussdrv_get_virt_addr

Pass in a PRU/L3/external memory physical address, and returns a pointer containing the corresponding virtual address.

    Function declaration:         void *prussdrv_get_virt_addr (unsigned int phyaddr)  
        
    Example function call:        void *virt_addr;
                                  unsigned int l3_phys_addr = 0x8000000;
                                  virt_addr = prussdrv_get_virt_addr (l3_phys_addr);

prussdrv_pru_wait_event

Waits for PRU event out.

    Function declaration:         int prussdrv_pru_wait_event (unsigned int pru_evtout_num);  
        
    Example function call:        prussdrv_pru_wait_event ( PRU_EVTOUT_0 ); 

prussdrv_pru_send_event

Sends system event to PRU.

    Function declaration:         int prussdrv_pru_send_event (unsigned int eventnum);  
        
    Example function call:        prussdrv_pru_send_event ( 32 ); 

prussdrv_pru_clear_event

Clears system event.

    Function declaration:         int prussdrv_pru_clear_event (unsigned int eventnum);  
        
    Example function call:        prussdrv_pru_clear_event ( 32 ); 

prussdrv_pru_send_wait_clear_event

Sends system event to PRU, waits for PRU event out, and clears system event.

    Function declaration:         int prussdrv_pru_send_wait_clear_event  (unsigned int send_eventnum, unsigned int pru_evtout_num, unsigned int ack_eventnum);
        
    Example function call:        prussdrv_pru_send_wait_clear_event  ( 32, PRU_EVTOUT_0, 32); 

prussdrv_exit

Releases PRUSS clocks and disables prussdrv module.

    Function declaration:         int prussdrv_exit (void);
        
    Example function call:        prussdrv_exit ( ); 

prussdrv_exec_program

Executes a binary file of opcodes on the PRU using the following steps:

  1. Disable PRU
  2. Write contents to PRU iRAM
  3. Enable PRU to begin executing instructions stored in iRAM
    Function declaration:         int prussdrv_exec_program (int prunum, char *filename);
        
    Example function call:        prussdrv_exec_program ( 0, "./PRU_example.bin"); 

prussdrv_start_irqthread

Initializes interrupt handler (or IRQ thread) for particular event. This function requires the following input parameters:

1. pru_evtout_num: the event number associated with (or hooked to) the interrupt handler.
2. priority: an integer, where a lower pririty number is given higher priority.
3. irqhandler: the interrupt handler name.
    Function declaration:         int prussdrv_start_irqthread (unsigned int pru_evtout_num,  int priority, function_handler irqhandler);

        
    Example function call:        #include pthread
                                  
                                  void *pruevtout0_thread(void *arg) {       // Example interrupt handler thread
                                     do {
                                         prussdrv_pru_wait_event (PRU_EVTOUT_0);
                                         // Handle event
                                         prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
                                     } while (1);
                                  }
                                  
                                  void main (void) { ...
                                         prussdrv_start_irqthread (PRU_EVTOUT_0, sched_get_priority_max(SCHED_FIFO) - 2, pruevtout0_thread);
                                  } 


Skeleton Application Code

The following is a skeleton application code that uses the PRUSSDRV APIs to load and execute a set of instructions to the PRU and handle an PRU-generated interrupt.

   /* Driver header file */
   #include <prussdrv.h>
   #include <pruss_intc_mapping.h> 
   
   #define PRU_NUM 	0
   
   /* IRQ handler thread */
   void *pruevtout0_thread(void *arg) {
       do {
          prussdrv_pru_wait_event (PRU_EVTOUT_0);
          prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT);
       } while (1);
   }
   
   void main (void)
   {
       /* 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 */
       prussdrv_init ();		
       prussdrv_open (PRU_EVTOUT_0);
       
       /* Map PRU's INTC */
       prussdrv_pruintc_init(&pruss_intc_initdata);
       
       /* Load and execute binary on PRU */
       prussdrv_exec_program (PRU_NUM, "./PRU_example.bin");
       
       /* Wait for event completion from PRU */
       prussdrv_pru_wait_event (PRU_EVTOUT_0);  // This assumes the PRU generates an interrupt 
                                                // connected to event out 0 immediately before halting
   
       /* Disable PRU and close memory mappings */
       prussdrv_pru_disable(PRU_NUM); 
       prussdrv_exit ();
    }