Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d3386749 | ||
|
|
5401e3af30 | ||
|
|
1ab885a7d5 | ||
|
|
6978a98f76 | ||
|
|
46df520bc9 | ||
|
|
abca446050 | ||
|
|
4e16344c70 | ||
|
|
272a0dd3fc | ||
|
|
a1303f2f87 | ||
|
|
58d98049d8 | ||
|
|
a1cc31f52d | ||
|
|
15f9434af7 | ||
|
|
c8cd586be0 | ||
|
|
6cd165672a | ||
|
|
6335cb86ac | ||
|
|
b7f7588e0b | ||
|
|
f06919e87c | ||
|
|
ff2485b979 | ||
|
|
3fc811a999 |
No files matched your search
@@ -0,0 +1,15 @@
|
||||
# .gitlab-ci.yml
|
||||
|
||||
image: rust:latest
|
||||
|
||||
variables:
|
||||
CARGO_HOME: $CI_PROJECT_DIR/.cargo_cache
|
||||
|
||||
stages:
|
||||
- stage1
|
||||
- stage2
|
||||
|
||||
include:
|
||||
- local: '.gitlab/ci/shared-hal.yml'
|
||||
- local: '.gitlab/ci/va108xx.yml'
|
||||
- local: '.gitlab/ci/va416xx.yml'
|
||||
@@ -0,0 +1,30 @@
|
||||
# .gitlab/ci/common-setup.yml
|
||||
|
||||
.common_setup:
|
||||
cache:
|
||||
paths:
|
||||
- '.cargo_cache/'
|
||||
- 'vorago-shared-hal/target/'
|
||||
- 'va108xx/target/'
|
||||
- 'va416xx/target/'
|
||||
key: cargo-cache
|
||||
|
||||
.rust_setup_thumbv7em:
|
||||
extends: .common_setup
|
||||
before_script:
|
||||
- rustup target add thumbv7em-none-eabihf
|
||||
|
||||
.rust_setup_thumbv6m:
|
||||
extends: .common_setup
|
||||
before_script:
|
||||
- rustup target add thumbv6m-none-eabi
|
||||
|
||||
.rust_setup_both_targets:
|
||||
extends: .common_setup
|
||||
before_script:
|
||||
- rustup target add thumbv7em-none-eabihf thumbv6m-none-eabi
|
||||
|
||||
.nextest_setup:
|
||||
extends: .common_setup
|
||||
before_script:
|
||||
- cargo install cargo-nextest
|
||||
@@ -0,0 +1,34 @@
|
||||
# .gitlab/ci/shared-hal.yml
|
||||
|
||||
shared-hal-check:
|
||||
stage: stage1
|
||||
extends: .rust_setup_both_targets
|
||||
script:
|
||||
- cd vorago-shared-hal
|
||||
- cargo check --target thumbv7em-none-eabihf --features "vor4x, defmt"
|
||||
- cargo check --target thumbv6m-none-eabi --features "vor1x, defmt"
|
||||
|
||||
shared-hal-fmt:
|
||||
stage: stage1
|
||||
extends: .common_setup
|
||||
script:
|
||||
- cd vorago-shared-hal
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
shared-hal-docs:
|
||||
stage: stage1
|
||||
extends: .rust_setup_both_targets
|
||||
script:
|
||||
- cd vorago-shared-hal
|
||||
- rustup install nightly
|
||||
- rustup component add rust-src --toolchain nightly
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --target thumbv7em-none-eabihf --features "vor4x, defmt" --no-deps
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc --target thumbv6m-none-eabi --features "vor1x, defmt" --no-deps
|
||||
|
||||
shared-hal-clippy:
|
||||
stage: stage1
|
||||
extends: .rust_setup_both_targets
|
||||
script:
|
||||
- cd vorago-shared-hal
|
||||
- cargo clippy --target thumbv7em-none-eabihf --features vor4x -- -D warnings
|
||||
- cargo clippy --target thumbv6m-none-eabi --features vor1x -- -D warnings
|
||||
@@ -0,0 +1,50 @@
|
||||
# .gitlab/ci/va108xx.yml
|
||||
|
||||
va108xx-check:
|
||||
stage: stage1
|
||||
extends: .rust_setup_thumbv6m
|
||||
script:
|
||||
- cd va108xx
|
||||
- cargo check --target thumbv6m-none-eabi
|
||||
- cargo check --target thumbv6m-none-eabi --examples
|
||||
- cargo check -p va108xx --target thumbv6m-none-eabi --all-features
|
||||
- cargo check -p va108xx-hal --target thumbv6m-none-eabi --features "defmt"
|
||||
|
||||
va108xx-build:
|
||||
stage: stage2
|
||||
extends: .rust_setup_thumbv6m
|
||||
script:
|
||||
- cd va108xx
|
||||
- cargo build --target thumbv6m-none-eabi
|
||||
|
||||
va108xx-test:
|
||||
stage: stage2
|
||||
extends: .nextest_setup
|
||||
script:
|
||||
- cd va108xx
|
||||
- cargo nextest run -p va108xx-hal --no-tests=pass
|
||||
|
||||
va108xx-fmt:
|
||||
stage: stage1
|
||||
extends: .common_setup
|
||||
script:
|
||||
- cd va108xx
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
va108xx-docs:
|
||||
stage: stage1
|
||||
extends: .common_setup
|
||||
script:
|
||||
- cd va108xx
|
||||
- rustup install nightly
|
||||
- rustup component add rust-src --toolchain nightly
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx --all-features
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va108xx-hal --features "defmt, embassy-oc30-oc31" --no-deps
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-reb1 --no-deps
|
||||
|
||||
va108xx-clippy:
|
||||
stage: stage1
|
||||
extends: .rust_setup_thumbv6m
|
||||
script:
|
||||
- cd va108xx
|
||||
- cargo clippy --target thumbv6m-none-eabi -- -D warnings
|
||||
@@ -0,0 +1,50 @@
|
||||
# .gitlab/ci/va416xx.yml
|
||||
|
||||
va416xx-check:
|
||||
stage: stage1
|
||||
extends: .rust_setup_thumbv7em
|
||||
script:
|
||||
- cd va416xx
|
||||
- cargo check --target thumbv7em-none-eabihf
|
||||
- cargo check --target thumbv7em-none-eabihf --examples
|
||||
- cargo check -p va416xx --target thumbv7em-none-eabihf --all-features
|
||||
- cargo check -p va416xx-hal --target thumbv7em-none-eabihf --features "defmt va41630"
|
||||
|
||||
va416xx-build:
|
||||
stage: stage2
|
||||
extends: .rust_setup_thumbv7em
|
||||
script:
|
||||
- cd va416xx
|
||||
- cargo build --target thumbv7em-none-eabihf
|
||||
|
||||
va416xx-test:
|
||||
stage: stage2
|
||||
extends: .nextest_setup
|
||||
script:
|
||||
- cd va416xx
|
||||
- cargo nextest run --features va41630 -p va416xx-hal
|
||||
|
||||
va416xx-fmt:
|
||||
stage: stage1
|
||||
extends: .common_setup
|
||||
script:
|
||||
- cd va416xx
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
va416xx-docs:
|
||||
stage: stage1
|
||||
extends: .common_setup
|
||||
script:
|
||||
- cd va416xx
|
||||
- rustup install nightly
|
||||
- rustup component add rust-src --toolchain nightly
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va416xx
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p va416xx-hal --features va41630 --no-deps
|
||||
- RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p vorago-peb1 --no-deps
|
||||
|
||||
va416xx-clippy:
|
||||
stage: stage1
|
||||
extends: .rust_setup_thumbv7em
|
||||
script:
|
||||
- cd va416xx
|
||||
- cargo clippy --target thumbv7em-none-eabihf -- -D warnings
|
||||
@@ -62,7 +62,8 @@ async fn main(_spawner: Spawner) {
|
||||
InterruptConfig::new(pac::Interrupt::OC2, true, true),
|
||||
);
|
||||
let (tx, _rx) = uarta.split();
|
||||
let mut async_tx = TxAsync::new(tx);
|
||||
// Safety: We do not cancel futures.
|
||||
let mut async_tx = unsafe { TxAsync::new(tx) };
|
||||
let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||
let mut idx = 0;
|
||||
loop {
|
||||
@@ -70,6 +71,7 @@ async fn main(_spawner: Spawner) {
|
||||
led0.toggle();
|
||||
led1.toggle();
|
||||
led2.toggle();
|
||||
// Safety: We are sending static lifetime slices, and not cancelling the futures.
|
||||
async_tx
|
||||
.write_all(STR_LIST[idx].as_bytes())
|
||||
.await
|
||||
|
||||
@@ -101,7 +101,8 @@ mod app {
|
||||
tc_handler::spawn().unwrap();
|
||||
tm_tx_handler::spawn().unwrap();
|
||||
|
||||
let tx_async = TxAsync::new(tx);
|
||||
// Safety: We do not cancel futures.
|
||||
let tx_async = unsafe { TxAsync::new(tx) };
|
||||
|
||||
static TC_PIPE: static_cell::ConstStaticCell<
|
||||
embassy_sync::pipe::Pipe<CriticalSectionRawMutex, TC_PIPE_SIZE>,
|
||||
@@ -284,6 +285,7 @@ mod app {
|
||||
let mut buf: [u8; 256] = [0; 256];
|
||||
loop {
|
||||
let read_len = cx.local.tm_rx.read(&mut buf).await;
|
||||
// Safety: The buffer outlives the UART TX structure.
|
||||
if let Err(e) = cx.local.uart_tx.write_all(&buf[0..read_len]).await {
|
||||
defmt::warn!("UART TX overrun error: {}", e);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Async TX UART functions are explicitely marked `unsafe`.
|
||||
- Async TX UART `write` now returns a `TxFuture`
|
||||
- Empty async TX write resolves to `Poll::Ready(0)` immediately
|
||||
|
||||
## [v0.13.1] 2026-05-19
|
||||
|
||||
- Docs.rs feature fix
|
||||
|
||||
## [v0.13.0] 2026-05-19
|
||||
|
||||
- Bump `vorago-shared-hal` dependency to v0.4
|
||||
@@ -281,7 +291,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- Added basic test binary in form of an example
|
||||
- README with basic instructions how to set up own binary crate
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/compare/va108xx-hal-v0.13.0...HEAD
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/compare/va108xx-hal-v0.13.1...HEAD
|
||||
[v0.13.1]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/compare/va108xx-hal-v0.13.0...va108xx-hal-v0.13.1
|
||||
[v0.13.0]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/src/tag/va108xx-hal-v0.13.0
|
||||
[v0.12.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.11.1...va108xx-hal-v0.12.0
|
||||
[v0.11.1]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-hal-v0.11.0...va108xx-hal-v0.11.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "va108xx-hal"
|
||||
version = "0.13.0"
|
||||
version = "0.13.1"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "HAL for the Vorago VA108xx family of microcontrollers"
|
||||
@@ -37,8 +37,8 @@ embassy-oc29-oc30 = ["_irqs-in-lib"]
|
||||
embassy-oc28-oc29 = ["_irqs-in-lib"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
targets = ["thumbv6m-none-eabi"]
|
||||
features = ["defmt", "embassy-oc30-oc31"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
|
||||
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [unreleased]
|
||||
|
||||
## [v0.6.1] 2026-05-19
|
||||
|
||||
- Rebuild docs for correct target
|
||||
|
||||
## [v0.6.0] 2025-09-03
|
||||
|
||||
- Re-generated PAC with `svd2rust` v0.37.0
|
||||
@@ -88,7 +92,8 @@ defmt version v1
|
||||
- First version of the PAC which builds. Uses a patched version
|
||||
of `svd2rust`: https://github.com/rust-embedded/svd2rust
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.6.0...HEAD
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/compare/va108xx-v0.6.1...HEAD
|
||||
[v0.6.1]: https://egit.irs.uni-stuttgart.de/rust/vorago-rs/src/tag/va108xx-v0.6.1
|
||||
[v0.6.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.5.1...va108xx-v0.6.0
|
||||
[v0.5.1]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.5.0...va108xx-v0.5.1
|
||||
[v0.5.0]: https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/compare/va108xx-v0.4.0...va108xx-v0.5.0
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "va108xx"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2021"
|
||||
description = "PAC for the Vorago VA108xx family of microcontrollers"
|
||||
|
||||
@@ -68,12 +68,14 @@ async fn main(_spawner: Spawner) {
|
||||
let uart_config = uart::Config::new_with_clock_config(clock_config);
|
||||
let uarta = uart::Uart::new_for_uart0(dp.uart0, pinsg.pg0, pinsg.pg1, uart_config);
|
||||
let (tx, _rx) = uarta.split();
|
||||
let mut async_tx = TxAsync::new(tx);
|
||||
// Safety: We do not cancel futures.
|
||||
let mut async_tx = unsafe { TxAsync::new(tx) };
|
||||
let mut ticker = Ticker::every(Duration::from_secs(1));
|
||||
let mut idx = 0;
|
||||
loop {
|
||||
defmt::println!("Current time: {}", Instant::now().as_secs());
|
||||
led.toggle();
|
||||
// Safety: We are sending static lifetime slices, and not cancelling the futures.
|
||||
async_tx
|
||||
.write_all(STR_LIST[idx].as_bytes())
|
||||
.await
|
||||
|
||||
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Async TX UART functions are explicitely marked `unsafe`.
|
||||
- Async TX UART `write` now returns a `TxFuture`
|
||||
- Empty async TX write resolves to `Poll::Ready(0)` immediately
|
||||
|
||||
# [v0.6.0] 2025-09-03
|
||||
|
||||
- Use `vorago-shared-hal` dependency to provide shared peripherals.
|
||||
|
||||
@@ -8,9 +8,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Async TX UART and Async SPI driver constructor is explicitely marked `unsafe`.
|
||||
- Async TX UART `write` now returns a `TxFuture`
|
||||
- Empty async TX write resolves to `Poll::Ready(0)` immediately.
|
||||
- Async SPI API now always returns futures instead of optional futures.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Asynch drivers now borrow the buffers properly for the lifetime of the future.
|
||||
- Asynch UART TX driver now borrows the TX peripheral for the duration of the future.
|
||||
|
||||
## [v0.4.0] 2026-05-19
|
||||
|
||||
## Changed
|
||||
### Changed
|
||||
|
||||
- Naming improvements for UART register module
|
||||
- Improved UART Async TX module. Only enable TX below threshold interrupts if the FIFO
|
||||
|
||||
@@ -22,7 +22,7 @@ embedded-hal-async = "1"
|
||||
embedded-hal-nb = "1"
|
||||
embedded-io = "0.7"
|
||||
embedded-io-async = "0.7"
|
||||
raw-slicee = "0.1"
|
||||
raw-buffer = "0.1"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
paste = "1"
|
||||
fugit = "0.4"
|
||||
|
||||
@@ -4,7 +4,7 @@ use arbitrary_int::u5;
|
||||
use critical_section::Mutex;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use portable_atomic::AtomicBool;
|
||||
use raw_slice::{RawBufSlice, RawBufSliceMut};
|
||||
use raw_buffer::{RawBufSlice, RawBufSliceMut};
|
||||
|
||||
use crate::{
|
||||
shared::{FifoClear, TriggerLevel},
|
||||
@@ -319,16 +319,28 @@ impl TransferContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpiFuture<'spi> {
|
||||
pub struct SpiFuture<'spi, 'read, 'write> {
|
||||
bank: super::Bank,
|
||||
spi: &'spi mut super::Spi<u8>,
|
||||
empty_buffer: bool,
|
||||
finished_regularly: core::cell::Cell<bool>,
|
||||
phantom_read: core::marker::PhantomData<(&'read (), &'write ())>,
|
||||
}
|
||||
|
||||
impl<'spi> SpiFuture<'spi> {
|
||||
fn new_for_read(spi: &'spi mut super::Spi<u8>, bank: super::Bank, words: &mut [u8]) -> Self {
|
||||
impl<'spi, 'read, 'write> SpiFuture<'spi, 'read, 'write> {
|
||||
fn new_for_read(
|
||||
spi: &'spi mut super::Spi<u8>,
|
||||
bank: super::Bank,
|
||||
words: &'read mut [u8],
|
||||
) -> Self {
|
||||
if words.is_empty() {
|
||||
panic!("words length unexpectedly 0");
|
||||
return Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: true,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
};
|
||||
}
|
||||
Self::generic_init_transfer(spi, bank);
|
||||
|
||||
@@ -359,13 +371,25 @@ impl<'spi> SpiFuture<'spi> {
|
||||
Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: false,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for_write(spi: &'spi mut super::Spi<u8>, bank: super::Bank, words: &[u8]) -> Self {
|
||||
fn new_for_write(
|
||||
spi: &'spi mut super::Spi<u8>,
|
||||
bank: super::Bank,
|
||||
words: &'write [u8],
|
||||
) -> Self {
|
||||
if words.is_empty() {
|
||||
panic!("words length unexpectedly 0");
|
||||
return Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: true,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
};
|
||||
}
|
||||
let index = bank as usize;
|
||||
let write_index = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words);
|
||||
@@ -388,18 +412,26 @@ impl<'spi> SpiFuture<'spi> {
|
||||
Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: false,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for_transfer(
|
||||
spi: &'spi mut super::Spi<u8>,
|
||||
bank: super::Bank,
|
||||
read: &mut [u8],
|
||||
write: &[u8],
|
||||
read: &'read mut [u8],
|
||||
write: &'write [u8],
|
||||
) -> Self {
|
||||
if read.is_empty() || write.is_empty() {
|
||||
panic!("read or write buffer unexpectedly empty");
|
||||
return Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: true,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
};
|
||||
}
|
||||
let index = bank as usize;
|
||||
let full_write_len = core::cmp::max(read.len(), write.len());
|
||||
@@ -433,17 +465,25 @@ impl<'spi> SpiFuture<'spi> {
|
||||
Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: false,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for_transfer_in_place(
|
||||
spi: &'spi mut super::Spi<u8>,
|
||||
bank: super::Bank,
|
||||
words: &mut [u8],
|
||||
words: &'read mut [u8],
|
||||
) -> Self {
|
||||
if words.is_empty() {
|
||||
panic!("read and write buffer unexpectedly empty");
|
||||
return Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: true,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
};
|
||||
}
|
||||
let write_idx = Self::generic_init_transfer_write_transfer_in_place(spi, bank, words);
|
||||
critical_section::with(|cs| {
|
||||
@@ -465,7 +505,9 @@ impl<'spi> SpiFuture<'spi> {
|
||||
Self {
|
||||
bank,
|
||||
spi,
|
||||
empty_buffer: false,
|
||||
finished_regularly: core::cell::Cell::new(false),
|
||||
phantom_read: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,13 +557,16 @@ impl<'spi> SpiFuture<'spi> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'spi> Future for SpiFuture<'spi> {
|
||||
impl<'spi> Future for SpiFuture<'spi, '_, '_> {
|
||||
type Output = Result<(), RxOverrunError>;
|
||||
|
||||
fn poll(
|
||||
self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> core::task::Poll<Self::Output> {
|
||||
if self.empty_buffer {
|
||||
return core::task::Poll::Ready(Ok(()));
|
||||
}
|
||||
WAKERS[self.bank as usize].register(cx.waker());
|
||||
if DONE[self.bank as usize].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||
let rx_overrun = critical_section::with(|cs| {
|
||||
@@ -542,9 +587,9 @@ impl<'spi> Future for SpiFuture<'spi> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'spi> Drop for SpiFuture<'spi> {
|
||||
impl<'spi> Drop for SpiFuture<'spi, '_, '_> {
|
||||
fn drop(&mut self) {
|
||||
if !self.finished_regularly.get() {
|
||||
if !self.finished_regularly.get() && !self.empty_buffer {
|
||||
// It might be sufficient to disable and enable the SPI.. But this definitely
|
||||
// ensures the SPI is fully reset.
|
||||
self.spi.regs.write_interrupt_clear(InterruptClear::ALL);
|
||||
@@ -563,6 +608,13 @@ impl<'spi> Drop for SpiFuture<'spi> {
|
||||
pub struct SpiAsync(pub super::Spi<u8>);
|
||||
|
||||
impl SpiAsync {
|
||||
/// Construct an asynchronous SPI driver for the given SPI peripheral.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The user MUST ensure that the `Drop` method of all futures generated with this driver
|
||||
/// is called on transfer cancellation. By default, this does not require any special handling.
|
||||
/// This case was considered exotic enough to justify not making the function `unsafe`.
|
||||
pub fn new(
|
||||
mut spi: super::Spi<u8>,
|
||||
#[cfg(feature = "vor1x")] opt_irq_cfg: Option<crate::InterruptConfig>,
|
||||
@@ -589,36 +641,48 @@ impl SpiAsync {
|
||||
Self(spi)
|
||||
}
|
||||
|
||||
fn read(&mut self, words: &mut [u8]) -> Option<SpiFuture<'_>> {
|
||||
if words.is_empty() {
|
||||
return None;
|
||||
}
|
||||
/// Future which read `words` from the slave.
|
||||
///
|
||||
/// Returns [None] if the provided buffer is empty.
|
||||
pub fn read<'read>(&mut self, words: &'read mut [u8]) -> SpiFuture<'_, 'read, '_> {
|
||||
let id = self.0.id;
|
||||
Some(SpiFuture::new_for_read(&mut self.0, id, words))
|
||||
SpiFuture::new_for_read(&mut self.0, id, words)
|
||||
}
|
||||
|
||||
fn write(&mut self, words: &[u8]) -> Option<SpiFuture<'_>> {
|
||||
if words.is_empty() {
|
||||
return None;
|
||||
}
|
||||
/// Future which writes `words` to the slave, ignoring all the incoming words.
|
||||
///
|
||||
/// Returns [None] if the provided buffer is empty.
|
||||
pub fn write<'write>(&mut self, words: &'write [u8]) -> SpiFuture<'_, '_, 'write> {
|
||||
let id = self.0.id;
|
||||
Some(SpiFuture::new_for_write(&mut self.0, id, words))
|
||||
SpiFuture::new_for_write(&mut self.0, id, words)
|
||||
}
|
||||
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Option<SpiFuture<'_>> {
|
||||
if read.is_empty() || write.is_empty() {
|
||||
return None;
|
||||
}
|
||||
/// Future which writes and reads simultaneously. `write` is written to the slave on MOSI and
|
||||
/// words received on MISO are stored in `read`.
|
||||
///
|
||||
/// 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 0.
|
||||
///
|
||||
/// Returns [None] if either of the provided buffers is empty.
|
||||
pub fn transfer<'read, 'write>(
|
||||
&mut self,
|
||||
read: &'read mut [u8],
|
||||
write: &'write [u8],
|
||||
) -> SpiFuture<'_, 'read, 'write> {
|
||||
let id = self.0.id;
|
||||
Some(SpiFuture::new_for_transfer(&mut self.0, id, read, write))
|
||||
SpiFuture::new_for_transfer(&mut self.0, id, read, write)
|
||||
}
|
||||
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) -> Option<SpiFuture<'_>> {
|
||||
if words.is_empty() {
|
||||
return None;
|
||||
}
|
||||
/// Future which writes and reads simultaneously. The contents of `words` are
|
||||
/// written to the slave, and the received words are stored into the same
|
||||
/// `words` buffer, overwriting it.
|
||||
///
|
||||
/// Returns [None] if the provided buffer is empty.
|
||||
pub fn transfer_in_place<'read>(&mut self, words: &'read mut [u8]) -> SpiFuture<'_, 'read, '_> {
|
||||
let id = self.0.id;
|
||||
Some(SpiFuture::new_for_transfer_in_place(&mut self.0, id, words))
|
||||
SpiFuture::new_for_transfer_in_place(&mut self.0, id, words)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,28 +695,28 @@ impl embedded_hal_async::spi::SpiBus for SpiAsync {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.read(words).unwrap().await
|
||||
self.read(words).await
|
||||
}
|
||||
|
||||
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.write(words).unwrap().await
|
||||
self.write(words).await
|
||||
}
|
||||
|
||||
async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||
if read.is_empty() && write.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.transfer(read, write).unwrap().await
|
||||
self.transfer(read, write).await
|
||||
}
|
||||
|
||||
async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.transfer_in_place(words).unwrap().await
|
||||
self.transfer_in_place(words).await
|
||||
}
|
||||
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
|
||||
@@ -1138,6 +1138,14 @@ pub struct Tx {
|
||||
regs: regs::MmioUart<'static>,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Tx {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Tx")
|
||||
.field("id", &self.id)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl Tx {
|
||||
/// Retrieve a TX pin without expecting an explicit UART structure
|
||||
///
|
||||
@@ -1241,8 +1249,13 @@ impl Tx {
|
||||
self.regs.write_data(Data::new_with_raw_value(data));
|
||||
}
|
||||
|
||||
pub fn into_async(self) -> TxAsync {
|
||||
TxAsync::new(self)
|
||||
/// Create an asynchronous UART driver.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [TxAsync::new] for details.
|
||||
pub unsafe fn into_async(self) -> TxAsync {
|
||||
unsafe { TxAsync::new(self) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use critical_section::Mutex;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embedded_io_async::Write;
|
||||
use portable_atomic::AtomicBool;
|
||||
use raw_slice::RawBufSlice;
|
||||
use raw_buffer::RawBufSlice;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -112,16 +112,30 @@ impl TxContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TxFuture {
|
||||
#[derive(Debug)]
|
||||
pub struct TxFuture<'uart, 'buf> {
|
||||
id: Bank,
|
||||
empty_buffer: bool,
|
||||
// Phantom used to borrow the buffer for the lifetime of the future.
|
||||
phantom: core::marker::PhantomData<(&'uart (), &'buf ())>,
|
||||
}
|
||||
|
||||
impl TxFuture {
|
||||
impl<'uart, 'buf> TxFuture<'uart, 'buf> {
|
||||
/// # Safety
|
||||
///
|
||||
/// This function stores the raw pointer of the passed data slice. The user MUST ensure
|
||||
/// that the slice outlives the data structure.
|
||||
pub unsafe fn new(tx: &mut Tx, data: &[u8]) -> Self {
|
||||
/// This case was considered exotic enough to justify not making the function `unsafe`.
|
||||
pub fn new(tx: &'uart mut Tx, data: &'buf [u8]) -> Self {
|
||||
if data.is_empty() {
|
||||
// We can just return a dummy future which is immediately ready, no need to set up
|
||||
// interrupts etc.
|
||||
return Self {
|
||||
id: tx.id,
|
||||
empty_buffer: true,
|
||||
phantom: core::marker::PhantomData,
|
||||
};
|
||||
}
|
||||
TX_DONE[tx.id as usize].store(false, core::sync::atomic::Ordering::Relaxed);
|
||||
tx.disable_interrupts();
|
||||
tx.disable();
|
||||
@@ -147,17 +161,24 @@ impl TxFuture {
|
||||
);
|
||||
tx.enable();
|
||||
});
|
||||
Self { id: tx.id }
|
||||
Self {
|
||||
id: tx.id,
|
||||
empty_buffer: false,
|
||||
phantom: core::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for TxFuture {
|
||||
impl Future for TxFuture<'_, '_> {
|
||||
type Output = Result<usize, TxOverrunError>;
|
||||
|
||||
fn poll(
|
||||
self: core::pin::Pin<&mut Self>,
|
||||
cx: &mut core::task::Context<'_>,
|
||||
) -> core::task::Poll<Self::Output> {
|
||||
if self.empty_buffer {
|
||||
return core::task::Poll::Ready(Ok(0));
|
||||
}
|
||||
UART_TX_WAKERS[self.id as usize].register(cx.waker());
|
||||
if TX_DONE[self.id as usize].swap(false, core::sync::atomic::Ordering::Relaxed) {
|
||||
let progress = critical_section::with(|cs| {
|
||||
@@ -169,20 +190,31 @@ impl Future for TxFuture {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TxFuture {
|
||||
/// Safety note:
|
||||
///
|
||||
/// It is imperative that this `Drop` method is executed to avoid undefined behaviour on
|
||||
/// transfer. Do *NOT* use `core::mem::forget` on the `TxFuture`.
|
||||
impl Drop for TxFuture<'_, '_> {
|
||||
fn drop(&mut self) {
|
||||
let mut reg_block = unsafe { self.id.steal_regs() };
|
||||
if !TX_DONE[self.id as usize].load(core::sync::atomic::Ordering::Relaxed) {
|
||||
if !TX_DONE[self.id as usize].load(core::sync::atomic::Ordering::Relaxed)
|
||||
&& !self.empty_buffer
|
||||
{
|
||||
disable_tx_interrupts(&mut reg_block);
|
||||
disable_tx(&mut reg_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TxAsync(Tx);
|
||||
|
||||
impl TxAsync {
|
||||
pub fn new(tx: Tx) -> Self {
|
||||
/// # Safety
|
||||
///
|
||||
/// The user MUST ensure that the `Drop` method of all futures generated with this driver
|
||||
/// is called on transfer cancellation. By default, this does not require any special handling.
|
||||
pub unsafe fn new(tx: Tx) -> Self {
|
||||
Self(tx)
|
||||
}
|
||||
|
||||
@@ -195,9 +227,8 @@ impl TxAsync {
|
||||
///
|
||||
/// This implementation is not side effect free, and a started future might have already
|
||||
/// written part of the passed buffer.
|
||||
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, TxOverrunError> {
|
||||
let fut = unsafe { TxFuture::new(&mut self.0, buf) };
|
||||
fut.await
|
||||
pub fn write<'buf>(&mut self, buf: &'buf [u8]) -> TxFuture<'_, 'buf> {
|
||||
TxFuture::new(&mut self.0, buf)
|
||||
}
|
||||
|
||||
/// Write an entire buffer into this writer.
|
||||
|
||||
Reference in new issue
Block a user