Using the PRU on the Beaglebone Black (information)

Previous Post: Robotics using the Beaglebone Black

Memory Maps and Linker Command Files

There are three areas that interact in memory management of the PRU:

1. The physical memory map of the PRU … as seen from the PRU (see AM335x Sitara Processors Technical Reference Manual (www.ti.com)

2. The Linker Command File (CMD) … see PRU Optimizing C/C++ Compiler (www.ti.com)

3. Directives within the compiled program that reference the CMD file… see PRU Optimizing C/C++ Compiler (www.ti.com)

PRU0 and PRU1 can talk to each other through their shared data memory space.  0x0000_0000 through 0x0000_1fff (8 KB) is PRU0’s memory and 0x0000_2000 through 0x0000_3fff (8 KB) is PRU1’s memory.

PRU0 and PRU1 see the ARM’s shared data memory at 0x0001_0000 through 0x0001_2fff (12 KB).

PRU0 and PRU1 have 8 KB of instruction memory, where executable code should be located.

The ARM sees PRU0’s instruction memory at 0x0003_4000 and PRU1’s instruction memory at 0x0003_8000.  The ARM sees PRU0’s data memory at 0x0000_0000 and PRU1’s data memory at 0x0000_2000.

A typical linker command file might look like this:

-cr

MEMORY

{

PAGE 0: /* instruction memory */

MEM: o = 0x00000000 l = 0x00002000

PAGE 1: /* data memory */

MEM: o = 0x00000000 l = 0x00002000

}

SECTIONS
{

/* initialized memory */

.cinit > MEM, PAGE 1
.data > MEM, PAGE 1
.fardata > MEM, PAGE 1
.init_array > MEM, PAGE 1
.rodata > MEM, PAGE 1
.rofardata > MEM, PAGE 1
.text > MEM, PAGE 0

/* uninitialized memory */

.args > MEM, PAGE 1
.bss > MEM, PAGE 1
.farbss > MEM, PAGE 1
.stack > MEM, PAGE 1
.sysmem > MEM, PAGE 1

}

On some devices, code and data memory are separate and the CMD file is indicating this to the device which writes to those memory regions by the PAGE directive.  PAGE 0 is code memory and PAGE 1 is data memory.

———-

It might be desirable to put some things in special places, for instance registers and starting locations.  In particular, it is often desirable to put the entry point for the code at address 0x0.  This can be done by adding

.text:_c_int00* > 0x0, PAGE 0

to the SECTIONS part of the CMD file

———

Registers are particular sections of memory that need to be accessed quickly and repeatedly.  It is often desirable to place these in specific locations that can be accessed quickly (NEAR memory) and to use strict language in addressing them so that assembly code and c-code can interact.

 

———–

Two special registers, R30 and R31, can be assigned by:

volatile register unsigned int __R30;

volatile register unsigned int __R31;

Enhanced GPIO is connected to pr1_pru0_pru_r31[16:0] and pr1_pru0_pru_r30[15:0].

__R31 is connected to input and INTC (read) and to the INTC controller (write).

Input: bit 31: pru_intr_in[1] (PRU Host interrupt 1 from INTC), bit 30 (PRU Host interrupt 0 from INTC), pru_intr_in[0], bits 29-0: pru<n>_r31_status[29:0] (status inputs from GPI port)

Output: 31-6 and 4 are reserved. bit 5 initiates an interrupt event when set, the vector output is determined from bits 3-0 (vector 0 through 15).

For example: __R31 = 0000 0000 0001 0011b; will create a pulse on pr1_pru_mst_intr[3]_intr_req INTC system event.

On the ARM side, the host talks to the pruss through the uio_pruss driver.  This driver creates 8 files, /dev/uio0 through /dev/uio7.  Looking into the uio_pruss source code, you can find that 3 -> PRU_EVTOUT0 (/dev/uio0), 4 -> PRU_EVTOUT1 (/dev/uio1), …, 10 -> PRU_EVTOUT7 (/dev/uio7), assuming you use the pruss_intc_mapping.h file.

__R30 is connected to output.  In particular,

pr1_pru<0:1>_pru_r30_m = GPOm, where m runs from 0…31.

The pin mapping between pr1_pru<0:1>_pru_r3<0:1>_<0…31> and gpio functions can be found in Table 4-1 in the AM335x Sitara Processors Data Sheet. Table 9-10 in the AM335x Sitara Processors Technical Reference Manual contains the offsets.  These offsets are relative to 0x44e10000; however, the pinctrl driver uses 0x44e10800.  So, 0x800 must be subtracted from the offset in Table 9-10 in order to use it in the DTS file.

The Pad Control Register for input/output pins has the following specification (see Table 9-1 in AM335x Sitara Processors Technical Reference Manual):

Bits 2-0 are the MUXMODE.  This corresponds to the mode column in the following table.

Bits 4-3 determine Pull Selection.  00 = Pulldown selected and activated, 01 = Pulldown selected but not activated, 10 = Pullup selected and activated, 11 = Pullup selected and not activated.

Bit 5 determines I/O type, where 0 is for output only operation and 1 is for input or output operation.

Bit 6 determines slew control (0 = fast, 1 = slow)

For a fast pin (0) with output or input (0) and pullup selected and activated (10) set into mode 5 (101), the Control Register would be 001 0101b = 0x25

 

Pin Name Signal Name Mode Beaglebone Header Offset gpio
pinctrl/pinmux registers: CONTROL_MODULE: 0x44e10800
 ECAP0_IN_PWM0_OUT  pr1_ecap0_ecap_capin_apwm_o  3
 GPMC_A0  pr1_mii_mt1_clk  5 040
 GPMC_A1  pr1_mii1_txd3  5 044
 GPMC_A2  pr1_mii1_txd2  5 048
 GPMC_A3  pr1_mii1_txd1  5 04C
 GPMC_A4  pr1_mii1_txd0  5 050
 GPMC_A6  pr1_mii1_rxd2  5 054
 GPMC_A7  pr1_mii1_rxd1  5 058
 GPMC_A8  pr1_mii1_rxd0  5 05C
 GPMC_A9  pr1_mii1_mr1_clk  5 060
 GPMC_A10  pr1_mii1_rxdv  5 064
 GPMC_A11  pr1_mii1_rxer  5 068
 GPMC_AD8  pr1_mii_mt0_clk  5 020
 GPMC_AD9  pr1_mii0_col  5  P8-13 024  gpio0[23]
 GPMC_AD10  pr1_mii0_txen  5 028
 GPMC_AD11  pr1_mii0_txd3  5 02C
 GPMC_AD12  pr1_mii0_txd2, pr1_pru0_pru_r30_14  5,6  P8-12 030  gpio1[12]
 GPMC_AD13  pr1_mii0_txd1, pr1_pru0_pru_r30_15  5,6  P8-11 034  gpio1[13]
 GPMC_AD14  pr1_mii0_txd0, pr1_pru0_pru_r31_14  5,6  P8-14 (?) 038 gpio1[14]
 GPMC_AD15  pr1_ecap0_ecap_capin_apwm_o, pr1_pru0_pru_r31_15  5,6  P8-15 03C gpio1[15]
 GPMC_BEn1  pr1_mii1_rxlink  5
 GPMC_CLK  pr1_mii1_crs, pr1_mdio_mdclk  4, 5  P8-18(?) 08C gpio2[1]
 GPMC_CSn1  pr1_edio_data_in6, pr1_edio_data_out6, pr1_pru1_pru_r30_12, pr1_pru1_pru_r31_12  3, 4, 5,6  P8-21 080 gpio1[30]
 GPMC_CSn2  pr1_edio_data_out7, pr1_pru1_pru_r30_13, pr1_pru1_pru_r31_13  3, 4, 5,6  P8-20 084 gpio1[31]
 GPMC_CSn3  pr1_mii0_crs, pr1_mdio_data  4, 5 088
 GPMC_WAIT0  pr1_mii1_col  5 070
 GPMC_WPn  pr1_mii1_txen  5 074
 LCD_AC_BIAS_EN  pr1_mii1_crs, pr1_edio_data_in5, pr1_edio_data_out5, pr1_pru1_pru_r30_11 pr1_pru1_pru_r31_11  2, 3, 4, 5, 6  P8-30  0EC gpio2[25]
 LCD_DATA0  pr1_mii_mt0_clk, pr1_pru1_pru_r30_0, pr1_pru1_pru_r31_0  5,6  P8-45 (PWM2B, taken by HDMI) 0A0 gpio2[6]
 LCD_DATA1  pr1_pru1_pru_r30_1, pr1_pru1_pru_r31_1  5, 6  P8-46 (PWM2B, taken by HDMI) 0A4 gpio2[7]
 LCD_DATA2  pr1_pru1_pru_r30_2, pr1_pru1_pru_r31_2  5, 6  P9-30 or P8-43(?) 0A8 gpio2[8]
 LCD_DATA3  pr1_pru1_pru_r30_3, pr1_pru1_pru_r31_3  5, 6  P8-41 (?) 0AC gpio2[9]
 LCD_DATA4  pr1_pru1_pru_r30_4, pr1_pru1_pru_r31_4  5, 6  P8-40 (?) 0B0 gpio2[10]
 LCD_DATA5  pr1_mii0_txd0, pr1_pru1_pru_r30_5, pr1_pru1_pru_r31_5  3, 5, 6  P8-42 0B4 gpio2[11]
 LCD_DATA6  pr1_edio_data_in6, pr1_edio_data_out6, pr1_pru1_pru_r30_6, pr1_pru1_pru_r31_6  2, 4, 5, 6  P8-39 0B8 gpio2[12]
 LCD_DATA7  pr1_edio_data_in7, pr1_edio_data_out7, pr1_pru1_pru_r30_7, pr1_pru1_pru_r31_7  2, 4, 5, 6  P8-39(?) 0BC gpio2[13]
 LCD_DATA8  pr1_mii0_rxd3  5  P8-37(?) 0C0 gpio2[14]
 LCD_DATA9  pr1_mii0_rxd2  5 0C4 gpio2[15]
 LCD_DATA10  pr1_mii0_rxd1  5  P8-36(?) 0C8 gpio2[16]
 LCD_DATA11  pr1_mii0_rxd0  5  P8-34(?) 0CC gpio2[17]
 LCD_DATA12  pr1_mii0_rxlink  5  P8-35(?) 0D0 gpio0[8](?)
 LCD_DATA13  pr1_mii0_rxer  5 0D4
 LCD_DATA14  pr1_mii_mr0_clk  5  P8-31(?) 0D8 gpio0[10](?)
 LCD_DATA15  pr1_mii0_rxdv  5  P8-32(?) 0DC gpio0[11](?)
 LCD_HSYNC  pr1_edio_data_in3, pr1_edio_data_out3, pr1_pru1_pru_r30_9, pr1_pru1_pru_r31_9 3, 4, 5, 6  P8-29 0E4 gpio2[23]
 LCD_PCLK  pr1_mii0_crs, pr1_edio_data_in4, pr1_edio_data_out4, pr1_pru1_pru_r30_10, pr1_pru1_pru_r31_10  2, 3, 4, 5, 6  P8-28 0E8 gpio2[24]
 LCD_VSYNC  pr1_edio_data_in2, pr1_edio_data_out2, pr1_pru1_pru_r30_8, pr1_pru1_pru_r31_8 3, 4, 5, 6  P8-27 0E0 gpio2[22]
 MCASP0_FSX  pr1_pru0_pru_r30_1, pr1_pru0_pru_r31_1  5, 6  P9-29 (PWM0B, in use by HDMI) 194 gpio3[15]
 MCASP0_ACLKR  pr1_pru0_pru_r30_4, pr1_pru0_pru_r31_4  5, 6  P9-42 1A0  gpio3[18]
 MCASP0_AHCLKR  pr1_pru0_pru_r30_3, pr1_pru0_pru_r31_3  5, 6  P9-28 19C  gpio3[17]
 MCASP_AHCLKX  pr1_pru0_pru_r30_7, pr1_pru0_pru_r31_7  5, 6  P9-25 1AC  gpio3[21]
 MCASP0_ACLKX  pr1_pru0_pru_r30_0, pr1_pru0_pru_r31_0  5, 6  P9-31 (PWM0A, in use by HDMI)  190  gpio3[14]
 MCASP0_FSR  pr1_pru0_pru_r30_5, pr1_pru0_pru_r31_5  5, 6  P9-25 (?)
 MCASP_AXR0  pr1_pru0_pru_r30_2, pr1_pru0_pru_r31_2 5, 6  P9-30  198 gpio3[16]
 MCASP0_AXR1  pr1_pru0_pru_r30_6, pr1_pru0_pru_r31_6  5, 6  P9-41  1A8  gpio3[20]
 MMC0_CMD  pr1_pru0_pru_r30_13, pr1_pru0_pru_r31_13  5, 6  not mapped
 MMC0_CLK  pr1_pru0_pru_r30_12, pr1_pru0_pru_r31_12  5, 6  not mapped
 MMC0_DAT0  pr1_pru0_pru_r30_11, pr1_pru0_pru_r31_11  5, 6  not mapped
 MMC0_DAT1  pr1_pru0_pru_r30_10, pr1_pru0_pru_r31_10  5, 6  not mapped
 MMC0_DAT2  pr1_pru0_pru_r30_9, pr1_pru0_pru_r31_9  5, 6 not mapped
 MMC0_DAT3  pr1_pru0_pru_r30_8, pr1_pru0_pru_r31_8  5, 6  not mapped
 SPIO_SCLK  pr1_uart0_cts_n, pr1_edio_sof  4, 5  P9-20, 22
SPIO_CS0  pr1_uart0_txd, pr1_edio_data_in1, pr1_edio_data_out1  4, 5, 6  P9-17
 SPIO_D0  pr1_uart0_rts_n, pr1_edio_latch_in  4, 5  P9-19, 21
 SPIO_D1  pr1_uart0_rxd, pr1_edio_data_in0, pr1_edio_data_out0  4, 5, 6  P9-18
 UART0_TXD  pr1_pru1_pru_r30_15, pr1_pru1_pru_r31_15 4, 5
 UART0_CTSn  pr1_edc_sync0_out  6
 UART0_RXD  pr1_pru1_pru_r30_14, pr1_pru1_pru_r31_14  5, 6
 UART0_RTSn  pr1_edc_sync1_out  6
 UART1_TXD  pr1_uart0_txd, pr1_pru0_pru_r31_16  5, 6  P9-24
 UART1_RXD  pr1_uart0_rxd, pr1_pru1_pru_r31_16  5, 6  P9-26
 UART1_RTSn  pr1_uart0_rts_n, pr1_edc_latch1_in  5, 6
 UART1_CTSn  pr1_uart0_cts_n, pr1_edc_latch0_in  5, 6
 XDMA_EVENT_INTR0  pr1_pru1_pru_31_16  5  not mapped
 XDMA_EVENT_INTR1  pr1_pru0_pru_r31_16  5  not mapped

 

Writing to certain pins in R31 allows communication with the INTC controller (see section 4.4.1.2 of the TRM).

———-

Output pins lie outside the PRU’s memory space and have to use the keyword ‘peripheral’ to interact.  They also need the cregister attribute (in c-code).  These pins also have to be allocated for use in the dtbo file.

 

The pin mapping between registers and devices can be found in the AM335x Sitara Processors Technical Reference Manual in Table 2-3. L4_PER Peripheral Memory Map.  For instance, the LEDs on the board are located in gpio1, pins 21, 22, 23, and 24.  The function for gpio1 is mapped to addresses 0x4804_c000.

 

The BB-BONE-PRU-01 allocates P9.27 to pru0. (gpio3 – 19)

According to Table 11 in the Beaglebone Black System Reference Manual, the following pins are available on P8 or P9: gpio1 – 12, 13, 14, 15, 30, 31; gpio2 – 6, 7, 8 ,9, 10, 11, 12, 13, 22, 34, 24; gpio3 – 19, 21; I2C1 – SCL, SDA; I2C2 – SCL, SDA; UART2 – TXD, RXD; UART1 – TXD, RXD; SPI1 – CS0, D0, D1, SCLK.

————

Although several pins are directly tied to the PRU, the PRU can still access all resources available to the ARM through the memory interface.  Other resources cannot be updated as quickly as the direct pins.  In mechanical control applications, this shouldn’t prove to be a problem.

 

Pins are multiplexed.  Due to the vast number of options, the AM335x devices have eight (8) pin configurations. The Pad Control Registers determine which pin configuration is used. The MUXMODE field sets which of the 8 configs you desire (0…7).  It appears that the dtbo file is setting these parameters when you allocate hardware resources, so you don’t have to build this into code.

 

The AM335x Sitara Processors Data Sheet contains the mode mapping for all the pins in Table 4.1.  This information is also available in the Beagleboard: Cape Expansion Headers section of the Beaglebone wiki at elinux.org for P8 and P9 in Tables 10 and 11 and in the unlabelled Figures after “65 Possible Digital I/Os.”

The cape manager is a program that works with the kernel to modify device parameters without recompiling the kernel or installing custom kernel modules.

Device Tree (DTS) fragments are located in https://github.com/beagleboard/linux/tree/3.8/firmware/capes and can be converted to dtbo files using the program dtc.  The dtbo files should be copied to the /lib/firmware directory on the Beaglebone.

 

The wiki at eLinux.org, “Beaglebone and the 3.8 kernel”  provides a generic DTS file along with an explanation of what and why it is.

———-

Getting the pru up and going requires the pru to clear the STANDBY_INIT bit on the PRU_ICSS_CFG register (0x00026000 in PRU and ARM memory spaces).  This can be set up by adding the line to PAGE 1 of the MEMORY part of the cmd file:

PRU_ICSS_CFG: o=0x00026000 l = 0x00000100 CREGISTER=4

Create a header file (pru_cfg.h) to define the bits and bytes in the register (recommended for each register that you use):

typedef struct{

volatile unsigned int REVID;

union{

volatile unsigned int SYSCFG;

volatile struct{

unsigned IDLE_MODE: 2;

unsigned STANDBY_MODE: 2;

unsigned STANDBY_INIT: 1;

unsigned SUB_MWAIT: 1;

unsigned reserved6_31: 26;

}SYSCFG_bits;

}

/*put the rest of the variables for each field in the register here. See Table 4-207 in the AM335x Sitara Processors Technical Reference Manual for all the bit and byte definitions for the register.*/

} pruCfg;

In your PRU c-file, declare the global variable:

#include “pru_cfg.h”

volatile pruCfg C4 __attribute__((cregister(“PRU_ICSS_CFG”,near),peripheral));

At the top of your main() code, clear the bit:

C4.SYSCFG_bits.STANDBY_INIT=0;

Posted in: Robotics

Comments are closed.