Git Product home page Git Product logo

linux-embedded-hal's Introduction

crates.io crates.io Documentation Minimum Supported Rust Version

linux-embedded-hal

Implementation of the embedded-hal traits for Linux devices

This project is developed and maintained by the Embedded Linux team.

GPIO character device

Since Linux kernel v4.4 the use of sysfs GPIO was deprecated and replaced by the character device GPIO. See gpio-cdev documentation for details.

This crate includes feature flag gpio_cdev that exposes CdevPin as wrapper around LineHandle from gpio-cdev. To enable it update your Cargo.toml. Please note that in order to prevent LineHandle fd from closing you should assign to a variable, see cdev issue for more details.

linux-embedded-hal = { version = "0.4", features = ["gpio_cdev"] }

SysfsPin can be still used with feature flag gpio_sysfs.

With default-features = false you can enable the features gpio_cdev, gpio_sysfs, i2c, and spi as needed.

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 HAL team, promises to intervene to uphold that code of conduct.

linux-embedded-hal's People

Contributors

adamgreig avatar almusil avatar bors[bot] avatar caemor avatar cbjamo avatar dbrgn avatar dfrankland avatar disasm avatar eldruin avatar gszy avatar homunkulus avatar iicurtis avatar japaric avatar kelnos avatar lehmaxence avatar leseulartichaut avatar mathk avatar peckpeck avatar qrasmont avatar reitermarkus avatar rnestler avatar ryankurte avatar sirhcel avatar therealprof avatar tommy-gilligan avatar wose avatar zuckschwerdt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linux-embedded-hal's Issues

impl embedded_hal::digital::Error for linux_embedded_hal::gpio_cdev::Error

I'm trying to write an initialisation function for a driver, but the fact that the pin initialisation functions don't give me an embedded-hal Error trait is being a bit of a pain in the behind for me.
I can't properly incorperate the errors that arise when setting up gpios in my drivers error enum.

My situation is an SPI device that has two additional gpios, a reset and an interrupt pin.
This is a very hardware specific driver so the pins and spidev are created in the driver::new() function.

The linux_embedded_hal::spi::SPIError does implement embedded_hal::spi::Error so that one is fine I think.

Is this a workable idea?

Async-tokio DelayNs implementation inaccurate for delays shorter than a few ms

hey fyi tokio::time::sleep is only good down to ms resolutions, for more granularity we typically need something nanosleep or a hot loop, so this implementation won't be accurate for anything less than a couple of ms.

having had to solve this a couple of times i suspect a more accurate way to do this would involve using epoll_wait with a timeout for > 1us delays (more accurate kernel timing than sleep is, particularly under the tokio runtime) and a hot loop over Instant::elapsed() for > 1ns delays (check elapsed and hit the waker every round).

possibly combining both into something like:

let now = Instant::now()
loop {
  // Grab elapsed at the start of the loop
  let elapsed = now.elapsed();

  // Break once we exceed the delay duration
  if elapsed > duration {
    break;
  }

  // Calculate the remaining sleep time
  let remainder = duration - elapsed;

  // epoll or spin depending on remainder
  if remainder > Duration::from_millis(1) {
    epoll_sleep().await;
  } else {
    spin_sleep().await;
  }
}

some folks do more complex things to balance accuracy and cpu use, but, this is fairly straightforward and would be closer to operating as intended.
(it's also good to keep track of elapsed times because there are reasons a sleep might end early, which has caused problems for me in the past)

Originally posted by @ryankurte in #109 (comment)

Update Crate Release

Currently trying to build with gpio-cdev feature flag like
linux-embedded-hal = { version ="0.3.0", features = ["gpio_cdev"] }

Gives the error

error: failed to select a version for `linux-embedded-hal`.
    ... required by package `myPackage v0.1.0 (/project)`
versions that meet the requirements `=0.3.0` are: 0.3.0

the package `myPackage` depends on `linux-embedded-hal`, with features: `gpio_cdev` but `linux-embedded-hal` does not have these features.


failed to select a version for `linux-embedded-hal` which could resolve this conflict

Version 0.3.0 of linux-embedded-hal was released in December 2019. gpio-cdev support was merged in afterward in March, 2020.

embedded_hal::serial::Read is not implemented as nonblocking

The embedded_hal::serial::Read trait defines its read method with a nb::Result. This suggests Read::read being nonblocking. But, linux_embedded_hal::Serial implements this trait by calling serial_unix::TTYPort::read which internally uses ppoll.

By default, the timeout passed to ppoll is 100ms, which results in read blocking for that amount of time. (Instead of immediately returning nb::Error::WouldBlock.)

GPIO input and outputs should be different types

Currently the pins always implement both InputPin and OutputPin even thought the pin might not be in the correct mode, and presumably trying to use it in the wrong mode either doesn't work or causes an error.

This could be done neatly with type states and into_output style methods like many other HALs. This would also make them more convenient to use as the user then doesn't have to manually set the correct mode before constructing the pin.

New crates.io release

Would be great to have a release of the current master on crates.io. One of my driver crates can't be published yet because a public release with Serial support is still missing.

v0.4.0 is missing embedded_hal_0_2::blocking::i2c traits?

This breaks when moving from 0.3.2 to [0.4.0-alpha.1](https://github.com/rust-embedded/linux-embedded-hal/compare/v0.3.0...v0.4.0-alpha.1) -- but the changelog does not mention this?

error[E0277]: the trait bound `I2cdev: _embedded_hal_blocking_i2c_Write` is not satisfied
  --> examples/basic.rs:12:26
   |
12 |         Rv8803::from_i2c(i2c, rv8803::bus::Address::Default).expect("Failed to initialize RV8803");
   |         ---------------- ^^^ the trait `_embedded_hal_blocking_i2c_Write` is not implemented for `I2cdev`
   |         |
   |         required by a bound introduced by this call
   |
note: required by a bound in `rv8803::<impl Rv8803<Bus<'a, I2C>>>::from_i2c`
  --> /home/mike/esp/rv8803/src/lib.rs:29:11
   |
29 |         + embedded_hal_0_2::blocking::i2c::Write<Error = E>,
   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `rv8803::<impl Rv8803<Bus<'a, I2C>>>::from_i2c`
...
39 |     pub fn from_i2c(i2c: I2C, address: crate::bus::Address) -> Result<Self, E> {
   |            -------- required by a bound in this associated function

error[E0277]: the trait bound `I2cdev: WriteRead` is not satisfied
  --> examples/basic.rs:12:26
   |
12 |         Rv8803::from_i2c(i2c, rv8803::bus::Address::Default).expect("Failed to initialize RV8803");
   |         ---------------- ^^^ the trait `WriteRead` is not implemented for `I2cdev`
   |         |
   |         required by a bound introduced by this call
   |
note: required by a bound in `rv8803::<impl Rv8803<Bus<'a, I2C>>>::from_i2c`
  --> /home/mike/esp/rv8803/src/lib.rs:28:10
   |
28 |     I2C: embedded_hal_0_2::blocking::i2c::WriteRead<Error = E>
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `rv8803::<impl Rv8803<Bus<'a, I2C>>>::from_i2c`
...
39 |     pub fn from_i2c(i2c: I2C, address: crate::bus::Address) -> Result<Self, E> {
   |            -------- required by a bound in this associated function

Linux PREEMPT_RT

Hi,
Wondering if anyone has taken at stab at using the Linux PREEMPT_RT patch with Rust to run some real-time(ish) tasks?
Thanks,

Enable i2c as a feature?

The dependency on i2cdev for i2c is currently the only thing tying this to linux. I confirmed this crate to compile and work on unix with i2c removed.
Would it be an option to offer i2c as a (default enabled) feature?

Add example?

Greetings.
I was kind of having a hard time getting the grasp of trying to use the digital GPIO pin. I worked it out in the end anyway, but I think it would be cool to add basic examples as simple as LED blinking, LED breathing, etc. like this:

extern crate linux_embedded_hal as hal;

use hal::sysfs_gpio::{Pin, Direction};
use std::error::Error;
use std::thread;
use std::time::Duration;

fn main() -> Result<(), Box<dyn Error>> {
    let gpio = Pin::new(198);

    match gpio.export() {
        Ok(()) => println!("Gpio {} exported!", gpio.get_pin()),
        Err(err) => println!("Gpio {} could not be exported: {}", gpio.get_pin(), err)
    }

    gpio.set_direction(Direction::Out)?;
    gpio.set_value(1)?;
    thread::sleep(Duration::from_secs(1));
    gpio.set_value(0)?;

    Ok(())
}

Get "-bash: ./test: No such file or directory" error on BeagleBone

When I use the below configuration and cross compile to ARMv7 I get the following error message on the BeagleBone:

debian@beaglebone:~$ ./test 
-bash: ./test: No such file or directory

When I use v0.2.2 of linux-embedded-hal or earlier I do not get this error. If I remove extern crate linux_embedded_hal as hal; from the code I do not get the error.

Any ideas?

The code

src/main.rs

extern crate linux_embedded_hal as hal;

fn main() {
    println!("Hello");
}

.cargo/config

[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-gnueabihf-gcc"
rustflags = ["-Clink-args=-Xlinker -rpath=/usr/lib/arm-linux-gnueabihf"]

Cargo.toml

[package]
name = "test"
version = "0.1.0"
edition = "2018"

[dependencies]
linux-embedded-hal = "0.4.0-alpha.0"

To compile I use:

cargo build --target=armv7-unknown-linux-musleabihf --release

Pin set_direction errors right after export

Hi, I'm using the Pin method for CS1 and CS2, also for 3 leds.
Here is how I'm using it:

        let cs_2 = Pin::new(16);
        cs_2.export().expect("Error: Error during CS2 export");
        cs_2.set_direction(Direction::High)
            .expect("Error: Setting CS2 pin as output");

So, when I do a first run, it fails:

System is Linux on armv7l hardware
OS Release is 5.10.33-v7l+
OS Version is #1415 SMP Fri Apr 30 15:50:57 BST 2021
Iniciating navigator module.
thread '<unnamed>' panicked at 'Error: Setting CS2 pin as output: Io(Os { code: 13, kind: PermissionDenied, message: "Permission denied" })', /home/raultrombin/.cargo/git/checkouts/navigator-rs-2872844b08e6ceff/cfe571b/src/lib.rs:131:14
stack backtrace:
   0: 0xb6f56e80 - std::backtrace_rs::backtrace::libunwind::trace::hd3840244c887d756
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1: 0xb6f56e80 - std::backtrace_rs::backtrace::trace_unsynchronized::hfa9aa3f288e7ea4d
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2: 0xb6f56e80 - std::sys_common::backtrace::_print_fmt::ha5dd1213f42cd24c
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/sys_common/backtrace.rs:65:5
   3: 0xb6f56e80 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h10e27ff4dc06f70d
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/sys_common/backtrace.rs:44:22
   4: 0xb6f72874 - core::fmt::rt::Argument::fmt::h6ca71d35b3cbe820
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/core/src/fmt/rt.rs:138:9
   5: 0xb6f72874 - core::fmt::write::h0dd162dfc1d20034
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/core/src/fmt/mod.rs:1094:21
   6: 0xb6f54ea8 - std::io::Write::write_fmt::h5e7c8c388c0530bc
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/io/mod.rs:1713:15
   7: 0xb6f56cb0 - std::sys_common::backtrace::_print::h85d5586bf00d40ec
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/sys_common/backtrace.rs:47:5
   8: 0xb6f56cb0 - std::sys_common::backtrace::print::h4e6afe6a16138b69
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/sys_common/backtrace.rs:34:9
   9: 0xb6f57f7c - std::panicking::default_hook::{{closure}}::h8cfdb93069a88529
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/panicking.rs:269:22
  10: 0xb6f57cc8 - std::panicking::default_hook::h686642dd8d4b0259
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/panicking.rs:288:9
  11: 0xb6f58678 - std::panicking::rust_panic_with_hook::h984f6dcc57afc0f1
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/panicking.rs:705:13
  12: 0xb6f5839c - std::panicking::begin_panic_handler::{{closure}}::hff00024b15d9e6b2
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/panicking.rs:597:13
  13: 0xb6f57314 - std::sys_common::backtrace::__rust_end_short_backtrace::hed49dc7f027d4b45
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/sys_common/backtrace.rs:151:18
  14: 0xb6f58154 - rust_begin_unwind
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/std/src/panicking.rs:593:5
  15: 0xb6f35b38 - core::panicking::panic_fmt::h79c5dd6da1f47f23
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/core/src/panicking.rs:67:14
  16: 0xb6f35eb4 - core::result::unwrap_failed::hc7b5d8b3e1351f6b
                       at /rustc/f0411ffcebcd7f75ac02ed45feb53ffd07b75398/library/core/src/result.rs:1651:5
  17: 0xb6f37510 - navigator_rs::Navigator::new::hcc0def6f7439095e
  18: 0xb6f3622c - navigator::NavigationManager::get_instance::he00dd8700ca85460
  19: 0xb6f36350 - init
  20:    0x10d78 - main
                       at /home/blueos/deploy/examples/cpp/main.cpp:26:7
  21: 0xb6c6d740 - __libc_start_main
                       at ./csu/libc-start.c:308:16
fatal runtime error: failed to initiate panic, error 9
Aborted

But during the next run it works, basically i have to run it 5 times before to have it working (the 5 first erros for each pin), on each boot of the OS.
Running it as sudo works at the fresh first time.

Unable to use embedded-hal SPI traits?

Hello,

I'm new, so apologies in advance for any mistakes. I'm trying to test an embedded-hal driver on a Raspberry Pi and get these errors:

the trait `embedded_hal::blocking::spi::write::Default<u8>` is not implemented for `hal::<unnamed>::Spidev

the trait `embedded_hal::blocking::spi::transfer::Default<u8>` is not implemented for `hal::<unnamed>::Spidev

My driver works on a Blue Pill board, what do I need to change for it to work with linux-embedded-hal?

Thanks :)

SPI struct implements both SpiBus and SpiDevice

Currently our Spidev wrapper struct implements both SpiBus and SpiDevice from embedded-hal. I think this is likely to lead to some confusion, especially since the SpiBus methods will still actually be using a shared SPI bus, toggling CS, and multiplexing with any other spidev devices on the same bus.

We discussed this a bit in #87 and while the main problem there is resolved by the new embedded-hal design, I think the split suggested is still worth considering. The proposal is to have two wrapper structs, SpidevBus and SpidevDevice perhaps, where:

  • SpidevBus implements just the SpiBus trait
    • we configure spidev to not drive the associated CS pin
    • we explain in the documentation that when this struct is used, it must be the only active spidev device on that bus
    • we encourage users to give it a CS pin that is not connected to anything, since whatever pin is assigned to it in the device tree can't be re-used as GPIO (and therefore can't be used as a CS)
    • this struct can then be used with any of the bus-multiplexing crates (like embedded-hal-bus) to generate lots of SpiDevice objects, using generic GPIO for CS control, or used when dedicated bus access is required (eg to generate smart LED waveforms)
    • we are basically lying to the kernel about it being a single device, because there's no way to request exclusive bus access with spidev
  • SpidevDevice implements just the SpiDevice trait
    • it's already a perfect fit for SpiDevice, the kernel handles sharing and CS for us, even with other programs
    • it will work just as users expect
    • but their device tree has to be set up to create the device and use the right CS

I'm happy to implement this as a PR if it sounds good to people, but it'd be great to get some feedback first or any suggestions on how it might be better done, especially if there's any clever spidev-related tricks that might be useful.

Unable to build on nightly (rustc 1.44.0-nightly (38114ff16 2020-03-21))

Steps to reproduce: git clone && cargo build:

>>= cargo -v build
       Fresh cfg-if v0.1.10
       Fresh void v1.0.2
       Fresh cc v1.0.50
       Fresh semver-parser v0.7.0
       Fresh version_check v0.9.1
       Fresh rustc-demangle v0.1.16
       Fresh nb v0.1.2
       Fresh semver v0.9.0
       Fresh libc v0.2.68
       Fresh bitflags v1.2.1
       Fresh rustc_version v0.2.3
       Fresh embedded-hal v0.2.3
       Fresh nix v0.14.1
       Fresh backtrace-sys v0.1.35
       Fresh nix v0.11.1
       Fresh byteorder v1.3.4
       Fresh termios v0.2.2
       Fresh serial-core v0.4.0
       Fresh ioctl-rs v0.1.6
       Fresh backtrace v0.3.46
       Fresh sysfs_gpio v0.5.4
       Fresh i2cdev v0.4.4
       Fresh spidev v0.4.0
       Fresh error-chain v0.12.2
       Fresh cast v0.2.3
       Fresh serial-unix v0.4.0
       Fresh gpio-cdev v0.2.0
   Compiling linux-embedded-hal v0.3.0 (/Users/r/prj/p/linux-embedded-hal)
     Running `rustc --crate-name linux_embedded_hal src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="gpio-cdev"' --cfg 'feature="gpio_cdev"' --cfg 'feature="gpio_sysfs"' --cfg 'feature="sysfs_gpio"' -C metadata=453f24c6b88d9603 -C extra-filename=-453f24c6b88d9603 --out-dir /Users/r/prj/p/linux-embedded-hal/target/debug/deps -C incremental=/Users/r/prj/p/linux-embedded-hal/target/debug/incremental -L dependency=/Users/r/prj/p/linux-embedded-hal/target/debug/deps --extern cast=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libcast-f695f5742b822139.rmeta --extern embedded_hal=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libembedded_hal-4c986ac6d091353f.rmeta --extern gpio_cdev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libgpio_cdev-713eeea279cdabc6.rmeta --extern i2cdev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libi2cdev-836156e2317b18cf.rmeta --extern nb=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libnb-c1350daed77af41f.rmeta --extern serial_core=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libserial_core-8f3a3c9ba21d72dd.rmeta --extern serial_unix=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libserial_unix-50fbf10e8f258cc6.rmeta --extern spidev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libspidev-19ef1dfbba2bd214.rmeta --extern sysfs_gpio=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libsysfs_gpio-9a66359ec333fd93.rmeta -L native=/Users/r/prj/p/linux-embedded-hal/target/debug/build/backtrace-sys-af67b5ab2dfcc035/out`
error[E0432]: unresolved import `i2cdev::linux`
  --> src/lib.rs:39:13
   |
39 | use i2cdev::linux::LinuxI2CMessage;
   |             ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:124:20
    |
124 |     inner: i2cdev::linux::LinuxI2CDevice,
    |                    ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:133:52
    |
133 |     pub fn new<P>(path: P) -> Result<Self, i2cdev::linux::LinuxI2CError>
    |                                                    ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:139:28
    |
139 |             inner: i2cdev::linux::LinuxI2CDevice::new(path, 0)?,
    |                            ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:145:66
    |
145 |     fn set_address(&mut self, address: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
    |                                                                  ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:147:34
    |
147 |             self.inner = i2cdev::linux::LinuxI2CDevice::new(&self.path, u16::from(address))?;
    |                                  ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:155:26
    |
155 |     type Error = i2cdev::linux::LinuxI2CError;
    |                          ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:164:26
    |
164 |     type Error = i2cdev::linux::LinuxI2CError;
    |                          ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:173:26
    |
173 |     type Error = i2cdev::linux::LinuxI2CError;
    |                          ^^^^^ could not find `linux` in `i2cdev`

error[E0433]: failed to resolve: could not find `linux` in `i2cdev`
   --> src/lib.rs:188:27
    |
188 |     type Target = i2cdev::linux::LinuxI2CDevice;
    |                           ^^^^^ could not find `linux` in `i2cdev`

warning: unused import: `I2CDevice`
  --> src/lib.rs:38:20
   |
38 | use i2cdev::core::{I2CDevice, I2CMessage, I2CTransfer};
   |                    ^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: unused import: `I2CMessage`
  --> src/lib.rs:38:31
   |
38 | use i2cdev::core::{I2CDevice, I2CMessage, I2CTransfer};
   |                               ^^^^^^^^^^

warning: unused import: `I2CTransfer`
  --> src/lib.rs:38:43
   |
38 | use i2cdev::core::{I2CDevice, I2CMessage, I2CTransfer};
   |                                           ^^^^^^^^^^^

error: aborting due to 10 previous errors

Some errors have detailed explanations: E0432, E0433.
For more information about an error, try `rustc --explain E0432`.
error: could not compile `linux-embedded-hal`.

Caused by:
  process didn't exit successfully: `rustc --crate-name linux_embedded_hal src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="gpio-cdev"' --cfg 'feature="gpio_cdev"' --cfg 'feature="gpio_sysfs"' --cfg 'feature="sysfs_gpio"' -C metadata=453f24c6b88d9603 -C extra-filename=-453f24c6b88d9603 --out-dir /Users/r/prj/p/linux-embedded-hal/target/debug/deps -C incremental=/Users/r/prj/p/linux-embedded-hal/target/debug/incremental -L dependency=/Users/r/prj/p/linux-embedded-hal/target/debug/deps --extern cast=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libcast-f695f5742b822139.rmeta --extern embedded_hal=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libembedded_hal-4c986ac6d091353f.rmeta --extern gpio_cdev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libgpio_cdev-713eeea279cdabc6.rmeta --extern i2cdev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libi2cdev-836156e2317b18cf.rmeta --extern nb=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libnb-c1350daed77af41f.rmeta --extern serial_core=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libserial_core-8f3a3c9ba21d72dd.rmeta --extern serial_unix=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libserial_unix-50fbf10e8f258cc6.rmeta --extern spidev=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libspidev-19ef1dfbba2bd214.rmeta --extern sysfs_gpio=/Users/r/prj/p/linux-embedded-hal/target/debug/deps/libsysfs_gpio-9a66359ec333fd93.rmeta -L native=/Users/r/prj/p/linux-embedded-hal/target/debug/build/backtrace-sys-af67b5ab2dfcc035/out` (exit code: 1)

Switch to gpiocdev-rs for GPIO uAPI v2 support?

Context:
Our gpio-cdev crate only supports GPIO uAPI v1, which has been deprecated in the kernel. There is a new crate gpiocdev which does support it in newer kernels.

Preliminary analysis of switching to the newer gpiocdev in no particular order:

  • Pro:
    • Supports GPIO uAPI v2 as well as v1 which is deprecated.
    • More active project.
    • Author is the author of the API in the Linux kernel.
    • gpiosim support.
  • Cons:
    • Porting effort.
    • Adds many dependencies.
    • Breaking change.
    • Outside of the rust-embedded org.

See rust-embedded/gpio-cdev#68

Remote I/O error when using i2c and two addresses

I get the following error when I try to access two different devices on the same i2c bus.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Io(Os { code: 121, 
kind: Other, message: "Remote I/O error" })', libcore/result.rs:1009:5

Here is my code:

extern crate embedded_hal;
extern crate linux_embedded_hal as hal;

use self::embedded_hal::blocking::i2c::{Read, Write};

use hal::I2cdev;

fn main() {
  let mut i2c = I2cdev::new("/dev/i2c-2").unwrap();
  const ADDR_1: u8 = 0x68;
  const ADDR_2: u8 = 0x0c;

  // Soft reset
  i2c.write(ADDR_1, &[0x6b]).unwrap();
  i2c.write(ADDR_1, &[0x80]).unwrap();

  // send WHO_AM_I command
  i2c.write(ADDR_1, &[0x75]).unwrap();
  let bytes: &mut [u8] = &mut [0; 1];
  i2c.read(ADDR_1, bytes).unwrap();
  debug_assert_eq!(bytes[0], 0x71); // Ok

  // Send WHO_AM_I command to other device
  i2c.write(ADDR_2, &[0x00]).unwrap(); // CRASH!
}

Any ideas?

Async `SpiDevice`?

Hi,

I'm trying to use #110 for some async needs and ran into the need for an SpiDevice satisfying embedded_hal_async::spi::SpiDevice.

Do y'all know if there's any work going into that? I'll probably take a stab at implementing it if I can't find anything.

SPI implementation doesn't follow embedded-hal requirements for CS

As far as I can tell*, the current implementation for SPIBus and SPIDevice via spidev will assert CS around any of the SPIBus methods like read() and write(), because that's what spidev does for each transfer by default.

However, the SPIDevice::transaction() method expects CS to be asserted once at the start, remain asserted for the duration of the closure, then become deasserted afterwards. Since the closure just calls those methods on SPIBus, CS is toggled for every transfer inside the transaction, which will break drivers.

For example, if a driver has some function that's given a buffer of data to send, and needs to prepend a command byte:

fn write_data(&mut self, data: &[u8]) -> Result<(), Self::Error> {
    self.spi.transaction(|bus| {
        bus.write(&[0])?;
        bus.write(data)
    });
}

It wants to have CS assert, a 0 byte written, the data written, and then CS de-asserted, but instead CS is asserted/deasserted around both the one-byte write of 0 and the multi-byte write for data.

Ideally, the SPIBus methods would not touch CS at all, and only transaction() would somehow assert CS at the start and deassert it at the end. I'm not sure if the Linux spidev interface actually allows for such a thing though, and even if it did, the way it grants you a "bus" that's actually shared with other devices means we sort of break the HAL trait assumptions anyway.

I think using spidev's transfer_multiple() alongside the cs_change setting it might be possible to do the right thing here, though I'm not completely sure how... if transfers were queued up only to be executed at the end of the transaction, using flush() inside the transaction wouldn't work, or would still cause excess CS state changes. Still, it might be better than the current situation?

* Right now I can only test this on a remote device and infer what's not working by how a chip isn't responding, so I might be totally wrong here...

I2C write_read() not woring correctly

@eldruin has created a Rust driver for the VEML60300 ambient light sensor that uses the embedded-hal traits.

At the lowest level of the driver are two functions write_register() and read_register() defined as follows:

fn write_register(&mut self, register: u8, value: u16) -> Result<(), Error<E>> {
    self.i2c
        .write(self.address, &[register, value as u8, (value >> 8) as u8])
        .map_err(Error::I2C)
}

fn read_register(&mut self, register: u8) -> Result<u16, Error<E>> {
    let mut data = [0; 2];
    self.i2c
        .write_read(self.address, &[register], &mut data)
        .map_err(Error::I2C)
        .and(Ok(u16::from(data[0]) | u16::from(data[1]) << 8))
}

In testing the code the function that writes to the registers in the VEML6030 is working as it is configuring the ambient light sensor and enabling it to collect samples.

When we try to read the raw data from the ambient light sensor using a function called read_raw() which simply calls the read_register() function with the correct register offset it always returns 0.

Within the test application if we replace the call to the drivers read_raw() function with the following:

let mut dev = LinuxI2CDevice::new("/dev/i2c-2", 0x10).unwrap();
let raw = dev.smbus_read_word_data(0x04).unwrap();

then correct data is being returned. If we split the write then read as:

dev.write(&[0x04]).unwrap();
let mut data = [0; 2];
dev.read(&mut data).unwrap();
let raw = u16::from(data[0]) | (u16::from(data[1]) << 8); 

then the value of raw is, again, always 0.

The code is all cross compiled for an NXP i.MX6 running a custom Yocto Linux build with kernel version 4.14.98.

-Andy.

SPI implementation panics if read and write buffers in a transfer are not the same length

In embedded-hal SPI transfers, the read and write buffers may be different lengths:

It is allowed for read and write to have different lengths, even zero length. The transfer runs for max(read.len(), write.len()) words. If read is shorter, incoming words after read has been filled will be discarded. If write is shorter, the value of words sent in MOSI after all write has been sent is implementation-defined, typically 0x00, 0xFF, or configurable.

In spidev read_write, it is not:

Note that the tx_buf and rx_buf must be the same length.

However currently we implement transfer by calling read_write directly:

SpiOperation::Transfer(read, write) => SpidevTransfer::read_write(write, read),

leading to panics when the buffer lengths differ. We should adjust the buffers passed to read_write, or split the transfer into a read_write and a write or something, to accommodate.

Improvement of error matching necessary

We have merged #71 which did the heavy-lifting for updating this to embedded-hal 1.0.0-alpha.6.
However, currently we are missing the extraction of information from the underlying nix/io errors in the embedded_hal::*::Error implementations so that they can be converted to a meaningful embedded_hal::*::ErrorKind.
At the moment, converting all errors to Other would render all drivers unable to act on things like i2c::NoAcknowledge.
For this one needs to dig a bit into the Linux kernel, and so on, though.

TODO:

  • #75
  • SPI
  • Serial

DelayUs should not be implemented with thread::sleep

I believe thread::sleep cannot provide microsecond precision on linux.

Failing example:

extern crate embedded_hal;
extern crate linux_embedded_hal as hal;

use embedded_hal::blocking::delay::DelayUs;

fn main() {
    let us = 10u8;
    let t = ::std::time::SystemTime::now();
    let mut delay = hal::Delay{};
    delay.delay_us(us);
    println!("Expecting {}us, got {}us", us, t.elapsed().unwrap().subsec_nanos() / 1000);
}

Prints

Running `target/release/test_hal`
Expecting 10us, got 84us

What is the recommended way to get this level of precision?

As an example this very bad loop works:

pub fn delay_us(us: u32) {
    let target = Instant::now() + Duration::new(0, us * 1000);
    while Instant::now() < target { }
}

Update `nix` in all dependent crates

TL;DR: We need to version bump dependencies of dependencies here. I'm willing to do it.

I've been out of the Rust Embedded loop a little while (priorities shifted), but I've come back and have found some issues with building nix on my Raspberry Pi dev harness.

That's a critical blocker for me to release a new version of one of my crates and I believe all of i2cdev, spidev, and sysfs_gpio need a bump and a test.

I can do the first two, but I'd have to make a project to use sysfs_gpio to confirm it's working.

If we're in agreement, I think I can carve out a little time over the next few weeks to go out to each of those libraries and do the version bump to nix to 0.14. One extra improvement will be not needing to build the beast that is nix three times for my examples which will make me pretty happy.

Here's the output of cargo-tree. It shows what is getting re-compiled (packages without "(*)")

└── linux-embedded-hal v0.2.2
    ├── cast v0.2.2
    ├── embedded-hal v0.2.2 (*)
    ├── i2cdev v0.4.1
    │   ├── bitflags v1.0.4 (*)
    │   ├── byteorder v1.3.1 (*)
    │   ├── libc v0.2.55
    │   └── nix v0.11.0
    │       ├── bitflags v1.0.4 (*)
    │       ├── cfg-if v0.1.9
    │       ├── libc v0.2.55 (*)
    │       └── void v1.0.2 (*)
    ├── spidev v0.3.0
    │   ├── bitflags v0.3.3
    │   ├── libc v0.2.55 (*)
    │   └── nix v0.6.0
    │       ├── bitflags v0.4.0
    │       ├── cfg-if v0.1.9 (*)
    │       ├── libc v0.2.55 (*)
    │       └── void v1.0.2 (*)
    │       [build-dependencies]
    │       ├── rustc_version v0.1.7
    │       │   └── semver v0.1.20
    │       └── semver v0.1.20 (*)
    └── sysfs_gpio v0.5.3
        └── nix v0.10.0
            ├── bitflags v1.0.4 (*)
            ├── bytes v0.4.12
            │   ├── byteorder v1.3.1 (*)
            │   └── iovec v0.1.2
            │       └── libc v0.2.55 (*)
            ├── cfg-if v0.1.9 (*)
            ├── libc v0.2.55 (*)
            └── void v1.0.2 (*)

Migrate from travis-ci to gh-actions

Per other WG projects, this should be migrated from travis-ci to github-actions.

Note that an outstanding issue impedes simple multiarch support, though this should be readily resolved by re-writing to pin dependencies with something like this, or perhaps by using cross?

Controller Area Network

Here to inquire on the steps to get CAN support added:

  • There's a PR well underway to get CAN support added to the embedded-hal repo.
  • I have an implementation that still needs some polishing, but is working.

Is submitting a PR here that references my repo the way to go?

Is this as simple as using `gpiozerio-rust` crate?

Is this crate as simple as using rust_gpiozero crate? For example if I want to print out hello world and turn on and off the lights, is the code as simple to type as ``rust_gpiozero`:

image


Another question, is there another crate that is based on embedded-hal (just like linux-embedded-hal) that would work for the Arduino and the syntax for linux-embedded-hal would be similar for the Arduino version?

I2C transaction breaks I2c trait contract

According to I2c trait transaction contract is as follows:

Transaction contract:
- Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
- Data from adjacent operations of the same type are sent after each other without an SP or SR.
- Between adjacent operations of a different type an SR and SAD+R/W is sent.
- After executing the last operation an SP is sent automatically.
- If the last operation is a `Read` the master does not send an acknowledge for the last byte.
- `ST` = start condition
- `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing
- `SR` = repeated start condition
- `SP` = stop condition

Using following simple test code:

use embedded_hal::i2c::blocking::{I2c, Operation as I2cOperation};
use linux_embedded_hal::I2cdev;

fn main() {
    let mut i2c_dev = I2cdev::new("/dev/i2c-1").unwrap();

    let data = [0xaa; 1];
    let mut ops = [I2cOperation::Write(&[0x40]), I2cOperation::Write(&data)];
    i2c_dev.transaction(0x3d, &mut ops).unwrap();
}

I'm expecting no SR "repeated start condition" to appear as both operations are of the same type (Write). Unfortunately I can see SR "repeated start condition" on the bus as well as SAD+R/W "slave address followed by bit 1 to indicate reading or 0 to indicate writing" (positions 6 and 8). This was captured using logic analyzer on embedded Linux board for the sample code attached above:
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.