BBB - pinMode, digitalRead, digitalWrite, analogRead...

I know that a lot of this has been asked before and/or has been answered and I have somehow missed the answer.

First off, I would like to thank those who helped solve the issue of making uarts work.

I have a BBB that is running I believe 3.8.11 and I would like the ability to hook up some simple IO to the board. Things like buttons/switches, likewise maybe hook up some external leds so it would be nice to be able to use some of the pins on the external connectors. So the question is what is the best way to do this. Are there some simple functions that are equivalent to the Arduino functions (pinMode, digitalRead, digitalWrite)?

I have been playing around with this for a little while and have not had that much luck yet. My first attempt was to use the library Beagle_GPIO-master by Francois Sugny, which I did not work for me as I believe it again relies on the old debug memory map stuff.

Yesterday, I tried out the library bonelib, which I have had some limited success with. In particular, I was able to the get the led example to work, after I modified the src/leds.cpp file to change the hardware path to where the leds are. to:
sprintf(p, “/sys/class/leds/beaglebone:green:usr%d/”, n);

However I was not able to get the IO pin stuff working as I tried building a simple test case, from a suggestion in a different posting, which looked like:

`
#include <stdio.h>
#include <unistd.h>
#include “bonelib/gpio.hpp”

int
main(int argc, const char argv[])
{
BeagleBone::gpio
IOP = BeagleBone::gpio::P8(3);
printf(“Start Test IO Pin\n\r”);

IOP->configure(BeagleBone::pin::OUT);
printf(“After Configure\n\r”);
IOP->set(1);
printf(“After first set\n\r”);
for (int i = 0; i < 8; i++) {
IOP->set(0);
printf(“Off\n\r”);
usleep(5001000);
IOP->set(1);
printf(“On\n\r”);
usleep(500
1000);
}
return 1;
}

`

But this failed as well, again I believe using the old omap mapping.
Start Test IO Pin
ERROR: Cannot open /sys/kernel/debug/omap_mux/gpmc_ad6 for writing: No such file or directory
After Configure

My guess is that I need to somehow use the GPIO interface, like the one mentioned in:
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/gpio.txt?id=refs/tags/v3.8.11

But this for example relies on I believe pin numbers. If so is there already a mapping somewhere that takes for example the logical pin P8(3) and maps to the correct pin number?

Note as part of the UART stuff, I know we used the define: /sys/kernel/debug/pinctrl/44e10800.pinmux/pins
(Defined on my machine as $PINS)
When I do: cat $PINS
I get an output of I believe 142 pins.

I know from trying to map uart2_rxd/txd that the address for uart2_rxd was something like: 44e10950, which looking through the list of 142 pins shows up like:
pin 84 (44e10950) 00000021 pinctrl-single
pin 85 (44e10954) 00000001 pinctrl-single
(Also showing the TXD). So in this case would I use 84 as the pin number to GPIO?

Thanks
Kurt

P.S - sorry if I rambled on a little too much.

that's correct, as you can read here:

http://blog.pignology.net/2013/05/getting-uart2-devttyo1-working-on.html

"With the BBB comes a new kernel, 3.8, and devicetree to describe
hardware, /sys/kernel/debug/omap_mux is gone."

rday

It’s likely going to take some time for libraries that support 3.8 to start to leak out. I’m trying now to wrap my head around the whole Device Tree concept and I’m left scratching my head about how a generic library would work since much of the pin modes and settings are going to need to be defined in compiled binary that must be loaded.

I was considering putting a C++ wrapper around the SYSFS methods and you’d just have to live within the default definitions for the pins unless you created the proper DT settings to change it. As long as the pin is already muxed to GPIO then you could at least do the standard input vs output, pull-up / pull-down, and read and write values without the noise of all the file operations in the middle of your code. It would be slow, but a little more friendly to work with. All the libraries that do memory-mapped I/O so far blow up with panics or seg-faults. I assume that is because of the fact they want to take control of muxing.

I just don’t see a way for a user program to alter the mux settings with device tree. Not without being able to create a dts file, compiling it, and feeding it to cape-manager on the fly. I’m sure bigger brains than mine are probably all over it.

Thanks,

I would hope that if they were going to remove the mechanism that all current stuff depends on, that there would be some instructions on the recommended way to do it with the new mechanisms…

Assuming the Mux settings are reasonably set such that without any shields you have several GPIO pins available to you, then simply having the ability to set them as Input/Output, Read and Write them and set PU/PD and as a plus interrupts, would be sufficient for a majority of the cases. This is assuming that the user also has SPI and I2C available (but that is different subject).

Next test, is to try the GPIO stuff from the link I mentioned. I have noticed that in the example I gave for the pins associated with uart2 pins RXD/TXD. If you look at their address in the Ti am335trd about page 758, you see their addresses to be something like: 44E10950. You also see the address for the first pin at 44E10800, if you subtract the address of the pins (Note will remove upper part to make easy), you see 950h-800h = 150h divide by 4 you end up with 84(base 10), which was the pin number printed.

So maybe this GPIO pin numbering scheme? So if I look at P8(3), I believe that this is listed as conf_gpmc_ad6, with an address (offset) of 818h which by the math below would be pin 6…

So maybe I will try that pin. On the other hand when I cat $pins is see the mux value of 31, so may try different one that hopefully is muxed to to Mode 7…

More later.
Kurt

Not having much luck figuring out the proper direction on how to do this.

Suggestions? Is the only valid way right now to do this is to create your own kernel driver?

Thanks
Kurt

I don’t think that would be required. You can definitely still export GPIO and read/write to that. The trick is, if you want anything other than the default MUX settings you have to set the MUX settings using DeviceTree.

This link explains a bit about it:
http://blog.pignology.net/2013/05/getting-uart2-devttyo1-working-on.html

This link has example files that will enable all the UARTS and MUX them correctly at boot-up:
http://pignology.net/blackdts_alluarts.gz

In short, it should be simple enough to toggle GPIO_XX from 0 to 1 and so forth or to change that an input and read the value on GPIO_XX from code. What’s going to be difficult will be changing from GPIO_XX to UART_XX under program control. You can pop fragments of DeviceTree in and out using file operations but I don’t see how you would do it on a generic level in something like a setPinMux() function. I think that is where a lot of the current libraries drive off the cliff, is in trying to set the MUX, not in the actual access to the PINs. So how to know what pins you can use for what in your library is going to need to be tackled.

Here’s an example I saw of doing the actual read/write on the pin:

`

//define pin variables
int pin_number = 44, logic_status = 0;
char* pin_direction = output;
//establish a direction and value file within export for gpio44
ofp_export = fopen("/sys/class/gpio/export", “w”);

if(ofp_export == NULL)
printf(“Unable to open export.\n”);

fseek(ofp_export, 0, SEEK_SET);
fprintf(ofp_export, “%d”, pin_number);
fflush(ofp_export);

//configure gpio44 for writing
ofp_gpio44_direction = fopen("/sys/class/gpio/gpio44/direction", “w”);

if(ofp_gpio44_direction==NULL)
printf(“Unable to open gpio44_direction.\n”);

fseek(ofp_gpio44_direction, 0, SEEK_SET);
fprintf(ofp_gpio44_direction, “%s”, pin_direction);
fflush(ofp_gpio44_direction);

//write a logic 1 to gpio44 to illuminate the LED
ofp_gpio44_value = fopen("/sys/class/gpio/gpio44/value", “w”);

if(ofp_gpio44_value == NULL)
printf(“Unable to open gpio44_value.\n”);

fseek(ofp_gpio44_value, 0, SEEK_SET);
fprintf(ofp_gpio44_value, “%d”, logic_status);
fflush(ofp_gpio44_value);

`

It’s apparent how a library would be of great use here.

Thanks for the heads up. It took me awhile to figure out what the pin numbering in this case is. First guess was that I would need to figure out the offsets of the pin, subtract from 0x800/4… Which gives is the pin numbering when you look at the mux/pin information for the pins, using: /sys/kernel/debug/pinctrl/44e10800.pinmux/pins

That did not work. So I later tried working it from the GPIO pins. examples
P9:11 which is gpio0(30) computes to 032+30= 30
P9:12 is GPIO1(28): 1
32+28 = 60

These worked :slight_smile:
Not sure if anyone else is interested in this or not. Will continue to do some input, so I can try to read a button on the prototype board. On the prototype cape, I have P9:11 patched over to one of the leds…
Warning this is Quick and dirty!

`
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

#define HIGH 0x1
#define LOW 0x0

#define INPUT 0x0
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2

#define true 0x1
#define false 0x0

extern void pinMode(uint8_t, uint8_t);
extern void digitalWrite(uint8_t, uint8_t);
extern int digitalRead(uint8_t);

void pinMode(uint8_t bPin, uint8_t bMode)
{
// First try to open Direction
FILE *pfileDir;
char abT[34];

sprintf(abT, “/sys/class/gpio/gpio%d/direction”, bPin);
pfileDir = fopen(abT, “w”);

if (pfileDir == NULL)
{
// Probably not exported…
FILE *pfileExport = fopen("/sys/class/gpio/export", “w”);
if(pfileExport == NULL)
{
printf(“Unable to open export.\n”);
return;
}
fseek(pfileExport, 0, SEEK_SET);
fprintf(pfileExport, “%d”, bPin);
fflush(pfileExport);
fclose(pfileExport);

// Again lets try to open the file direction
pfileDir = fopen(abT, “w”);
if (pfileDir == NULL)
{
printf(“Error opening: %s\n”, abT);
return;
}
}

fseek(pfileDir, 0, SEEK_SET);
switch (bMode)
{
case INPUT:
fprintf(pfileDir, “in”);
break;
case OUTPUT:
fprintf(pfileDir, “out”);
break;
case INPUT_PULLUP:
// BUGBUG:: Have not done anything with pull up yet…
fprintf(pfileDir, “in”);
break;
}
fflush(pfileDir);
fclose(pfileDir);
}

// We will cache out one pin for now… Probably not much use, but…
static uint8_t s_bDWPinLast = 0xff;
static FILE * s_pfileDW = NULL;

void digitalWrite(uint8_t bPin, uint8_t bVal)
{
char abT[32];
// This function assumes that pinMode was called, which made sure things were exported…
if (bPin != s_bDWPinLast)
{
if (s_pfileDW)
{
fclose(s_pfileDW);
}
sprintf(abT, “/sys/class/gpio/gpio%d/value”, bPin);
s_pfileDW = fopen(abT, “w”);
if (s_pfileDW == NULL)
{
s_bDWPinLast = 0xff;
printf(“error opening %s\n”, abT);
return;
}
s_bDWPinLast = bPin;
}
fseek(s_pfileDW, 0, SEEK_SET);
fprintf(s_pfileDW, “%d\n”, (int)bVal);
fflush(s_pfileDW);

}

int digitalRead(uint8_t bPin)
{
return 0; // BUGBUG - Still need to do this…
}

#define LED_GPIOP 30
int main(int argc, const char *argv[])
{

printf(“Start Test IO Pin\n\r”);
pinMode(LED_GPIOP, OUTPUT); // set our pin as output
printf(“After pinMode”);
for (int i = 0; i < 8; i++)
{
printf(“On\n\r”);
digitalWrite(LED_GPIOP, HIGH);
usleep(1000*1000);

printf(“Off\n\r”);
digitalWrite(LED_GPIOP, LOW);
usleep(1000*1000);
}
return 1;
}

`

Kurt

You sir, rock! That’s a nice place to start from.

Thanks, still playing some,

I am trying to figure out how to do Pull-up resistors (and maybe PD), as to make it easier to hookup and test switch inputs.

Currently I don’t see any way using the /sys/class/gpio/… Unless maybe there are some special keywords or the like, that you can pass to one of the defined files like direction. So for example in my examples I want to enable the PU on P9:12, I would need to figure out the address of this pin, which I think is offset 0x878 (Table 11 shows M0 name for ping as gpmc_be1n but processor shows a pin gpmc_ben1).

So the only way I see to enable the PU is to build a dtsi file with pinmux pinx that I would define for offset 0x78 and value of 0x1f (Mode 7, PU, PU/PD-enable).

Then run the dtc command on this file. Then copy the output file to /lib/firmware. I could then write the logical name of this file out to the file /sys/devices/bone_capemgr.9/slots, which hopefully will load in my overlay…

Am I missing something, or hopefully there is an easier approach to this.

Thanks
Kurt

I think the process you describe is how the kernel maintainers would like it to work.

It’s probably best we just start accepting this now and write some tools that can generate these virtual cape/device tree files on the fly. As soon I get my BBB, I think my very first task will be to dig into the new device tree stuff and write a simple pinMode python tool.

From a production point of view, the device tree approach makes perfect sense, but from a hobbyist point of view it definitely feels like a lot of extra work. On the bright side, at least we can load these dynamically instead of having to reboot every time we want to make changes. :slight_smile:

Yes, unfortunately for us who tinker, that is exactly what you will need to do. Providing functions to change the pinmux on-the-fly will not be trivial.

I sort-of understand the Kernel people like the ability to have the pin-mux be defined in some defined way. Although personally I do wish they would expose some APIs to do so. Also for things like PU/PD, I wish that at a minimum they would expose another psuedo file like direction that allowed these to be updated. Or potentially overload the direction one, by adding some other valid values other than in/out. like in_pu *or in_pull-up, likewise for PD

But assuming we are on our own here, I wish either the BBB reference manual (Table 10/11) or some external files, were updated to have some additional information, like: the pin address (or offset) and potentially the default/initial state of the pins. It would also be nice to have it printed out in a few different orders, like P8/P9 pin order, address order … Maybe someone has already done this?

Thanks
Kurt

I’m working on that actually. I am building a spreadsheet to link the addresses and kernel “pins” to the header positions on the P8/P9 headers, as well as showing the default mux value for each pin. I could not deal with referencing 4 different places trying to figure out what was what. I hope to have that all done this week.

The pin mux control/registers control everything physical about the pin like what internal signal the pin is physically connected to, pull up, pull down, and enabling the receive circuitry so the state of the voltage on the pin can be read. This is separate from gpio, which is just an internal signal routed to/from the pin. So, you won’t find pull up/down in the gpio stuffs.

I see a “pinmux-helper” on the way that should “allow runtime configuration”: https://github.com/beagleboard/meta-beagleboard/blob/master/common-bsp/recipes-kernel/linux/linux-mainline-3.8/not-capebus/0109-pinmux-helper-Add-runtime-configuration-capability.patch

If that doesn’t make it easy enough, I’m sure someone will write something that does. Everything BBB is all very very new stuff.

Note, I miss read the Mux table stuff. I was thinking that PU/PD bit needed to be set for the PU to work. Relooking at the TI manual, this bit is more of a disable, that is it must be a 1 to disable the PU/PD… So those pins who already show up with a Mux value of 0x37 do have their PU enabled. So updated my test program, with two LEDS. Note: I am not using the full UART mux setup yet so my test is using the pins associated with UART4. In particular I am using P9_11,12 for LEDS and P9_13 for a button…

In case anyone is interested, here is my updated test code. It runs for 10 seconds, changing the state of one LED every 1/4 second and setting the state of the 2nd LED to the inverted value of the button.

`
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <time.h>

#define HIGH 0x1
#define LOW 0x0

#define INPUT 0x0
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2

#define true 0x1
#define false 0x0

extern void pinMode(uint8_t, uint8_t);
extern void digitalWrite(uint8_t, uint8_t);
extern int digitalRead(uint8_t);

void pinMode(uint8_t bPin, uint8_t bMode)
{
// First try to open Direction
FILE *pfileDir;
char abT[34];

sprintf(abT, “/sys/class/gpio/gpio%d/direction”, bPin);
pfileDir = fopen(abT, “w”);

if (pfileDir == NULL)
{
// Probably not exported…
FILE *pfileExport = fopen("/sys/class/gpio/export", “w”);
if(pfileExport == NULL)
{
printf(“Unable to open export.\n”);
return;
}
fseek(pfileExport, 0, SEEK_SET);
fprintf(pfileExport, “%d”, bPin);
fflush(pfileExport);
fclose(pfileExport);

// Again lets try to open the file direction
pfileDir = fopen(abT, “w”);
if (pfileDir == NULL)
{
printf(“Error opening: %s\n”, abT);
return;
}
}

fseek(pfileDir, 0, SEEK_SET);
switch (bMode)
{
case INPUT:
fprintf(pfileDir, “in”);
break;
case OUTPUT:
fprintf(pfileDir, “out”);
break;
case INPUT_PULLUP:
// BUGBUG:: Have not done anything with pull up yet…
fprintf(pfileDir, “in”);
break;
}
fflush(pfileDir);
fclose(pfileDir);
}

// We will cache out one pin for now… Probably not much use, but…
static uint8_t s_bDWPinLast = 0xff;
static FILE * s_pfileDW = NULL;

void digitalWrite(uint8_t bPin, uint8_t bVal)
{
char abT[32];
// This function assumes that pinMode was called, which made sure things were exported…
if (bPin != s_bDWPinLast)
{
if (s_pfileDW)
{
fclose(s_pfileDW);
}
sprintf(abT, “/sys/class/gpio/gpio%d/value”, bPin);
s_pfileDW = fopen(abT, “w”);
if (s_pfileDW == NULL)
{
s_bDWPinLast = 0xff;
printf(“error opening %s\n”, abT);
return;
}
s_bDWPinLast = bPin;
}
fseek(s_pfileDW, 0, SEEK_SET);
fprintf(s_pfileDW, “%d\n”, (int)bVal);
fflush(s_pfileDW);

}

int digitalRead(uint8_t bPin)
{
char abT[32];
// This function assumes that pinMode was called, which made sure things were exported…
if (bPin != s_bDWPinLast)
{
if (s_pfileDW)
{
fclose(s_pfileDW);
}
sprintf(abT, “/sys/class/gpio/gpio%d/value”, bPin);
s_pfileDW = fopen(abT, “r”);
if (s_pfileDW == NULL)
{
s_bDWPinLast = 0xff;
printf(“error opening %s\n”, abT);
return -1;
}
s_bDWPinLast = bPin;
}
fseek(s_pfileDW, 0, SEEK_SET);
int iRet = fgetc(s_pfileDW);
if (iRet == ‘0’)
return 0;
if (iRet == ‘1’)
return 1;
return iRet; // ???
}

unsigned long millis(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts );
return ( ts.tv_sec * 1000 + ts.tv_nsec / 1000000L );
}

#define LED1 30
#define LED2 60
#define BTN1 31
int main(int argc, const char *argv[])
{

printf(“Start Test IO Pin\n\r”);
pinMode(LED1, OUTPUT); // set our pin as output
pinMode(LED2, OUTPUT); //
pinMode(BTN1, INPUT);

printf(“After pinMode”);
// Will run for 10 seconds
unsigned long ulTimeStart = millis();
unsigned long ulTimePeriod = millis();
uint8_t bLED = 0;
int iBtn = digitalRead(BTN1);

while ((millis()-ulTimeStart) < 10000)
{
if ((millis()-ulTimePeriod) > 250)
{
bLED = !bLED ;
digitalWrite(LED1, bLED ? HIGH : LOW);
ulTimePeriod = millis();
}

// Now see the state of the button.
int iNewBtn = digitalRead(BTN1);
if (iBtn != iNewBtn)
{
iBtn = iNewBtn;
digitalWrite(LED2, iBtn ? LOW : HIGH); // invert as
printf(“Button: %d\n”, iBtn);
}
usleep(100); // give some time to the system
}
return 1;
}

`

Next up I will probably split these functions off and add them to my Linux (BBB/RPI) code library that I use for my Phoenix code base (Hexapod Robot code).

Kurt

Forgot to mention: When I integrate this stuff in. I will upload the code up to my github account:
github\kurte

Hey,
I tried to enable UART1_RTS and CTS (0x97c and 0x978) using a modified version of the above uart2pinmux.dts, which is present here https://github.com/chayansharma/Demo. after putting it to slots and doing dmesg | tail it showed the following error

[ 1048.779917] pinctrl-single 44e10800.pinmux: pin 44e1097c already requested by 4819c000.i2c; cannot claim for helper.14
[ 1048.791395] pinctrl-single 44e10800.pinmux: pin-95 (helper.14) status -22
[ 1048.798670] pinctrl-single 44e10800.pinmux: could not request pin 95 on device pinctrl-single
[ 1048.807732] bone-pinmux-helper helper.14: Failed to select default state
[ 1048.849694] bone-pinmux-helper: probe of helper.14 failed with error -22

Can anyone suggest me how to solve this conflict?