cancel
Showing results for 
Search instead for 
Did you mean: 
Scholar
Scholar
10,711 Views
Registered: ‎05-28-2012

Cannot Preset GPIO Output

Jump to solution

I am finding that I cannot set the value of the GPIO output before setting the direction of the GPIO to out. In my case, the pin is externally pulled high while the pin is in high-impedance input mode. In the example below, GPIO 15 controls a HW reset line. It is pulled high and asserts low.

echo 15 > /sys/class/gpio/export
cat /sys/class/gpio/gpio15/direction
cat /sys/class/gpio/gpio15/value
echo 1 > /sys/class/gpio/gpio15/value
echo out > /sys/class/gpio/gpio15/direction
echo 0 > /sys/class/gpio/gpio15/value

The reset drops at the direction change. Not at the setting the value to zero. I've experimented with low-level code in the FSBL to configure a GPIO as preset output. I found the DATA register cannot be written until the DIR = output. Seems the order has to be:
 DIR = output
 DATA = 1
 OEN = 1
The Linux driver appears have this order
 DATA = 1 <-- "echo 1 > value"
 DIR = output <--- "echo out > direction" starts here
 OEN = 1
 DATA = 1
The first write to DATA does not stick. DATA is still the reset default of 0.

 

A bug in HW or needs to be worked-around in SW?

 

 

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Adventurer
Adventurer
14,150 Views
Registered: ‎09-19-2014

Re: Cannot Preset GPIO Output

Jump to solution

No, I think you misunderstand.

 

I said:

i.e. > echo high > direction  (makes it output value of 1)

 

What this does is make direction = out, and value = 1 all in one atomic step. As in, if you read from direction, it will not say 'high', but instead 'out'. Thus you don't need to set direction to out as the third step, because it is already there.

 

echo 15 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio15/direction

cat /sys/class/gpio/gpio15/direction

[shows 'out', and it outputs value '1'/high, even though reading from 'value' is meaningless.]
...

echo 0 > /sys/class/gpio/gpio15/value [whenever you want to set it to low after that]

 

Perhaps the documentation was updated in the inbetween years...

View solution in original post

0 Kudos
11 Replies
Highlighted
Anonymous
Not applicable
10,688 Views

Re: Cannot Preset GPIO Output

Jump to solution

I took a look at the driver and it looks like the code is ok at least at a low-level.  I don't know what it is doing from a higher level within Linux though.

 

My initial thought is that it appears to be a hardware limitation but if you need a definitive answer you need to open a support case.

 

0 Kudos
Highlighted
Scholar
Scholar
10,683 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

I personally think it is yet another weird quirk of th Zynq HW. Most processors allow the GPIO data register to changed anytime. The Zynq seems to full of odd gating choices. I doubt that the HW will ever be changed. A fix in SW would be like so:

 

drivers/gpio/xilinx_gpiops.c

static int xgpiops_dir_out(struct gpio_chip *chip, unsigned int pin, int state)
{
    struct xgpiops *gpio = container_of(chip, struct xgpiops, chip);
    unsigned int reg, bank_num, bank_pin_num;

    xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num);

    /* set the GPIO pin as output */
    reg = xgpiops_readreg(gpio->base_addr +
                   XGPIOPS_DIRM_OFFSET(bank_num));
    reg |= 1 << bank_pin_num;
    xgpiops_writereg(reg,
              gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num));

    /* set the state of the pin after direction change but before output enable. */
    xgpiops_set_value(chip, pin, state); /*****MOVED UP FROM BOTTOM */

    /* configure the output enable reg for the pin */
    reg = xgpiops_readreg(gpio->base_addr +
                   XGPIOPS_OUTEN_OFFSET(bank_num));
    reg |= 1 << bank_pin_num;
    xgpiops_writereg(reg,
              gpio->base_addr + XGPIOPS_OUTEN_OFFSET(bank_num));

//    /* set the state of the pin */       /* MOVE TO BEFORE OEN */
//    xgpiops_set_value(chip, pin, state);

    return 0;
}

 

Should work but I am not sure about situations where the GPIO is already configured output. Also I am assuming that the GPIO framework is keeping a shadow value from a previous set operation.

 

 

0 Kudos
Highlighted
Adventurer
Adventurer
8,944 Views
Registered: ‎09-19-2014

Re: Cannot Preset GPIO Output

Jump to solution

I know this question is from a long time ago. If I'm understanding the question correctly, I had the same issue.

 

It's actually just a quirk of how the GPIO driver in sysfs works. It's in the documentation, and I missed it too when I read it the first time.

 

https://www.ridgerun.com/developer/wiki/index.php/How_to_use_GPIO_signals

3 - Configure GPIO for input or output - To avoid hardware issues where two devices are driving the same signal, GPIOs default to be configured as an input. If you want to use the GPIO as an output, you need to change the configuration

 

This means even if you tell the GPIO pins to be outputs in the devicetree, in the sysfs interface, they will always default to input, so as not to interfere. This is not a bug.

 

 

https://www.kernel.org/doc/Documentation/gpio/sysfs.txt

"direction" ... reads as either "in" or "out". This value may

normally be written. Writing as "out" defaults to
initializing the value as low. To ensure glitch free
operation, values "low" and "high" may be written to
configure the GPIO as an output with that initial value.

Note that this attribute will not exist if the kernel
doesn't support changing the direction of a GPIO, or
it was exported by kernel code that didn't explicitly
allow userspace to reconfigure this GPIO's direction.

 

So you can't write to value before you set direction to "out", which causes it to always output a 0 value first. The solution, as it says to ensure glitch-free operation, is to set direction to "high", which is the same as setting direction to "out" and value to "1" is the one atomic operation.

 

i.e. > echo high > direction  (makes it output value of 1)

0 Kudos
Highlighted
Scholar
Scholar
8,936 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

It has been a lot of years since I last read the gpio doc. I wasn't aware of the "high" and "low" option for the direction. Must have been added in the last several years.

However the problem I was observing had more to do with the silicon requiring a certain order of register writes to ensure a glitch-free operation. The Zynq GPIO Linux driver still does the writes in an order that results in a glitch. I tried using "high" like so:

echo 15 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio15/direction
echo out > /sys/class/gpio/gpio15/direction

My GPIO 15 is active low reset. My system reboot on "out" > direction. Implies that it still glitched low before setting it high. The problem still exists.

0 Kudos
Highlighted
Adventurer
Adventurer
14,151 Views
Registered: ‎09-19-2014

Re: Cannot Preset GPIO Output

Jump to solution

No, I think you misunderstand.

 

I said:

i.e. > echo high > direction  (makes it output value of 1)

 

What this does is make direction = out, and value = 1 all in one atomic step. As in, if you read from direction, it will not say 'high', but instead 'out'. Thus you don't need to set direction to out as the third step, because it is already there.

 

echo 15 > /sys/class/gpio/export
echo high > /sys/class/gpio/gpio15/direction

cat /sys/class/gpio/gpio15/direction

[shows 'out', and it outputs value '1'/high, even though reading from 'value' is meaningless.]
...

echo 0 > /sys/class/gpio/gpio15/value [whenever you want to set it to low after that]

 

Perhaps the documentation was updated in the inbetween years...

View solution in original post

0 Kudos
Highlighted
Scholar
Scholar
8,894 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

I'll take your word that:

echo high > direction

will set the GPIO to an outuput with high level. It does not explain why a subsequent

echo out > direction

would glitch my reset line. I'd expect the GPIO driver to emit "already an output" message or silently ignore it. I guess the driver must not check and just changes from an output of 1 to an output of 0. My kernel is 2014.3 or 3.15.0.

 

I'll have to check if my FSBL bare metal GPIO code still exhibits the same oddness I seen a couple years ago. Maybe Xilinx did fix the silicon and Linux enforced the "out > direction" with default 0 behaviour.

 

I don't have a board right now. I'll try more experiments when I get a board. It's not a high priority for me as I can leave it high-impedance input with pull up and set it to an output to reset the system.

 

0 Kudos
Highlighted
Scholar
Scholar
8,886 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

Okay...I did some more tests and looked deeper into the gpiolib code.

  direction = high -> means set direction to output with level of 1

  direction = out -> means set direction to output with level of 0

  direction = low -> same as above.

No check to see if the GPIO is already an output. Effectively setting the direction also sets the level.

 

I can't figure out why gpio-zynq.,c would work glitch free as it writes with with this order DIRM, OEN and DATA. For a brief moment between OEN and DATA writes, the output line will be whatever is lying around in DATA. Might be I have a larger enough capacitor this time around to smooth out the glitch. Or maybe memory access reordering. It works for now.

 

Thanks for the help.

0 Kudos
Highlighted
Adventurer
Adventurer
8,878 Views
Registered: ‎09-19-2014

Re: Cannot Preset GPIO Output

Jump to solution

I did quote the documentation part above:

"Writing as "out" defaults to initializing the value as low."

 

That's what the documentation says. That's what you've seen it do. Yes, it's weird, but that's how it's designed.

 

I now consider the GPIO sysfs interface a disconnected concept from the defaults you specify in the devicetree. It doesn't even care about what you specified in the devicetree. It would probably be hard to implement that way. I've just learnt that the documentation is what matters here - not what you put in the devicetree.

0 Kudos
Highlighted
Scholar
Scholar
8,870 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

I've found that the GPIO documentation has been more a writeup of intent than implementation. Well...it has been till recently. I have some 5 year old code that first set the value to "1" then the direction to "out".

 

The devicetree stuff uses GPIO devfs descriptors rather than GPIO sysfs. I expect that GPIO sysfs will soon be deprecated and then removed. Its already caused some grief as the base gpio number is now allocated downward from 512 rather than upward from 0. A lot of old legacy code will break.

 

The GPIO sysfs is handy for ad-hoc tests. Device trees and devfs are not as convenient.

 

0 Kudos
Highlighted
Xilinx Employee
Xilinx Employee
3,230 Views
Registered: ‎03-13-2012

Re: Cannot Preset GPIO Output

Jump to solution

Might be the LED-GPIO driver could be used for these cases? http://www.wiki.xilinx.com/Linux+GPIO+Driver#Linux%20Kernel%20Drivers-LEDS-GPIO%20Driver

0 Kudos
Highlighted
Scholar
Scholar
3,215 Views
Registered: ‎05-28-2012

Re: Cannot Preset GPIO Output

Jump to solution

Thanks for the link. GPIO LED or Keys definitely appears to the replacement for sysfs. The iteration cycle of programming a device tree to obtain a GPIO devfsis longer than just exporting GPIO sysfs immediately at runtime. The device tree/devfs approach is okay if everything is static and working. Go through the pain of getting a device tree working just once. During the initial development and board bring up, nothing is static or working.

0 Kudos