Skip to content

Commit 6fda0f2

Browse files
bors[bot]Dirbaio
andauthored
Merge #351
351: SPI: split into device/bus, allows sharing buses with automatic CS r=therealprof a=Dirbaio Because why not? This separates the concepts of "SPI bus" and "SPI device". I got the idea of having traits for SPI devices from #299. It has an excellent breakdown of the issues of the status quo, so go read that first. The difference from #299 is that proposes "repurposing" the existing traits to represent devices, while this PR proposes specifying the existing traits represent buses, and introduces a new trait for representing devices on top of that. - HALs impl the bus traits, just like now. No extra boilerplate. - Crates like `shared-bus` add the "bus mutexing" logic, to impl `SpiDevice` on top of `SpiBus` (+ `OutputPin` for CS). There's a wide variety of possible impls, all can satisfy the `SpiDevice` requirements: - Exclusive single-device, that just owns the entire bus - Single-thread, on top of `RefCell` - Multithreaded std, using std `Mutex` - Multithreaded embedded, using some `AtomicBool` taken flag. - Async embedded, using an async mutex (this'd require an async version of SpiDevice). - Drivers take `T: SpiDevice` (or `SpiDeviceRead`, `SpiDeviceWrite`), then they start a `.transaction()`, then use it to read/write/transfer data. The transaction ends automatically when returning. Example: ```rust fn read_register(&mut self, addr: u8) -> Result<u8, Error> { let mut buf = [0; 1]; self.spi.transaction(|bus| { bus.write(&[addr])?; bus.read(&mut buf)?; })?; Ok(buf[0]) } ``` ## No Transactional needed Previous proposals boiled down to: for each method call (read/write/transfer), it automatically assets CS before, deasserts it after. This means two `write`s are really two transactions, which might not be what you want. To counter this, `Transactional` was added, so that you can do multiple operations in a single CS assert/deassert. With this proposal, you have an explicit "Transaction" object, so you can easily do multiple reads/writes on it in a single transaction. This means `Transactional` is no longer needed. The result is more flexible than `Transactional`, even. Take an imaginary device that responds to "read" operations with a status code, and the data only arrives on success. With this proposal you can easily read data then take conditional action. With `Transactional` there's no way, best you can do is read the data unconditionally, then discard it on error. It allows for smaller memory usage as well. With `Transactional` you had to allocate buffer space for all operations upfront, with this you can do them as you go. ```rust fn read_data(&mut self, addr: u8, dest: &mut [u8]) -> Result<(), Error> { self.spi.transaction(|bus| { bus.write(&[addr])?; // Read status code, 0x00 indicates success let mut buf = [0; 1]; bus.read(&mut buf)?; if buf[0] != 0x00 { return Err(Error::ErrorCode(buf[0])); } // If the operation is successful, actually read the data, still in the same transaction bus.read(dest) }) } ``` Co-authored-by: Dario Nieuwenhuis <[email protected]>
2 parents ddf4375 + b50b065 commit 6fda0f2

File tree

8 files changed

+343
-69
lines changed

8 files changed

+343
-69
lines changed

.github/bors.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ status = [
55
"ci-linux (stable, x86_64-unknown-linux-gnu)",
66
"ci-linux (stable, thumbv6m-none-eabi)",
77
"ci-linux (stable, thumbv7m-none-eabi)",
8-
"ci-linux (1.46.0, x86_64-unknown-linux-gnu)",
8+
"ci-linux (1.54.0, x86_64-unknown-linux-gnu)",
99
"ci-linux-test (stable)",
10-
"ci-linux-test (1.46.0, x86_64-unknown-linux-gnu)",
10+
"ci-linux-test (1.54.0, x86_64-unknown-linux-gnu)",
1111
"fmt",
1212
]

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
include:
2323
# Test MSRV
24-
- rust: 1.46.0
24+
- rust: 1.54.0
2525
TARGET: x86_64-unknown-linux-gnu
2626

2727
# Test nightly but don't fail

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
rust: [stable]
1717

1818
include:
19-
- rust: 1.46.0
19+
- rust: 1.54.0
2020
TARGET: x86_64-unknown-linux-gnu
2121

2222
# Test nightly but don't fail

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
- The Minimum Supported Rust Version (MSRV) is now 1.54.0
12+
- `spi`: unify all traits into `SpiReadBus`, `SpiWriteBus` and `SpiBus` (read-write).
13+
- `spi`: Add `SpiDevice` trait to represent a single device in a (possibly shared) bus, with managed chip-select (CS) pin.
14+
1015
## [v1.0.0-alpha.7] - 2022-02-09
1116

1217
*** This is (also) an alpha release with breaking changes (sorry) ***

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[![crates.io](https://img.shields.io/crates/d/embedded-hal.svg)](https://crates.io/crates/embedded-hal)
22
[![crates.io](https://img.shields.io/crates/v/embedded-hal.svg)](https://crates.io/crates/embedded-hal)
33
[![Documentation](https://docs.rs/embedded-hal/badge.svg)](https://docs.rs/embedded-hal)
4-
![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.46+-blue.svg)
4+
![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.54+-blue.svg)
55

66
# `embedded-hal`
77

@@ -98,7 +98,7 @@ Because of this we only aim to support the latest `-alpha`.
9898

9999
## Minimum Supported Rust Version (MSRV)
100100

101-
This crate is guaranteed to compile on stable Rust 1.46 and up. It *might*
101+
This crate is guaranteed to compile on stable Rust 1.54 and up. It *might*
102102
compile with older versions but that may change in any new patch release.
103103

104104
## License

0 commit comments

Comments
 (0)