linux-embedded-hal

repository·master·Indexed 43 days ago

https://github.com/rust-embedded/linux-embedded-hal

Implementation of the embedded-hal traits for Linux devices, enabling the use of generic embedded drivers on Linux hardware. Version 0.5.0 provides support for GPIO (via cdev and sysfs), I2C, SPI, Serial, and Delay traits, bridging Linux kernel interfaces with the hardware abstraction layer.

Tokens
5.6K
Snippets
25
Records
29
Agent score
54%

What's inside linux-embedded-hal

  1. Overview of linux-embedded-hal

    master
    The linux-embedded-hal crate provides implementations of the [embedded-hal] traits specifically for Linux devices. It allows developers to use standard embedded-hal drivers on Linux-based hardware by bridging the gap between Linux kernel interfaces and the hardware abstraction layer traits.
  2. Configure linux-embedded-hal features

    master

    By default, linux-embedded-hal includes standard features. To minimize dependencies or use specific hardware interfaces, you can use default-features = false and enable only the features you need.

    Available features:

    • gpio_cdev: Provides CdevPin as a wrapper around LineHandle from the gpio-cdev crate. This is the modern replacement for the deprecated sysfs GPIO interface.
    • gpio_sysfs: Provides SysfsPin for interacting with GPIO via the (now deprecated) sysfs interface.
    • i2c: Enables I2C support.
    • spi: Enables SPI support.
    # Example configuration for minimal features including GPIO character device
    linux-embedded-hal = { version = "0.4", default-features = false, features = ["gpio_cdev"] }
  3. Use GPIO character device (gpio_cdev)

    master

    Since Linux kernel v4.4, the character device GPIO interface is preferred over the deprecated sysfs GPIO. To use the character device interface, enable the gpio_cdev feature in your Cargo.toml.

    Important Note: When using CdevPin (which wraps gpio-cdev's LineHandle), you must assign the pin to a variable to ensure the LineHandle file descriptor remains open. If the handle is dropped, the GPIO line may close prematurely.

    linux-embedded-hal = { version = "0.4", features = ["gpio_cdev"] }
  4. Use linux-embedded-hal with embedded-hal drivers

    master

    This crate provides implementations of the embedded-hal traits for Linux-based devices. By using this crate, you can leverage platform-agnostic drivers available on crates.io that are designed to work with the embedded-hal ecosystem. You can enable specific peripheral support (I2C, SPI, Serial, GPIO) via Cargo features.

    /* 
    To use this crate, ensure your Cargo.toml includes the necessary features for the peripherals you need, for example:
    
    [dependencies]
    linux-embedded-hal = { version = "0.5.0", features = ["i2c", "spi", "gpio_cdev"] }
    */
  5. The Periodic trait

    master

    The Periodic marker trait indicates that a timer is designed to automatically restart its countdown immediately after the previous countdown finishes.

    When a timer implements Periodic, calling wait() after a successful Ok result will trigger a new cycle. If a timer does not implement Periodic, the behavior of calling wait() after the last call returned Ok is unspecified (implementers are encouraged to panic to signal error).

  6. Use SpidevBus for direct SPI bus access and software-controlled Chip-Select

    master

    Use SpidevBus when you need direct access to the underlying SPI bus rather than a single managed device. This is useful for:

    • Using GPIO pins as software-controlled CS pins to share a bus manually.
    • Drivers that require control over the entire bus (e.g., smart LED drivers).

    Critical Usage Constraints:

    1. CS Pin Behavior: The CS pin associated with the spidev device used to create the SpidevBus will be asserted whenever any device accesses this bus. It is recommended to use a dummy spidev device associated with an unused/unconnected CS pin.
    2. Exclusivity: No other spidev devices on the same bus should be used while a SpidevBus instance exists, as Linux does not guarantee exclusive access.
    3. Configuration: You can configure the underlying spidev::Spidev instance with the SPI_NO_CS flag (from spidev::SpiModeFlags) to prevent any CS pin activity.

    If you are sharing a bus using GPIOs, consider using the embedded-hal-bus crate in conjunction with SpidevBus.

    // Example usage pattern
    let mut bus = SpidevBus::open("/dev/spidev0.0")?;
    // bus now implements embedded_hal::spi::SpiBus
  7. Use SpidevDevice for single SPI devices with Linux-managed Chip-Select

    master

    Use SpidevDevice when you want to interact with a single SPI device where the Chip-Select (CS) pin is already managed by the Linux kernel (e.g., defined in the device tree).

    Key characteristics:

    • Implements the embedded_hal::spi::SpiDevice trait, which is the standard requirement for most drivers.
    • Linux handles bus sharing between different devices and processes.
    • It wraps a spidev::Spidev instance, allowing you to access the underlying struct for reconfiguration.
    • Note: Delay operations (SpiOperation::DelayUs) are capped at 65,535 microseconds.
    // Example usage pattern
    let mut device = SpidevDevice::open("/dev/spidev0.0")?;
    // device now implements embedded_hal::spi::SpiDevice
  8. Use SysTimer for delays and periodic timing

    master

    SysTimer is a timer implementation based on std::time::Instant. It implements the CountDown and Periodic traits, making it suitable for creating delays or periodic tasks.

    Key Behaviors

    • Initialization: Use SysTimer::new() to create an instance. The initial duration is 0, so you must call start() before calling wait().
    • Starting a timer: Call start(count) where count can be any type that implements Into<Duration> (e.g., Duration::from_millis(1000)).
    • Waiting: Use wait() to check if the duration has elapsed. Because wait() is non-blocking (returning nb::Result), you should use the nb::block! macro to wait until the timer finishes.
    • Periodicity: SysTimer is a Periodic timer. When wait() returns Ok, it automatically restarts the timer for the next interval.
    use std::time::Duration;
    use nb::block;
    use linux_embedded_hal::SysTimer;
    use linux_embedded_hal::CountDown;
    
    fn main() {
        let mut timer = SysTimer::new();
    
        // Start a 1-second countdown
        timer.start(Duration::from_millis(1000)).unwrap();
    
        // Blocks execution for 1 second
        block!(timer.wait()).unwrap();
    }
  9. Use Delay and Timers

    master

    This crate provides timing and delay utilities for Linux.

    Available types:

    • Delay: A delay implementation.
    • SysTimer: A system timer.
    • CountDown: A trait for countdown timers.
    • Periodic: A trait for periodic timers.
    use linux_embedded_hal::delay::Delay;
    use linux_embedded_hal::timer::SysTimer;
    
    // Example usage of Delay or SysTimer
  10. Handle SysfsPinError

    master

    Errors encountered during GPIO operations are wrapped in SysfsPinError. This error type implements embedded_hal::digital::Error. To access the underlying sysfs_gpio::Error, use the .inner() method.

    // Assuming an error occurred during a pin operation
    match result {
        Err(e) => {
            let inner_err = e.inner();
            println!("Sysfs error: {}", inner_err);
        }
        Ok(_) => println!("Success"),
    }
  11. Access GPIO via Cdev (Character Device)

    master

    When the gpio_cdev feature is enabled, you can use the CdevPin type to interact with GPIO pins via the Linux character device interface. This is a modern alternative to the sysfs interface.

    Available types:

    • CdevPin: The pin wrapper for character device access.
    • CdevPinError: Error type for Cdev GPIO operations.
    use linux_embedded_hal::gpio_cdev::CdevPin;
    
    // Usage depends on the specific CdevPin implementation details