Beaglebone: Inputs: Toggling R30, accessing GPIO and PWMs (obsolete)

Andrew B. Wright, Ph. D., SM ’88

12/31/2016

The 4.1+ kernel has seen significant changes in how the cape manager system works.  This system is still undergoing revisions, so some of the work-arounds that are presented in this blog will be superseded by a permanent solution in the not-too-distant future.  However, this appears to be the direction that the development of the beaglebone is going, so things should only get better over time.

The new system uses a universal cape device tree in preference to individually designed devices trees.  It uses the config-pin utility to choose amongst the options defined in that overlay.

As of this writing, cape-universaln is enabled by default.  Unfortunately, this does not allow the setting of the hdmi pins.  So, if you want to have access to pins 27 through 40 on the P8 connector, you need to enable the cape-univerala overlay.

Edit /boot/uEnv.txt to change:

cmdline=coherent_pool=1M quiet cape_universal=enable

to

cmdline=coherent_pool=1M quiet

In other words, drop the cape_universal=enable from the cmdline.

Add the line (towards the bottom of the file, after the cmdline statement):

cape_enable=bone_capemgr.enable_partno=cape_universala,<any other cape>

You might want the <any other cape> to get things such as a2d converters, i2c devices, etc. to work.  Perhaps in those cases, cape_universala will get r done.  Time will tell.  If you develop a custom cape, this would be the place for your overlay.

Set up the pin with config-pin

config-pin P8.13 gpio

Find the correct gpio number with

config-pin -i P8.13

which tells that the Kernel GPIO id: 23.

Set up the direction through the gpio interface

echo “out” > /sys/class/gpio/gpio23/direction

Confirm the direction with

config-pin -q P8.13

Toggle the pin with

echo “1” > /sys/class/gpio/gpio23/value

and

echo “0” > /sys/class/gpio/gpio23/value


Here is a little c-language program that toggles both pin 13 and pin 23 on the P8 header.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/poll.h>

int open_gpio(int num){
 int fd;
 char str[50];

 sprintf(str,"/sys/class/gpio/gpio%d/direction",num);
 fd = open(str, O_RDWR);
 if(fd < 0){ printf("no go on gpio%d\n",num); return(-1);}
 write(fd,"out",3);
 return(fd);
}

int open_gpio_value(int num){
 int fd;
 char str[50];

 sprintf(str,"/sys/class/gpio/gpio%d/value",num);
 fd = open(str, O_RDWR);
 if(fd < 0){ printf("no go on gpio%d value\n",num); return(-1);}
 return(fd);
}

int close_gpio(int fd){
 write(fd,"in",2);
 close(fd);
}

int main(void)
{
 for(j=0;j<10;j++){
 write(pin_gpio86_value.fd,"1",1);
 write(pin_gpio23_value.fd,"1",1);
 for(i=0;i<100000;i++);
 write(pin_gpio86_value.fd,"0",1); 
 write(pin_gpio23_value.fd,"0",1);
 for(i=0;i<100000;i++);
 }

 close_gpio(pin_gpio86_direction.fd);
 close(pin_gpio86_value.fd);
 close_gpio(pin_gpio23_direction.fd);
 close(pin_gpio23_value.fd);

 return(0);
}

 

Here is the makefile to go along with it.

toggle: toggle.c
	gcc toggle.c -o toggle
install:
	config-pin P8.13 gpio
	config-pin P8.27 gpio

I added a section in the makefile, make install, to do the config-pin statements for you.  These can be done automatically at boot-up, but this test is just a throw-away test, and you may want to do other things with those pins.


Now, to change P8.13 to a pwm.

config-pin P8.13 pwm

P8.13 is EHRPWM2B, which is located at address 48304200.  According to my friend, internets, the pwm’s do not get placed in the file system in the same locations at every boot.  So, you cannot (necessarily) echo  “1” to /sys/class/pwm/pwmchip6/export and always get P8.13’s pwm.

I tracked it down in /sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchipX/pwm1.

The X is what might get assigned at each boot differently (0, 2, 3, 6), allegedly (I have not tested).  Nonetheless, you can open/read each possibility and take the one that works.

Change the c-code to the following:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/poll.h>

int main(void)
{
 struct pollfd pin_gpio23_value,pin_gpio23_direction;
 struct pollfd x;
 
 int i;
 int result = 0;
 char str[80];
  for(i=0;i<=6;i++){
 sprintf(str,"/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip%d/export",i);
 if((x.fd=open(str,O_WRONLY)) >= 0){
 write(x.fd,"1",1);
 close(x.fd);
 sprintf(str,"/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip%d/pwm1/period",i);
 if((x.fd=open(str,O_RDWR)) >= 0){
 write(x.fd,"1000000",7); //1000000 ns period = 1 ms
 close(x.fd);
 }
 sprintf(str,"/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip%d/pwm1/duty_cycle",i);
 if((x.fd=open(str,O_RDWR)) >= 0){
 write(x.fd,"200000",6);
 close(x.fd);
 }
 sprintf(str,"/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip%d/pwm1/enable",i);
 if((x.fd=open(str,O_RDWR)) >= 0){
 write(x.fd,"1",1);
 close(x.fd);
 }
 }
 }
 return 0;
}

 

Here’s an updated Makefile with a different ‘install’ line.

toggle: toggle.c
	gcc toggle.c -o toggle
install:
	config-pin P8.13 pwm

For completeness, here’s a table of all the PWM on the header, their gpio entry, and the location in the file system.

PWM Name File System Location Header Pin
EHRPWM2B (pwm1)
/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchipX
P8.13 (23), P8.46
EHRPWM2A (pwm0)
/sys/devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchipX
P8.19 (22), P8.45
EHRPWM1A (pwm0) /sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchipX P8.36, P9.14
EHRPWM1B (pwm1) /sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchipX P8.34, P9.16
EHRPWM0A (pwm0) /sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchipX P9.22, P9.31
EHRPWM0B ) (pwm1) /sys/devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchipX P9.21, P9.29
ECAPPWM0 /sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchipX (?) P9.42
ECAPPWM2 /sys/devices/platform/ocp/48304000.epwmss/48304100.ecap/pwm/pwmchipX (?) P9.28

Analog to digital convertors

1/2/2017

This belongs in a separate blog, but, I have this page open to edit.  Maybe this is the documentation.

To get the adcs working.

Load the BB-ADC overlay (echo BB-ADC > /sys/devices/platform/bone_capemgr/slots).

Look in /sys/devices/platform/ocp/44e0d000.tscadc/TI-am335x-adc/iio:device0 for the sub-files.

This is also linked under /sys/bus/iio/devices.

In /sys/bus/iio/devices/iio:device0/buffer are a few files that enable sampling into a buffer:

enable  … echo 1 to start conversion

length … echo <number of samples>

watermark … not sure what this is

In /sys/bus/iio/devices/iio:device0/scan_elements are a few files which set up the channels to sample and the sequence:

in_voltage0_en   … echo 1 to enable this channel (has to be done before enable)

in_voltage0_index … I think this is the order of sampling

Then /dev/iio:device0 will have the data.

Not sure how to update the sample rate or what the sample rate is, but the documentation says 200 kSamples per Second.

The documentation points you towards an example called generic_buffer.c.  As of the 4.1 kernel, this appears to have disappeared.  Go to the beaglebone black debian kernel sources depository to check it out.

This example will not work on the 4.1+ adc driver, where the trigger does not appear to be available.  However, it gives some insight on how to write a code to read and parse the adcs.

More to come …


Some stuff about ROS.

12/29/2016

With 4.1 and later, there are universal capes.  See here for some details.

Here are some migration notes.

This seems to be in rapid development, so, go to /opt/source/beaglebone-universal-io directory on your beaglebone and type

git pull origin master

This should get you the latest capes.  I did not have any luck with cape-universalh.  I could get things to load with the steps that follow, but universalh did not work even then.  So, I think I would forgo the step of getting the latest and greatest.  Perhaps the very latest debian has more things fixed than my current version, 4.4.9-ti-r25.

However, if these matters are on that much of a bleeding edge, it might be better to wait.

So, I started using cape-universala, which loads at least.  I noted that config-pin P8.27 gpio works, but that the state entry that config-pin uses to provide information to the user does not get updated.  So, cape-universala is a bit buggy too.

Why do I want the HDMI pins?  To get access to as much pru pins as possible.


Allegedly,

config-pin overlay cape-universalh

for example, will give you the cape with emmc pins left out.  But, it fails.

More allegedly, you can edit /boot/uEnv.txt to load the cape-universalh instead of cape-universaln, but I’m not yet seeing that.


Here’s a blog about a sailing boat that gives detailed instructions on how to get a cape other than the default.

 

It’s possible that errors are resulting from the old overlay, before the git pull.

cat /sys/devices/platform/ocp/ocp:cape-universal/status

gives a pin-mapping of the pins allocated by the cape-universaln.

12/26/2016

Some files:

/sys/kernel/debug/pinctrl/44e100.pinmux/pins … info on the pins.

/sys/class/gpio/export

direction, value, active_low

device tree overlays

/sys/devices/platform/bone_capemgr/slots

uEnv.txt

cape-enable=capemgr.enable_partno=<dtb file>

cape-disable=capemgr.disable_partno=<dtb file>

Stick the dtb into /lib/firmware


pwm … p8-13

config-pin -l P8.13

tells you

default gpio gpio_pu gpio_pd pwm

Then run

config-pin P8.13 pwm

and check

cat /sys/devices/platform/ocp/ocp:P8_13_pinmux/state

and it says ‘pwm.’

Look in /sys/class/pwm which has a series of links to (e.g.)

/sys/class/pwm/pwmchip0 -> /sys/devices/platform/ocp/48300000.epwmss/48300100.eap/pwm/pwmchip0

Going into pwmchip0 and echo 0 > export creates the folder pwm0.

12/25/2016

Yet another black hole to crawl back up!

My current state of understanding of the remoteproc system …

It appears that remoteproc has sandboxed the pru so that you cannot set registers outside the local memory space.  This can be done through the device tree or through the HWREG function.


There is a bunch of code related to the pru_cape (TI demo/lab module) that uses the StarterWare package.  This seems to indicate that the arm-side program should access the registers (using the HWREG macro) and then initiate the pru through the remoteproc interface.  The pru should play nice in its sandbox.

This is almost certainly a design improvement.  But, the lack of documentation!!!!

It also appears that the arm side is sandboxed.  When HWREG is used to access portions of memory, I get a segmentation fault.  However, once through this barrier, I’m sure that progress will continue.

Looks like I’m not going to make it through that barrier.  I think this is an old way of doing things, like /dev/mem.  Seems to need a kernel module to get access to system resources from user space.

StarterWare workflow looks good, but I cannot see how it implements on the current kernel.


I’m starting to look into the resource_table as a means of allocating resources to the PRU.  If this is the way to go, then I might be back to my earlier way of doing things, but with the need to put entries into the resource_table.


For some reason, in 4.1, the cape manager disappeared and then was brought back.  Was this an attempt to make the device tree go away?  In favor of what?

12/23/2016

It is critically important for diagnostic work to be able to get info into and out of the controller so that you can debug code. Several important things can be done on the beaglebone/pru.

You can blink one of the four user leds.

You can toggle a pin connected to the pru (R30).

You can access General Purpose Input / Output (GPIO) functions in memory space off the pru.

You don’t have to use rproc communications to do this, so this example will not use those features for purposes of making the example simpler.

Finding the pesky pins!

It is difficult to get all the information related to the pins, since it does not seem to be stored in one place.  Start with the LEDs.

The Beaglebone System Reference Manual (SRM) tells the location of the LEDS.

Table 8 tells us that user0 is connected to gpio2_21, user1 is connected to gpio2_22, user2 is connected to gpio2_23, and user 3 is connected to gpio2_24.  A note after the table indicates that changing the logic level will toggle the LED.

Go to the AM335x Sitara Technical Reference Manual (TRM) and locate Table 2-2.

 

The location of the gpio registers in the pru memory space are:

GPIO0, 0x44e07000
GPIO1, 0x4804c000
GPIO2, 0x481ac000
GPIO3, 0x481ae000

The gpio header file is located here. This contains the SETDATAOUT and CLEARDATAOUT registers, which are used to change the logic level.

The control module registers (see Table 9-10 of the TRM) set the mode for each pin.  The base register is 0x44E1 0000 (see Table 2-2 of the TRM).  The offset for each pin is located in Table 9-10 of the TRM.

Go to the AM3358 data sheet.  Table 4-1 indicates that gpio1_21 (GPMC_A5), gpio1_22 (GPMC_A6), gpio1_23 (GPMC_A7), and gpio1_24 (GPMC_A8)  requires mode 7 to be set.

From TRM Table 9-10, the offset for the pad control register is gpio1_21 (GPMC_A5,0x854), gpio1_22 (GPMC_A6, 0x858), gpio1_23 (GPMC_A7, 0x85C), and gpio1_24 (GPMC_A8, 0x860).

How to put gpio1 into the right mode?  What is mode 7?  How is it set?

The definition of the pad control register is shown in the TRM on Table 9-1, Table 9-2, and Table 9-3.

To set USER_LED0, write 0xxx to 0x44E10000+0x854 to set the pin into mode 7, output, pull down.  Then, write 1 to bit 21 of 0x4804c000’s setdataout register to turn the led on.  Write 1 to bit 21 of 0x481ac000’s cleardataout register.

Posted in: Robotics

Comments are closed.