rust-embedded / linux-embedded-hal Goto Github PK
View Code? Open in Web Editor NEWImplementation of the `embedded-hal` traits for Linux devices
License: Apache License 2.0
Implementation of the `embedded-hal` traits for Linux devices
License: Apache License 2.0
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.
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
spidev
to not drive the associated CS pinspidev
device on that busSpiDevice
objects, using generic GPIO for CS control, or used when dedicated bus access is required (eg to generate smart LED waveforms)spidev
SpidevDevice
implements just the SpiDevice
trait
SpiDevice
, the kernel handles sharing and CS for us, even with other programsI'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.
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:
Line 100 in 86ab035
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.
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
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:
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(())
}
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?
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?
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
?
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.
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:
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.
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...
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`:
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?
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
.)
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:
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)
Since sysfs is now deprecated, we should migrate dependence to gpio-cdev.
Here to inquire on the steps to get CAN support added:
embedded-hal
repo.Is submitting a PR here that references my repo the way to go?
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,
we've just released [email protected]
, as per usual we need to bump this crate and fix any broken interfaces to get started fixing up any deps ^_^
hey fyi
tokio::time::sleep
is only good down toms
resolutions, for more granularity we typically need somethingnanosleep
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 overInstant::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)
I think it would be great to add implementations for the new embedded-hal CAN traits via socketcan. Would you be open for a PR for this?
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 :)
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?
See: https://rustsec.org/advisories/RUSTSEC-2021-0119.html
According to changelog v0.4.0-alpha.4
should be released, but it seems it is not published to crates.io yet.
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 (*)
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.
As the title suggests, v0.3.0 of linux-embedded-hal does not have gpio-cdev feature, but it is claimed to have in the documentaiton.
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?
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
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.
@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.
We have noticed that this crate uses serial-unix which has not been maintained in 5 years: https://github.com/dcuddeback/serial-rs.
Instead the maintained crate serialport (https://github.com/serialport/serialport-rs) could be used.
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 { }
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.