• Stars
    star
    210
  • Rank 187,585 (Top 4 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 6 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rust interface to the Linux GPIO Character Device API (/dev/gpiochip...)

gpio-cdev

Build Status Version License

rust-gpio-cdev is a Rust library/crate providing access to GPIO character device ABI. This API, stabilized with Linux v4.4, deprecates the legacy sysfs interface to GPIOs that is planned to be removed from the upstream kernel after year 2020 (which is coming up quickly).

Use of this API is encouraged over the sysfs API used by this crate's predecessor sysfs_gpio if you don't need to target older kernels. For more information on differences see Sysfs GPIO vs GPIO Character Device.

Installation

Add the following to your Cargo.toml

[dependencies]
gpio-cdev = "0.4"

Note that the following features are available:

  • async-tokio: Adds a Stream interface for consuming GPIO events in async code within a tokio runtime.

Examples

There are several additional examples available in the examples directory.

Read State

use gpio_cdev::{Chip, LineRequestFlags};

// Read the state of GPIO4 on a raspberry pi.  /dev/gpiochip0
// maps to the driver for the SoC (builtin) GPIO controller.
let mut chip = Chip::new("/dev/gpiochip0")?;
let handle = chip
    .get_line(4)?
    .request(LineRequestFlags::INPUT, 0, "read-input")?;
for _ in 1..4 {
    println!("Value: {:?}", handle.get_value()?);
}

Mirror State (Read/Write)

use gpio_cdev::{Chip, LineRequestFlags, EventRequestFlags, EventType};

// Lines are offset within gpiochip0; see docs for more info on chips/lines
//
// This function will synchronously follow the state of one line
// on gpiochip0 and mirror its state on another line.  With this you
// could, for instance, control the state of an LED with a button
// if hooked up to the right pins on a raspberry pi.
fn mirror_gpio(inputline: u32, outputline: u32) -> Result<(), gpio_cdev::Error> {
    let mut chip = Chip::new("/dev/gpiochip0")?;
    let input = chip.get_line(inputline)?;
    let output = chip.get_line(outputline)?;
    let output_handle = output.request(LineRequestFlags::OUTPUT, 0, "mirror-gpio")?;
    for event in input.events(
        LineRequestFlags::INPUT,
        EventRequestFlags::BOTH_EDGES,
        "mirror-gpio",
    )? {
        let evt = event?;
        println!("{:?}", evt);
        match evt.event_type() {
            EventType::RisingEdge => {
                output_handle.set_value(1)?;
            }
            EventType::FallingEdge => {
                output_handle.set_value(0)?;
            }
        }
    }

    Ok(())
}

Async Usage

Note that this requires the addition of the async-tokio feature.

use futures::stream::StreamExt;
use gpio_cdev::{Chip, AsyncLineEventHandle};

async fn gpiomon(chip: String, line: u32) -> gpio_cdev::Result<()> {
    let mut chip = Chip::new(args.chip)?;
    let line = chip.get_line(args.line)?;
    let mut events = AsyncLineEventHandle::new(line.events(
        LineRequestFlags::INPUT,
        EventRequestFlags::BOTH_EDGES,
        "gpioevents",
    )?)?;

    while let Some(event) = events.next().await {
        let event = event?;
        println!("GPIO Event: {:?}", event);
    }

    Ok(())
}

Sysfs GPIO vs GPIO Character Device

Compared to the sysfs gpio interface (as made available by the sysfs_gpio crate) the character device has several advantages and critical design differences (some of which are driving the deprecation in the kernel).

Since many people are familiar with the sysfs interface (which is easily accessible via basic commands in the shell) and few people are familiar with the GPIO character device, an exploration of the two and key differences here may prove useful.

Getting Access to a GPIO

In the Linux kernel, individual GPIOs are exposed via drivers that on probe register themselves as GPIO chips with the gpio subsystem. Each of these chips provides access to a set of GPIOs. At present, when this chip is registered a global base number is assigned to this driver. The comments from the linux kernel gpio_chip_add_data sum up the situation nicely when assigning the a base number to a GPIO chip on registration.

/*
 * TODO: this allocates a Linux GPIO number base in the global
 * GPIO numberspace for this chip. In the long run we want to
 * get *rid* of this numberspace and use only descriptors, but
 * it may be a pipe dream. It will not happen before we get rid
 * of the sysfs interface anyways.
 */

The entire sysfs interface to GPIO is based around offsets from the base number assigned to a GPIO chip. The base number is completely dependent on the order in which the chip was registered with the subsystem and the number of GPIOs that each of the previous chips registered. The only reason this is usable at all is that most GPIOs are accessed via SoC hardware that is registered consistently during boot. It's not great; in fact, it's not even good.

The GPIO character device ABI provides access to GPIOs owned by a GPIO chip via a bus device, /sys/bus/gpiochipN (or /dev/gpiochipN). Within a chip, the programmer will still need to know some details about how to access the GPIO but things are generally sane. Figuring out which bus device is the desired GPIO chip can be done by iterating over all that are present and/or setting up appropriate udev rules. One good example of this is the lsgpio utility in the kernel source.

In sysfs each GPIO within a chip would be exported and used individually. The GPIO character device allows for one or more GPIOs (referenced via offsets) to be read, written, configured, and monitored via a "linehandle" fd that is created dynamically on request.

"Exporting" a GPIO

Using the sysfs API, one would write the global GPIO number to the "export" file to perform further operations using new files on the filesystem. Using the gpiochip character device, a handle for performing operations on one or more GPIO offsets within a chip are available via a "linehandle" fd created using the GPIO_GET_LINEHANDLE_IOCTL. A consequence of this is that a line will remember its state only for as long as the fd is open; the line's state will be reset once the fd is closed.

When a linehandle is requested, additional information is also included about how the individual GPIOs will be used (input, output, as-is, active-low, open drain, open source, etc). Multiple lines can be grouped together in a single request but they must all be configured the same way if being used in that way. See struct gpioevent_request.

Reading/Writing GPIOs

Via sysfs, GPIOs could be read/written using the value file. For GPIO character devices, the GPIOHANDLE_GET_LINE_VALUES_IOCTL and GPIOHANDLE_SET_LINE_VALUES_IOCTL may be used to get/set the state of one or more offsets within the chip.

Input Events

Via sysfs, one could setup things up using the trigger file to notify userspace (by polling on the value file) of a single event based on how things were setup. With GPIO character devices, one can setup a gpio_eventrequest that will create a new anonymous file (fd provided) for event notifications on a lines within a gpiochip. Contrary to sysfs gpio events, the event file will queue multiple events and include with the event (best effort) nanosecond-precision timing and an identifier with event type.

With this information one could more reasonably consider interpreting a basic digital signal from userspace (with rising and falling edges) from userspace using the queueing with timing information captured in the kernel. Previously, one would need to quickly handle the event notification, make another system call to the value file to see the state, etc. which had far too many variables involved to be considered reliable.

Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.65.0 and up. It might compile with older versions but that may change in any new patch release.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Code of Conduct

Contribution to this crate is organized under the terms of the Rust Code of Conduct, the maintainer of this crate, the Embedded Linux Team, promises to intervene to uphold that code of conduct.

More Repositories

1

rust-raspberrypi-OS-tutorials

📚 Learn to write an embedded OS in Rust 🦀
Rust
13,436
star
2

awesome-embedded-rust

Curated list of resources for Embedded and Low-level development in the Rust programming language
6,173
star
3

embedded-hal

A Hardware Abstraction Layer (HAL) for embedded systems
Rust
1,977
star
4

wg

Coordination repository of the embedded devices Working Group
1,892
star
5

heapless

Heapless, `static` friendly data structures
Rust
1,492
star
6

discovery

Discover the world of microcontrollers through Rust!
Rust
1,458
star
7

book

Documentation on how to use the Rust Programming Language to develop firmware for bare metal (microcontroller) devices
1,083
star
8

riscv

Low level access to RISC-V processors
Rust
820
star
9

cortex-m

Low level access to Cortex-M processors
Rust
801
star
10

cortex-m-quickstart

Template to develop bare metal applications for Cortex-M microcontrollers
Rust
786
star
11

svd2rust

Generate Rust register maps (`struct`s) from SVD files
Rust
685
star
12

cargo-binutils

Cargo subcommands to invoke the LLVM tools shipped with the Rust toolchain
Rust
488
star
13

rust-sysfs-gpio

A Rust Interface to the Linux sysfs GPIO interface (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt)
Rust
383
star
14

cortex-m-rt

Minimal startup / runtime for Cortex-M microcontrollers
Rust
357
star
15

riscv-rt

Minimal runtime / startup for RISC-V CPU's.
Rust
299
star
16

embedded-alloc

A heap allocator for embedded systems
Rust
295
star
17

linux-embedded-hal

Implementation of the `embedded-hal` traits for Linux devices
Rust
233
star
18

embedonomicon

How to bootstrap support for a no_std target
Rust
206
star
19

rust-i2cdev

Rust library for interfacing with i2c devices under Linux
Rust
205
star
20

rust-spidev

Rust library providing access to spidev devices under Linux
Rust
121
star
21

not-yet-awesome-embedded-rust

A collection of items that are not yet awesome in Embedded Rust
120
star
22

cortex-a

Low level access to Cortex-A processors
Rust
120
star
23

bare-metal

Abstractions common to microcontrollers
Rust
114
star
24

meta-rust-bin

Yocto layer for installing Rust toolchain from pre-built binaries
BitBake
102
star
25

critical-section

Pluggable critical section
Rust
97
star
26

gpio-utils

Userspace Utilities for managing GPIOs in Linux
Rust
94
star
27

showcase

Awesome embedded projects by the Rust community!
CSS
91
star
28

nb

Minimal and reusable non-blocking I/O layer
Rust
87
star
29

rust-embedded.github.io

A collection of books and other documents about embedded Rust
84
star
30

blog

The Rust Embedded WG Blog
SCSS
71
star
31

svd

A CMSIS-SVD file parser
Rust
70
star
32

r0

Initialization code ("crt0") written in Rust
Rust
69
star
33

aarch64-cpu

Low level access to processors using the AArch64 execution state.
Rust
65
star
34

svdtools

Python package to handle vendor-supplied, often buggy SVD files.
Rust
60
star
35

debugonomicon

Shell
60
star
36

rust-sysfs-pwm

Linux PWM Access via Sysfs in Rust
Rust
47
star
37

register-rs

Unified interface for type-safe MMIO and CPU register access in Rust
Rust
46
star
38

fixedvec-rs

Heapless vector implementation for Rust
Rust
45
star
39

qemu-exit

Exit QEMU with user-defined code
Rust
40
star
40

cortex-m-semihosting

Semihosting for ARM Cortex-M processors
Rust
40
star
41

msp430

Low level access to MSP430 microcontrollers
Rust
36
star
42

msp430-quickstart

Template to develop bare metal applications for MSP430 microcontrollers
Rust
36
star
43

embedded-dma

Rust
35
star
44

volatile-register

Volatile access to memory mapped hardware registers
Rust
34
star
45

itm

Tool to parse and dump ITM packets
Rust
28
star
46

mutex-trait

Low level API definition of a Mutex
Rust
25
star
47

msp430-rt

Minimal startup / runtime for MSP430 microcontrollers
Rust
15
star
48

patterns

A book capturing different approaches or patterns for solving problems in Embedded Rust
15
star
49

docker-rust-cross

Docker images for testing rust code on many versions and architecures (DEPRECATED)
Shell
13
star
50

panic-semihosting

Report panic messages to the host stderr using semihosting
Rust
12
star
51

cortex-r

Low level access to Cortex-R processors
Shell
11
star
52

arm-dcc

Debug Communication Channel (DCC) API
Rust
9
star
53

rust-embedded-www

The Rust embedded website: http://www.rust-embedded.org
HTML
7
star
54

panic-itm

Log panic messages using the ITM (Instrumentation Trace Macrocell)
Rust
6
star
55

rust-embedded-provisioning

Terraform provisioning for Rust Embedded infrastructure
HCL
2
star
56

template

Rust
1
star
57

discovery-mb2

Rust Discovery Book for BBC micro::bit v2
Rust
1
star