The gpio interface

gpio allows access to a specific GPIO pin. The interface is restricted because it provides privileged access to GPIO hardware.

Use snap interface gpio to see which gpio devices are available on the system:

$ snap interface gpio
name:    gpio
summary: allows access to a specific GPIO pin
slots:
  - pi:bcm-gpio-0
  - pi:bcm-gpio-1
  - pi:bcm-gpio-10
[...]

Example

The pi-fancontrol snap provides simple fan control on a Raspberry Pi with a fan connected to GPIO 14 (pin 8). With the snap installed, the following command will connect the interface to the pin:

snap connect pi-fancontrol:gpio pi:bcm-gpio-14
Interface documentation:

See Interface management and Supported interfaces for further details on how interfaces are used.


Developer details

Auto-connect: no
Attributes:

  • number (slot): GPIO pin number to export and expose to consuming snaps

Hardware IO interfaces covers some general considerations common to these kinds of devices.

To use a gpio device, the snap developer must add plugs: [ gpio ] to a snap’s snapcraft.yaml. The snap user can then access a specific gpio device with an interface connection.

Unless the snap is expected to actually use a set of gpio pins that is not predefined, it is recommended to define distinct plugs for each used gpio pin, like:

plugs:
  activity-led:
    interface: gpio
  warning-led:
    interface: gpio

This has the advantage of being self-documenting and 1-1 connections like these are easier to track and setup with auto-connections, if the latter is needed.

When the interface is connected, "echo (pin number) > /sys/class/gpio/export" is run internally to enable access to the GPIO pin.

Once connected, the consuming snap can use the device via /sys/class/gpio/gpioN where N is the pin number specified by the connected slot.

Finally, when the interface is disconnected, "echo (pin number) > /sys/class/gpio/unexport" is run internally to disable access to the GPIO pin.

Code examples

The hook and control scripts for pi-fancontrol can be found in the project’s GitHub repository: https://github.com/ogra1/pi-fancontrol-snap

The source code for the GPIO interface is in the snapd repository: https://github.com/snapcore/snapd/blob/master/interfaces/builtin/gpio.go.

1 Like

Hi, I’m having some issues using the gpio interface, not sure if I’m using it correctly.

Snaps that want to consume a gpio device simply plugs: [ gpio ] and the gpio device to connect is specified during interface connection

What does [ gpio] mean here? I have a sample snapcraft.yaml which used to work for me which had:

apps:
  scan:
    command: node $SNAP/lib/node_modules/something/something.js
    daemon: simple
    plugs:
      - network
      - gpio-30
      - gpio-31
      - gpio-117
      - gpio-118

However this doesn’t seem to work. The code is unable to access the gpio pins:

2019-02-08T10:09:19Z br-forklift.scan[31421]: /bin/sh: 1: cannot create /sys/class/gpio/gpio117/value: Permission denied
2019-02-08T10:09:19Z br-forklift.scan[31421]: { Error: Command failed: echo 0 > /sys/class/gpio/gpio117/value
2019-02-08T10:09:19Z br-forklift.scan[31421]: /bin/sh: 1: cannot create /sys/class/gpio/gpio117/value: Permission denied

In the output of snap interfaces, the slot is showing as - for my application like:

-                             br-forklift:gpio-117
-                             br-forklift:gpio-118
-                             br-forklift:gpio-30
-                             br-forklift:gpio-31

This doesn’t seem right, though from the snapcraft file it looks correct. Any ideas to why this might be?

Can you please add a small sample in this doc to make it clear.

You need to connect the gpio plugs to a gadget snap that slots those. For example, on the raspberry pi you would do

snap connect br-forklift:gpio-117 pi:gpio-117

(not sure what gadget snap you’re using on this device)

I am also having trouble specifying specific pins with the gpio plug.
I am trying to use the gpio-N plugs, following the example posted by @tavish

  monitor:
    command: bin/monitor
    daemon: simple      
    plugs:
      - gpio-22 
      - gpio-17 
      - gpio-27 
      - gpio-7 

But I get an error message when uploading to the snap store.
unknown plugs interface name reference 'gpio-17' lint-snap-v2_app_plugs_plug_reference

I am currently using core20 base with devmode confinement. The output of snap interfaces ouputs:

:gpio-control              -
:gpio-memory-control       -

which suggests the gpio interface isn’t supported.
The output of snap connections --all doesn’t list anything related to gpio. I am building off a Raspberry Pi 4 running Ubuntu Server 20.04

When you are using the plug side, you just specify the interface name, so this would just be:

plugs:
 - gpio

and then when it comes time to connect after you have installed your snap, you would use:

snap connect your-snap:gpio the-gadget-snap:gpio-22
snap connect your-snap:gpio the-gadget-snap:gpio-17
...

where the-gadget if you are on an Ubuntu Core Raspberry Pi image would be just pi for example

We don’t currently have a gadget snap installed on classic Server images for the Raspberry Pi, you would need to use an Ubuntu Core image to get the gpio slots provided by a gadget snap as explained above. If you need to use the classic Server image, you will need to build your own (classic) gadget snap which exposes these interface slots.

Thanks. I do ultimately want to install this on a UbuntuCore, but would prefer to develop/test directly on UbuntuServer for simplicity.
I’ll look into building a devmode gadget snap based on the 20-armhf branch.

When trying to install the pi gadget snap, the error
- Mount snap "pi" (unset) (cannot install gadget snap on classic if not requested by the model)
shows up. I think that’s what you referred to when you mentioned I needed to build my own classic gadget snap. But this still occurred after I’ve built the pi gadget snap (from the 20-arm64 branch), and changed the confinement to classic in its snapcraft.yaml

$ sudo snap install pi_20-1_arm64.snap --classic --dangerous
error: cannot perform the following tasks:
- Mount snap "pi" (unset) (cannot install gadget snap on classic if not requested by the model)

I think I misunderstand what’s meant by “classic requested by the model”. Can you share more details relating to building a classic-mode gadget?

You need to seed the image with a model assertion that references the classic gadget. You can see more information on building a model assertion at https://core.docs.ubuntu.com/en/image/image-building. The things that will change is that you will not have a kernel snap, the model will be a classic one, and you will need to call snap prepare-image --classic manually (instead of using ubuntu-image as explained in the docs). I think this all is sufficiently complicated to start a new forum post about it

1 Like

As discussed now in the documentation this is not very self-documenting though, so the recommended approach is possibly to have:

plugs:
  gpio-22:
    interface: gpio
  gpio-17:
    interface: gpio
  gpio-27:
    interface: gpio
  gpio-7:
    interface: gpio

or possibly even more purporse related plug names.

1 Like

The documentation doesn’t explain that the gpio interface slots need to be provided by a gadget. Without that, there will be no slots to connect to:

$ snap interface gpio
name:    gpio
summary: allows access to specific GPIO pin
1 Like

It might be worthwhile to provide a pointer to the kernel GPIO documentation, which explains that in general leveraging existing kernel drivers (e.g. restart-gpio) which provide GPIO support is preferred to using the userspace ABI(s). Note, there are certain use cases where use of the userspace ABI(s) are totally appropriate. Providing this link as a reference will hopefully influence developers to understand the bigger picture.