What is the correct way to share a locking reference to a resource in AVR (no_std) Rust?

Viewed 43

I have two device drivers that need to use the SPI bus.

Fortunately the one that wants to "own" it, uses a trait, and I can interpose my own implementation.

If this were regular Rust an Arc<Mutex<SPI>> would be sufficient, but I am encountering challenges.


extern crate alloc;

use alloc::sync::Arc;
use avr_hal_generic::avr_device::interrupt::{CriticalSection, Mutex};

...

let spi = Arc::new(Mutex::new(spi));
let device_interface = SpiWorkaround::new(spi.clone(), cs, dc);

When I try to compile this in a project based off the https://github.com/Rahix/avr-hal-template I get

error[E0463]: can't find crate for `alloc`
 --> src/main.rs:5:1
  |
5 | extern crate alloc;
  | ^^^^^^^^^^^^^^^^^^^ can't find crate

If I add alloc="*" to the Cargo.toml I get

error: no matching package named `alloc` found
location searched: registry `crates-io`

I was able to get past these using cargo build --release -Z build-std=core,alloc (is there a way to put that in the Cargo.toml?) and got this error:

error[E0432]: unresolved import `alloc::sync`
 --> src/main.rs:7:12
  |
7 | use alloc::sync::Arc;
  |            ^^^^ could not find `sync` in `alloc`

What is the proper technique for letting two data structures take turns using an object in the no_std AVR environment?

1 Answers

You cannot use Arc for that. Arc uses atomic usize for its reference counter, and therefore only supports target that have usize-sized atomics. Unfortunately the size of usize for your platform is 16 bits, but it only supports up to 8 bits atomics.

You can copy the source code of Arc from std and adapt it to use AtomicU8 instead of AtomicUsize (there may already be a crate for that, I didn't found one though). Note this will only support up to 255 active owners.

As for the other question, you can put change .cargo/config.toml [build-std] key as follows to avoid the need to pass -Zbuild-std every time:

[unstable]
build-std = ["core", "alloc"]
Related