Problems Reconfiguring GPIO's

Greetings,

I am working on developing a new piece of equipment using the BBB as the controller.

One aspect of the project is control of an inlet and outlet pump from a tank. Time sensitivity is not critical.

I am looking to use
P8-11 (GPIO 45) as pulldown input - Program man/auto
P8-12 (GPIO 44) as pulldown input - Pump 1 - man on/off
P8-14 (GPIO 26) as pulldown input - Pump 2 - man on/off
P8-15 (GPIO 47) as pulldown input - Pump 2 start switch
P8-16 (GPIO 46) as pulldown input - Pump 1 Stop switch
P8-17 (GPIO 27) as pulldown input - Pump 2 Stop switch
P8-18 (GPIO 65) as pulldown input - Pump 1 Start switch

Fortunately, pulldown input is the default state of each of those pins.

Unfortunately, I also want
P9-12 (GPIO 60) as pulldown output to turn on pump 1 using a relay, where P9-12’s default state is pullup input, and
P9-15 (GPIO 48) as pulldown output to turn on pump 2 using a relay, where P9-15’s default state is pulldown input.

I have been trying to work through RCN’s dtb-rebuilder with Derek Molloy’s book to accomplish this.

But I have not impacted this default state.

I am using Kenerl r.19.94-ti-r42.

I have captured my boot sequence using a serial cable through putty:

uboot_overlays: [uboot-base-dtb = am335x-boneblack-uboot-univ.dtb]…
the seqeunce confirms it switched to the above, then loads with 162266 bytes read

am335x-boneblack-uboot-univ.dtb includes

  1. am33xx.dtsi, which appears to set on chip GPIO’s,
  2. am335x-bone-common.dtsi, which appears to only interact with P9-19 & P9-20 in terms of GPIO, and
  3. am335x-bone-common-univ.dtsi

So looking at P9-12 in am335x-bone-common-univ.dtsi:

Line 713 of am335x-bone-common-univ.dtsi begins the definitions of Gpio on P9-12
/* P9_12 (ZCZ ball U18) gpio1_28 /
P9_12_default_pin: pinmux_P9_12_default_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7) >; }; /
gpmc_be1n.gpio1_28 /
P9_12_gpio_pin: pinmux_P9_12_gpio_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT | INPUT_EN | MUX_MODE7) >; }; /
gpmc_be1n.gpio1_28 /
P9_12_gpio_pu_pin: pinmux_P9_12_gpio_pu_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLUP | INPUT_EN | MUX_MODE7) >; }; /
gpmc_be1n.gpio1_28 /
P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLDOWN | INPUT_EN | MUX_MODE7) >; }; /
gpmc_be1n.gpio1_28 /
P9_12_gpio_input_pin: pinmux_P9_12_gpio_input_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_INPUT | MUX_MODE7) >; }; /
gpmc_be1n.gpio1_28 */

I have tried modifying the lines above with no success
1)
P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLDOWN_EN | INPUT | MUX_MODE7) >; }; /* gpmc_be1n.gpio1_28 */

and

P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLDOWN_EN | MUX_MODE7) >; }; /* gpmc_be1n.gpio1_28 */

and
3)
P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin { pinctrl-single,pins = <
AM33XX_IOPAD(0x0878, PIN_OUTPUT_PULLDOWN| MUX_MODE7) >; }; /* gpmc_be1n.gpio1_28 */

Line 2049 starts the next section which appears to only define the pinctrl states
/* P9_12 (ZCZ ball U18) */
P9_12_pinmux {
compatible = “bone-pinmux-helper”;
status = “okay”;
pinctrl-names = “default”, “gpio”, “gpio_pu”, “gpio_pd”, “gpio_input”;
pinctrl-0 = <&P9_12_default_pin>;
pinctrl-1 = <&P9_12_gpio_pin>;
pinctrl-2 = <&P9_12_gpio_pu_pin>;
pinctrl-3 = <&P9_12_gpio_pd_pin>;
pinctrl-4 = <&P9_12_gpio_input_pin>;
};

I have not played with these.

Finally, the last place it appears to configure P9-15 starts on Line 2777
P9_12 {
gpio-name = “P9_12”;
gpio = <&gpio1 28 0>;
input;
dir-changeable;
};

I have tried a few modification here with no success such as

P9_12 {
gpio-name = “P9_12”;
gpio = <&gpio1 28 3>;
output;
pulldown;
};

I nano’ed, modified and saved the am335x-bone-common-univ.dtsi file, used the dtb-rebuilder make all command, backed up the old binary file am335x-boneblack-uboot-univ.dtb_BACKUP and replaced it with the new am335x-boneblack-uboot-univ.dtb.

And yes I messed it up a couple times and had to completely rebuild the BBB’s loaded image, updates, upgrades, etc… Lots of fun.

I have not seen any change in the default state of P9-12 from pullup input as checked using config-pin query.

Can anyone redirect me to some examples, or provide a some tips, or simply tell me I’m off my rocker and nowhere close to where I need to be?

I’m a little stuck here.

Unfortunately, I also want
P9-12 (GPIO 60) as pulldown output to turn on pump 1 using a relay, where
P9-12's default state is pullup input, and
P9-15 (GPIO 48) as pulldown output to turn on pump 2 using a relay, where
P9-15's default state is pulldown input.

I have been trying to work through RCN's dtb-rebuilder with Derek Molloy's
book to accomplish this.

  First or second edition? It may be pertinent.

But I have not impacted this default state.

  OTOH, I note you mentioned checking using config-pin, but not trying to
set using it. Have you tried using config-pin at run time instead of all
this DTB hassle? {the /old/ config-pin script, not the less-capable binary
that is now in the path}

Hi!

I’m a little stuck here.

Drop all than device tree and config-pin stuff. Instead use libpruio for pinmuxing. Once installed you can configure the pins from user space in your source code, compiled against libpruio. (This also safes boot-time and kernel memory.)

Example:
`

// Input
if (pruio_gpio_config(io, P8_11, PRUIO_GPIO_IN_0)) {
printf(“GPIO P8_11 configuration failed (%s)\n”, io->Errr); break;}
// Output
if (pruio_gpio_setValue(io, P9_12, 0)) {
printf(“GPIO P9_12 configuration failed (%s)\n”, io->Errr); break;}

`

Check the examples for complete code. By default an output pin gets configured without restistor, but you can override by function pruio_setPin(io, P9_12, 7 + PRUIO_PULL_UP).

Regards

Thank you for the responses, gentlemen.

Dennis:
2nd addition… ran it to those problems last spring… edition matters for certain. 1st addition uses only an outdated device tree method.

I’ve used config-pin in the ways you’ve described from the IDE, but have not incorporated it into C++ program. Will look for examples

As an aside – setting an output to pull-up/pull-down seems to me
rather perverse. My understanding of circuits is that pull-up/-down is
meant to ensure one reads a particular state when external devices are
/not/ driving a line to either rail, or are tri-stated (floating) when the
line is shared among devices. Once your application is running, your
outputs should be driven to one or the other state, they won’t be floating.

I want to ensure the pump is not triggered from any noise. Perhaps I misunderstood this feature.

TJF
I will review this method.

Best Regards

I've used config-pin in the ways you've described from the IDE, but have
not incorporated it into C++ program. Will look for examples

  Well, there is always the old C-lib system() call

  Or managing to read the config-pin /script/ source and figuring out how
to invoke the equivalent directly <G>

I want to ensure the pump is not triggered from any noise. Perhaps I
misunderstood this feature.

  If you need to prevent the pump for doing anything during system
start-up, you likely need to put the pull-up/-down resistors on the pump
inputs themselves, where they won't be affected by changes in the pin-mux
settings. However, take into consideration that recommendations are that
/no/ voltages be applied to I/O pins before the board itself is powered --
which implies having some sort switched buffer between the I/O pin and the
pump control with its pull-up/-down if it uses an external power-supply
rather than one controlled by the Beagle itself.

  The heavily promoted libpruio bothers me for some reason -- among them
being that it requires one of the two PRUs to be dedicated to it, so not of
use if one has an application that needs both PRUs; and that control chain
-- Linux app sending command to PRU application to modify pin-mux so Linux
app can make use of new state [Does this mean the kernel may have a
disconnect in what /it/ thought the pin-mux state was, or does the PRU
somehow update the kernel]. OTOH -- if the author could get it to work on a
BB AI (which has two /pairs/ of PRUs, and currently has nothing for
run-time pin-muxing -- requiring device tree edits for any thing that is
not a default)...

... which appears to be sysfs writes...

  Note -- there appears to be an error at line 1446 of the script
version... It is setting PULL-DOWN, but is in a block of code that is
supposed to be setting PULL-UP. Looks like a cut&paste of lines 1414-1430
(setting pull-down), to 1432-1448, in which three of the four _pd where
changed to _pu.

    # GPIO with pull-up enabled

[iI][nN]+|[iI][nN][pP][uU][tT]+|[iI][nN][-_][pP][uU]|[iI][nN][pP][uU][tT][-_][pP][uU])
      MODE=gpio_pu;
      DIR=in
      ;;

[oO][uU][tT]+|[oO][uU][tT][pP][uU][tT]+|[oO][uU][tT][-_][pP][uU]|[oO][uU][tT][pP][uU][tT][-_][pP][uU])
      MODE=gpio_pu;
      DIR=out
      ;;

[lL][oO]+|[lL][oO][wW]+|0+|[lL][oO][-_][pP][uU]|[lL][oO][wW][-_][pP][uU]|0[-_][pP][uU])
      MODE=gpio_pu;
      DIR=low
      ;;

[hH][iI]+|[hH][iI][gG][hH]+|1+|[hH][iI][-_][pP][uU]|[hH][iI][gG][hH][-_][pP][uU]|1[-_][pP][uU])
      MODE=gpio_pd; <<<<< line 1446, compare to previous three
      DIR=high
      ;;

  Direction is written via (trimmed)(line 1470)

    if [ -n "$DIR" ] ; then
      eval GPIO="\$${PIN}_GPIO"
      FILE="$GPIODIR/gpio$GPIO/direction"
      if [ -e $FILE ] ; then
        if [ -w $FILE ] ; then
          echo $DIR > $FILE || (echo_err "Cannot write gpio
direction file: $FILE" && exit 1)

and mode is written (line 1484 -- note that I think I only showed the post
3.8 kernel)

    if [ ! "x${SLOTS_LOCATION}" = "xold38kernel" ] ; then
      # Expand filename using shell globbing
      for FILE in $OCPDIR${PIN}_pinmux/state ; do
        echo_dbg "echo $MODE > $FILE"
        if [ -w $FILE ] ; then
          echo $MODE > $FILE || (echo_err "Cannot write pinmux
file: $FILE" && exit 1)

  So... from C/C++ determining the sysfs file names for the pins, and
writing the direction and mode strings to the proper files would be the
direct way. I believe most newer images have put the "debian" user into a
group with GPIO write access (I snipped the "else" branch which invokes the
write using sudo -- I'm presuming [-w ...] is a test for "is file
writable")

How do you make the PRU modify pinmuxing? You have no idea what you’re talking about!

Regards

I can only state then, that a quick perusal of the online documentation
(in particular, the github readme) gives this one the impression that the
package provides a specific program running on a PRU which must be used,
and that a host application, via a library, talks to that PRU to perform
I/O. If setting the configuration and subsequent I/O performed without
involving a PRU, it is not readily apparent. The presence of that warning
about the PRU being able to access any memory reinforces this, as it
implies that a PRU could write to the pin-mux registers to change
configuration.

@ P B:

I want to ensure the pump is not triggered from any noise. Perhaps I misunderstood this feature.

You should also consider to implement an external pulldown. The weak internal resistance isn’t present in the early boot phase (it comes up 7-10 seconds after power-on).

@ Dennis

Pinmuxing must be done from privileged mode (effectively: Linux kernel/kernel module only). Neither userspace nor PRU can change a pinmux.

If you must have a pin that changes direction and you need to control it from the PRU, you can use the digital I/O’s on the IEP (industrial ethernet peripheral). I can confirm that this works.

See:
https://groups.google.com/forum/#!msg/beagleboard/AcQ3lY03UD0/glUL7Rc-CgAJ
https://e2e.ti.com/support/processors/f/791/t/445028

I probably need to clarify. I can confirm that you can tri-state an IEP output pin from the PRU. I actually used an input and output pin wired together so I could dodge the whole question of changing direction.

As I understand it, most of the pinmux issues on the AM57xx are due to a chip bug. I don’t think anybody can work around them.

Pinmuxing must be done from privileged mode (effectively: Linux kernel/kernel module only).

Correct.

Neither userspace nor PRU can change a pinmux.

Not correct. In a libpruio configuration all members of system-group ‘pruio’ can pinmux from user space. That’s why libpruio development is as easy as Arduino development, but much more powerful.

If you must have a pin that changes direction and you need to control it from the PRU, you can use the digital I/O’s on the IEP (industrial ethernet peripheral). I can confirm that this works.

Off-topic.

@ P B

You asked for GPIO. In order to control the flow rate, you could also control the pumps by PWM signals.

  1. While I’m always grateful for your responses, TJF, you need to understand that your answers almost always come across a bit … abrupt. I presume it’s a language thing as I couldn’t possibly convey nuance in German.

  2. You know the libpruio architecture cold, but none of your documentation explains it, at all. So, the relationship between kernel module, system groups, PRU, and user mode is not at all clear to newcomers who actually try to look at your libpruio library.

  3. The reliance on FreeBASIC is an absolute non-starter for a LOT of people. While I’m sure you find it to be a superior tool, most people already find the BeagleBone forbidding enough. Adding another unfamiliar tool to the mix is not something most people are willing to do.

Thanks.

@Andrew P. Lentvorski

You came in to point to your tri-state solutions. I also use a tri-state GPIO in my one-wire driver libpruw1. But it isn’t the topic in this thread.

  1. While I’m always grateful for your responses, TJF, you need to understand that your answers almost always come across a bit … abrupt. I presume it’s a language thing as I couldn’t possibly convey nuance in German.

I’m sorry if you’re not fast enough.

  1. You know the libpruio architecture cold, but none of your documentation explains it, at all. So, the relationship between kernel module, system groups, PRU, and user mode is not at all clear to newcomers who actually try to look at your libpruio library.

I do my very best not just develping a unique solution, but also documenting it in a forein language. The docu may not be perfect, but it explains that relaionship. It’s OK when you don’t read that. But don’t tell other that it isn’t present.

  1. The reliance on FreeBASIC is an absolute non-starter for a LOT of people. While I’m sure you find it to be a superior tool, most people already find the BeagleBone forbidding enough. Adding another unfamiliar tool to the mix is not something most people are willing to do.

The library also includes bindings and examples for C and Python programming languages. Why do you see a reliance on FreeBASIC?

Thanks.

Neither userspace nor PRU can change a pinmux.

Not correct. In a libpruio configuration all members of system-group ‘pruio’ can pinmux from user space. That’s why libpruio development is as easy as Arduino development, but much more powerful.

Because you shunt the request through the custom kernel module. Telling people that they can pinmux from userspace simply confuses people further who are already probably plenty confused.

Yes, the library shunts requests. And that’s why (only) libpruio users can do pinmuxing from user space single source in their code. There’s nothing wrong with that statement.

You’re right, one of us is confusing people.

Regards