raspberrypi/hats

Unable to specify GPIO as output, driven high.

Opened this issue · 14 comments

mlyle commented
# SPI Chip Enables

# microcontroller
setgpio   8     OUTPUT    UP
# gyro
setgpio   7     OUTPUT    UP
# accelerometer
setgpio   5     OUTPUT    UP

Doesn't do what one might expect; it configures these GPIOs as outputs, with the weak pullup enabled.. with the IO driven down hard.

When used for SPI chip enables, this is super bad, because the default of driving the pin down low means the slaves can fight on the MISO pin.

Ideally there would be a way to tell the bootloader to forcefully drive these pins high ASAP.

P33M commented

The reset value of the GPIO pad output drive defaults to 0, thus selecting GPIO as output without first poking a 1 at GPIO_SET will result in the pin being driven to 0. Setting the initial data pattern is outside the scope of the alt function setup.

The preferred way to specify chipselects would be to assign them as gpio-cs pins in the SPI devicetree atom. Thus if you leave the pins as the power-on default (inputs, pulled high) then on driver probe the correct pins will be assigned by the Linux kernel and driven appropriately.

https://www.kernel.org/doc/Documentation/devicetree/bindings/spi/spi-bus.txt

Is there a recommended way to set these values in the eeprom_settings.txt file? The one given only has metadata and basic GPIO config. If I need to make a device tree overlay manually, that's fine, but how do I pass that to eepmake for inclusion?

mlyle commented

@Talonj123 you can do -c foo.dto on the eepmake command line to bundle it in.

@P33M I'm disappointed there's not a way to set GPIOs early-- it seems like it would be advantageous to be able to put LEDs, chip selects, reset lines, etc, into known states.

l1k commented

Digging out this ancient but still relevant issue:

It would indeed by useful if the initial GPIO polarity could be defined in the HAT EEPROM. Obviously, this only applies if a GPIO's func_sel is output.

One use case is the Chip Select line for SPI devices. Not every SPI device is happy with Chip Select being asserted on power-on and becoming deasserted only when the pinctrl kernel driver probes. One example is the Microchip MCP3550 ADC, which transitions into Continuous Conversion Mode if Chip Select is asserted without clocking data in and out.

The dt-blob.bin does allow specifying the initial polarity via the startup_state parameter, but the HAT EEPROM does not.

Although the power-on-reset state of the GPIO is "low" (as @P33M states above), I'm worried that the state after a warm reset (reboot) might be whatever the register contains and is thus undefined. Does the Raspberry Pi firmware set the register contents to zero upon a warm reset?

The eeprom_format contains two reserved bits per GPIO. One of those could be designated as the desired initial polarity if func_sel is output. Would the Raspberry Pi Foundation be willing to add support for this in the firmware? Members of the Revolution Pi project could help with amending the tooling and documentation, as we've done for bank 1 support in the HAT EEPROM.

Thanks!

Not every SPI device is happy with Chip Select being asserted on power-on and becoming deasserted only when the pinctrl kernel driver probes.

Setting the polarity and/or drive in the HAT EEPROM won't prevent this, only reduce the interval for which the CS line appears to be asserted. Is that going to be sufficient?

It's advisable to choose GPIOs with the appropriate default pulls to suit the application - 0-8 high, 9-27 low - adding inverters if necessary. I'm not against making the change in principle, but I'm not convinced it will have the desired effect.

l1k commented
Setting the polarity and/or drive in the HAT EEPROM won't prevent this, only reduce the interval for which the CS line appears to be asserted. Is that going to be sufficient?

Hm, my understanding is that GPIO settings in dt-blob.bin take effect before the ARM core powers on. In my tests, that resulted in the Chip Select for MCP3550 never being asserted on boot (verified with an oscilloscope). Which is optimal.

Is the same not possible with the HAT EEPROM? Do the settings in the HAT EEPROM take effect later than those in dt-blob.bin?

Also, is the assumption correct that GPIO register settings are not set to POR state upon a warm reset, i.e. reboot?

Thanks a lot for patiently dealing with my questions. :)

mlyle commented

Not every SPI device is happy with Chip Select being asserted on power-on and becoming deasserted only when the pinctrl kernel driver probes.

It's advisable to choose GPIOs with the appropriate default pulls to suit the application - 0-8 high, 9-27 low - adding inverters if necessary. I'm not against making the change in principle, but I'm not convinced it will have the desired effect.

You can always overcome these default pulls with explicit pullups/pulldowns. But you can't overcome them if the code drives the pin down hard at startup.

Off the top of my head I couldn't tell you the boot sequence with regard to GPIOs, but dt-blob.bin, the config.txt "gpio=" declarations and the HAT EEPROM GPIOs all get processed fairly close together. There's then quite a gap while the kernel, Device Tree and overlays are loaded and processed, before the kernel is launched.

OK, reading your message again I think I see now the issue: setting a CS GPIO to an output but with the wrong polarity would cause it to overcome the pull - internal or external - and assert CS prematurely. So my question is, why get the HAT to declare the pin as an output at all? The kernel should be able to transition a pin from being an input with a pull to an output driving in the same direction without glitching, so leave it to the kernel.

What have I missed?

mlyle commented

I like things being driven early for noise margin, etc. And there's some safety with setting pin directions always in the hat, etc, so that if the wrong hardware is attached subsequent software isn't dangerous. I was thinking this was the desired/best practice.

After all, why bother with a HAT EEPROM at all, if you're just going to leave everything to userland. There's no reason to configure any of the pins at all if they're completely passively safe in the default configuration. Instead, we have this ability to configure pins, so it might as well be useful.

Instead, we have this ability to configure pins, so it might as well be useful.

Except in this case I think the usefulness is questionable, making it seem more like "so we might as well use it".

I think the best use for a HAT EEPROM is to get the correct overlay loaded automatically.

l1k commented

Okay, so the recommendation is to set these GPIOs to inputs in the HAT EEPROM with an appropriate pull, which may be augmented with an external pull. Understood. Actually that's what the RevPi project is already doing, it just seemed like a gap in the HAT EEPROM spec that output polarity cannot be defined, and we thought it might be minimally cleaner and safer to set them to outputs with correct polarity from the get-go. We'll stick with the existing (recommended) approach for now. Should we ever find that it's insufficient for some reason, I'll pipe up again. Thanks a lot Phil. :)

mlyle commented

@pelwell Well, if we don't think setting GPIO direction is useful (though I do), maybe the functionality should be deprecated. Leaving it there but broken in a way that doesn't make it useful is annoying.

I wasn't with Pi when the HAT EEPROM spec was defined, but my guess is that the ability to select GPIO inputs and output is to some extent an accident of the way the FSELs are implemented on the BCM2835 family of SoCs. In other devices the pinmux hardware has a single GPIO fsel, with pin direction and drive left to the GPIO block. Some devices may even have a top-level GPIO vs alternate function switch. I'm pretty sure the original focus was on the alternate functions to enable the various hardware interfaces.

As I said, I am prepared to make such a change, but only if I feel there is a real benefit to doing so. In the meantime, if you want to experiment with what the end result would be like you can mock it up using the gpio= config,txt directive: https://www.raspberrypi.com/documentation/computers/config_txt.html#gpio-control

mlyle commented

@pelwell Driving things hard early makes things more robust. 50kohm impedance isn't very noise tolerant, especially for things that are going offboard (to a hat, often in no enclosure or a plastic enclosure).

Driving to a preselected value--- which I think in all use cases can be the same as the pull direction --- is good.

As it is, people could easily be surprised by bus fights, etc, etc.

I also think it's safer/a best practice to just let the hat self-disclose how pins should be programmed, directions, etc. That way if you have the wrong hat on, terrible things are less likely to happen.