Andrew B. Wright, S. M. ’88, Ph. D.
R30 and R31 are tied to gpio resources. However, with the Beaglebone, many of the pins carrying these signals are multiplexed with other signals, in particular the HDMI. For example, PRU1 has no signals brought out to the P8 or P9 connectors that can be accessed with the cape-universal default cape. In order to get these pins, you have to unload the default cape and write a custom dts file. These aren’t unachievable tasks, but they make it difficult to use the PRU1.
If you want to use as many signals that aren’t tied up by default (i.e. avoid unloading the eMMC or HDMI device tree overlays), then you may have to go “off-PRU” to get the signals.
There are many, many tutorials on how to use R30 to access digital outs and R31 to access digital ins. Not so much on getting to the GPIO in general.
It’s actually extremely easy with all the work in the previous blogs. But, that one last piece of info took a while to ferret out of the TRM.
My main reason for going “off-PRU” came from wanting to use only P9 for CASSY. In addition to avoiding those reserved signals, it makes the wiring of the CAPE much less convoluted.
For this project, the following signals will be allocated:
|P9.22||EHPWM0A||Right Motor Plus (6 ma)||0x154||0x3|
|P9.21||EHPWM0B||Right Motor Minus (6 ma)||0x150||0x3|
|P9.12||GPIO1 ||Right Motor Plus Direction (6 ma)||0x078||0x7|
|P9.15||GPIO1 ||Right Motor Minus Direction (6 ma)||0x040||0x7|
|P9.14||EHPWM1A||Left Motor Plus (6 ma)||0x048||0x6|
|P9.16||EHPWM1B||Left Motor Minus (6 ma)||0x04c||0x6|
|P9.11||GPIO0 ||Left Motor Plus Direction (6 ma)||0x070||0x7|
|P9.13||GPIO0 ||Left Motor Minus Direction (6 ma)||0x074||0x7|
|P9.30||PRU0 R31 ||Right Encoder Channel A (6 ma)||0x198||0x26|
|P9.27||PRU0 R31 ||Right Encoder Channel B (6 ma)||0x1a4||0x26|
|P9.24||PRU0 R31 ||Left Encoder Channel A (4 ma)||0x184||0x26|
|P9.42||PRU0 R31 ||Left Encoder Channel B (6 ma)||0x1a0||0x26|
|P9.39||Analog In0 (25 ma)||Inverted Pendulum Potentiometer||0x20|
|P9.40||Analog In1 (25 ma)||unused||0x20|
|P8.7||gpio2 ||Left Front Bumper||
|P8.8||gpio2 ||Right Front Bumper||0x094||0x27|
|P8.9||gpio2 ||Left Rear Bumper||
|P8.10||gpio2 ||Right Rear Bumper||
|P9.37||Analog In2 (25 ma)||unused||0x20|
|P9.38||Analog In3 (25 ma)||unused||0x20|
|P9.33||Analog In4 (25 ma)||unused||0x20|
|P9.32||Analog Vdd (for pot)|
|P9.7,8||Sys 5V (for logic power, optoisolator, encoder)|
|P9.23||GPIO1 ||Cape enable (mainly the motors)||0x044||0x7|
|P9.1, 2, 43, 44, 45, 46||Digital Ground|
|P9.17||gpio0 , i2c1 – scl||0x15C||0x72|
|P9.18||gpio0 , i2c1 – sda||0x158||0x72|
|Pins in use by HDMI or other||P9.25||P9.28||P9.29||P9.31 P9.41 P9.19 P9.20|
In order to get to the GPIO registers, define a header file, pru_gpio.h,
In a real application, bits wouldn't be set or cleared all the same. If you wanted to set only bit 16 on gpio1, the command would be
GPIO1.SETDATAOUT = 1<<16; .
The following table lists pins on the headers that are not part of the CASSY project, but which have been tested. It is a difficult process to get access to the pins, especially considering that many are in use by default. So, when the task has been done, best to write it down for later consumption.
|P8.20||GPMC_CSn2 carries GPIO1 ||in use by BB-BONE-EMMC-2G||0x084||0x7|
|P8.19||GPMC_AD8 carriers gpio0 ||speaker||0x020||0x7|
Access to the gpio control registers is a bit tricky. The example, /usr/lib/ti/pru-software-support-package/examples/am335x/PRU_access_const_table, gives an idea of the syntax required to access registers off the PRU.
#define CM_PER_BASE ((volatile uint8_t *)(0x44E00000))
volatile uint8_t *ptr_cm;
ptr_cm = CM_PER_BASE;
ptr_cm[SPI0_CLKCTRL] = ON;
gets you to the register base.
The gpio registers can be accessed by:
volatile pruGPIO *GPIO0 = (volatile pruGPIO *)(0x44e07000);
volatile pruGPIO *GPIO1 = (volatile pruGPIO *)(0x4804c000);
volatile pruGPIO *GPIO2 = (volatile pruGPIO *)(0x481ac000);
volatile pruGPIO *GPIO3 = (volatile pruGPIO *)(0x481ae000);
where the pruGPIO typedef is defined in pru_gpio.h.
To access the pin for this project, P8.7, use the config-pin utility (added to the Makefile):
config-pin P8.7 gpio
The ARM side program has been modified to use PRU1 instead of PRU0. This will allow the gpio pin to be toggled in real-time. The resource table is the same used in the previous examples. The linker command file is the same used in previous examples, but renamed as gpio.cmd.
The communication file, pru_comm.c, has seen some reorganization. The change in logic allows the main code to call just one subroutine, rather than three.
The state machine to process actions is updated to use an enum with the enumerated states.
In previous versions of the OS, gpio2 and gpio3 were not enabled at boot. The CM_PER register had to be adjusted to activate these modules. However, in the current version, all four gpio modules are active by default.
With the remoteproc interface, passing data back and forth is much easier. As an aside, here is a routine that allows registers to be read and passed to the arm. (coming soon)
Before you can access the pins, you also have to add them to your dts file:
"P9.11", //uart4_rxd ... gpio0 ... 0x7 ... gpmc_wait0
"P9.12", //GPIO1_28 ... 0x7 ... gpmc_ben1
"P9.13", //uart4_txd ... gpio0 ... 0x7 ... gpmc_wpn
"P9.15", //gpio1_16 ... 0x7 ... gpmc_a0
target = <&am33xx_pinmux>;
pinctrl-single,pins = < 0x070 0x7 //P9.11 0x078 0x7 //P9.12 0x074 0x7 //P9.13 0x040 0x7 //P9.15 >;
You almost certainly already have entries in your dts file. The above entries would patch into the appropriate fragments.