Compare commits
26 Commits
rcc-no-spa
...
asynci2cv1
Author | SHA1 | Date | |
---|---|---|---|
54123de7bd | |||
838a97c186 | |||
5bc7557826 | |||
006260fedd | |||
e3ee24017d | |||
467b53076c | |||
27e6634c9d | |||
1f9b649f80 | |||
bef9b7a853 | |||
50a983fd9b | |||
7e5deae589 | |||
a2c440ef8c | |||
fd670a9ae5 | |||
ef69f386ab | |||
872f1ec4c2 | |||
6ccd8c051e | |||
c46418f123 | |||
19ff043acd | |||
ea99671729 | |||
8eff749823 | |||
cdcd3e26dd | |||
18c1f9dd56 | |||
ac7134ed0d | |||
0f2208c0af | |||
6c42885d4a | |||
3b33cc4691 |
@ -1,4 +1,5 @@
|
|||||||
use core::cmp::{max, min};
|
use core::cmp::{max, min};
|
||||||
|
use core::iter::zip;
|
||||||
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
|
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
|
||||||
@ -16,6 +17,12 @@ pub struct Error {
|
|||||||
pub status: u32,
|
pub status: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AddMulticastAddressError {
|
||||||
|
NotMulticast,
|
||||||
|
NoFreeSlots,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Control<'a> {
|
pub struct Control<'a> {
|
||||||
state_ch: ch::StateRunner<'a>,
|
state_ch: ch::StateRunner<'a>,
|
||||||
events: &'a Events,
|
events: &'a Events,
|
||||||
@ -316,6 +323,54 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP
|
self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add specified address to the list of hardware addresses the device
|
||||||
|
/// listens on. The address must be a Group address (I/G bit set). Up
|
||||||
|
/// to 10 addresses are supported by the firmware. Returns the number of
|
||||||
|
/// address slots filled after adding, or an error.
|
||||||
|
pub async fn add_multicast_address(&mut self, address: [u8; 6]) -> Result<usize, AddMulticastAddressError> {
|
||||||
|
// The firmware seems to ignore non-multicast addresses, so let's
|
||||||
|
// prevent the user from adding them and wasting space.
|
||||||
|
if address[0] & 0x01 != 1 {
|
||||||
|
return Err(AddMulticastAddressError::NotMulticast);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
self.get_iovar("mcast_list", &mut buf).await;
|
||||||
|
|
||||||
|
let n = u32::from_le_bytes(buf[..4].try_into().unwrap()) as usize;
|
||||||
|
let (used, free) = buf[4..].split_at_mut(n * 6);
|
||||||
|
|
||||||
|
if used.chunks(6).any(|a| a == address) {
|
||||||
|
return Ok(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if free.len() < 6 {
|
||||||
|
return Err(AddMulticastAddressError::NoFreeSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
free[..6].copy_from_slice(&address);
|
||||||
|
let n = n + 1;
|
||||||
|
buf[..4].copy_from_slice(&(n as u32).to_le_bytes());
|
||||||
|
|
||||||
|
self.set_iovar_v::<80>("mcast_list", &buf).await;
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the list of configured multicast hardware addresses.
|
||||||
|
pub async fn list_mulistcast_addresses(&mut self, result: &mut [[u8; 6]; 10]) -> usize {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
self.get_iovar("mcast_list", &mut buf).await;
|
||||||
|
|
||||||
|
let n = u32::from_le_bytes(buf[..4].try_into().unwrap()) as usize;
|
||||||
|
let used = &buf[4..][..n * 6];
|
||||||
|
|
||||||
|
for (addr, output) in zip(used.chunks(6), result.iter_mut()) {
|
||||||
|
output.copy_from_slice(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
|
async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) {
|
||||||
let mut buf = [0; 8];
|
let mut buf = [0; 8];
|
||||||
buf[0..4].copy_from_slice(&val1.to_le_bytes());
|
buf[0..4].copy_from_slice(&val1.to_le_bytes());
|
||||||
|
@ -27,7 +27,7 @@ use ioctl::IoctlState;
|
|||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
pub use crate::control::{Control, Error as ControlError, Scanner};
|
pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner};
|
||||||
pub use crate::runner::Runner;
|
pub use crate::runner::Runner;
|
||||||
pub use crate::structs::BssInfo;
|
pub use crate::structs::BssInfo;
|
||||||
|
|
||||||
|
@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 0.3.3 - 2023-11-15
|
||||||
|
|
||||||
|
- Add `main` macro reexport for Xtensa arch.
|
||||||
|
- Remove use of `atomic-polyfill`. The executor now has multiple implementations of its internal data structures for cases where the target supports atomics or doesn't.
|
||||||
|
|
||||||
## 0.3.2 - 2023-11-06
|
## 0.3.2 - 2023-11-06
|
||||||
|
|
||||||
- Use `atomic-polyfill` for `riscv32`
|
- Use `atomic-polyfill` for `riscv32`
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "async/await executor designed for embedded usage"
|
description = "async/await executor designed for embedded usage"
|
||||||
@ -34,7 +34,7 @@ _arch = [] # some arch was picked
|
|||||||
arch-std = ["_arch", "critical-section/std"]
|
arch-std = ["_arch", "critical-section/std"]
|
||||||
arch-cortex-m = ["_arch", "dep:cortex-m"]
|
arch-cortex-m = ["_arch", "dep:cortex-m"]
|
||||||
arch-xtensa = ["_arch"]
|
arch-xtensa = ["_arch"]
|
||||||
arch-riscv32 = ["_arch"]
|
arch-riscv32 = ["_arch", "dep:portable-atomic"]
|
||||||
arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
|
arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
|
||||||
|
|
||||||
# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
|
# Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
|
||||||
@ -59,9 +59,12 @@ rtos-trace = { version = "0.1.2", optional = true }
|
|||||||
|
|
||||||
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
||||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
|
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
|
||||||
atomic-polyfill = "1.0.1"
|
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
|
|
||||||
|
# needed for riscv
|
||||||
|
# remove when https://github.com/rust-lang/rust/pull/114499 is merged
|
||||||
|
portable-atomic = { version = "1.5", optional = true }
|
||||||
|
|
||||||
# arch-cortex-m dependencies
|
# arch-cortex-m dependencies
|
||||||
cortex-m = { version = "0.7.6", optional = true }
|
cortex-m = { version = "0.7.6", optional = true }
|
||||||
|
|
||||||
|
@ -115,12 +115,12 @@ mod thread {
|
|||||||
pub use interrupt::*;
|
pub use interrupt::*;
|
||||||
#[cfg(feature = "executor-interrupt")]
|
#[cfg(feature = "executor-interrupt")]
|
||||||
mod interrupt {
|
mod interrupt {
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::{Cell, UnsafeCell};
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, Ordering};
|
|
||||||
use cortex_m::interrupt::InterruptNumber;
|
use cortex_m::interrupt::InterruptNumber;
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
|
use critical_section::Mutex;
|
||||||
|
|
||||||
use crate::raw;
|
use crate::raw;
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ mod interrupt {
|
|||||||
/// It is somewhat more complex to use, it's recommended to use the thread-mode
|
/// It is somewhat more complex to use, it's recommended to use the thread-mode
|
||||||
/// [`Executor`] instead, if it works for your use case.
|
/// [`Executor`] instead, if it works for your use case.
|
||||||
pub struct InterruptExecutor {
|
pub struct InterruptExecutor {
|
||||||
started: AtomicBool,
|
started: Mutex<Cell<bool>>,
|
||||||
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
|
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +158,7 @@ mod interrupt {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
started: AtomicBool::new(false),
|
started: Mutex::new(Cell::new(false)),
|
||||||
executor: UnsafeCell::new(MaybeUninit::uninit()),
|
executor: UnsafeCell::new(MaybeUninit::uninit()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +167,8 @@ mod interrupt {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// You MUST call this from the interrupt handler, and from nowhere else.
|
/// - You MUST call this from the interrupt handler, and from nowhere else.
|
||||||
|
/// - You must not call this before calling `start()`.
|
||||||
pub unsafe fn on_interrupt(&'static self) {
|
pub unsafe fn on_interrupt(&'static self) {
|
||||||
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
||||||
executor.poll();
|
executor.poll();
|
||||||
@ -196,11 +197,7 @@ mod interrupt {
|
|||||||
/// do it after.
|
/// do it after.
|
||||||
///
|
///
|
||||||
pub fn start(&'static self, irq: impl InterruptNumber) -> crate::SendSpawner {
|
pub fn start(&'static self, irq: impl InterruptNumber) -> crate::SendSpawner {
|
||||||
if self
|
if critical_section::with(|cs| self.started.borrow(cs).replace(true)) {
|
||||||
.started
|
|
||||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
panic!("InterruptExecutor::start() called multiple times on the same executor.");
|
panic!("InterruptExecutor::start() called multiple times on the same executor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,10 +219,10 @@ mod interrupt {
|
|||||||
/// This returns a [`SendSpawner`] you can use to spawn tasks on this
|
/// This returns a [`SendSpawner`] you can use to spawn tasks on this
|
||||||
/// executor.
|
/// executor.
|
||||||
///
|
///
|
||||||
/// This MUST only be called on an executor that has already been spawned.
|
/// This MUST only be called on an executor that has already been started.
|
||||||
/// The function will panic otherwise.
|
/// The function will panic otherwise.
|
||||||
pub fn spawner(&'static self) -> crate::SendSpawner {
|
pub fn spawner(&'static self) -> crate::SendSpawner {
|
||||||
if !self.started.load(Ordering::Acquire) {
|
if !critical_section::with(|cs| self.started.borrow(cs).get()) {
|
||||||
panic!("InterruptExecutor::spawner() called on uninitialized executor.");
|
panic!("InterruptExecutor::spawner() called on uninitialized executor.");
|
||||||
}
|
}
|
||||||
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
||||||
|
@ -7,9 +7,9 @@ pub use thread::*;
|
|||||||
mod thread {
|
mod thread {
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, Ordering};
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub use embassy_macros::main_riscv as main;
|
pub use embassy_macros::main_riscv as main;
|
||||||
|
use portable_atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::{raw, Spawner};
|
use crate::{raw, Spawner};
|
||||||
|
|
||||||
|
@ -8,6 +8,9 @@ mod thread {
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
#[cfg(feature = "nightly")]
|
||||||
|
pub use embassy_macros::main_riscv as main;
|
||||||
|
|
||||||
use crate::{raw, Spawner};
|
use crate::{raw, Spawner};
|
||||||
|
|
||||||
/// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
|
/// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa
|
||||||
|
@ -7,7 +7,15 @@
|
|||||||
//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
|
//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
|
||||||
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
|
//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_macros::task) macro, which are fully safe.
|
||||||
|
|
||||||
|
#[cfg_attr(target_has_atomic = "ptr", path = "run_queue_atomics.rs")]
|
||||||
|
#[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")]
|
||||||
mod run_queue;
|
mod run_queue;
|
||||||
|
|
||||||
|
#[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")]
|
||||||
|
#[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")]
|
||||||
|
#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
|
||||||
|
mod state;
|
||||||
|
|
||||||
#[cfg(feature = "integrated-timers")]
|
#[cfg(feature = "integrated-timers")]
|
||||||
mod timer_queue;
|
mod timer_queue;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
@ -21,7 +29,6 @@ use core::pin::Pin;
|
|||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU32, Ordering};
|
|
||||||
#[cfg(feature = "integrated-timers")]
|
#[cfg(feature = "integrated-timers")]
|
||||||
use embassy_time::driver::{self, AlarmHandle};
|
use embassy_time::driver::{self, AlarmHandle};
|
||||||
#[cfg(feature = "integrated-timers")]
|
#[cfg(feature = "integrated-timers")]
|
||||||
@ -30,21 +37,14 @@ use embassy_time::Instant;
|
|||||||
use rtos_trace::trace;
|
use rtos_trace::trace;
|
||||||
|
|
||||||
use self::run_queue::{RunQueue, RunQueueItem};
|
use self::run_queue::{RunQueue, RunQueueItem};
|
||||||
|
use self::state::State;
|
||||||
use self::util::{SyncUnsafeCell, UninitCell};
|
use self::util::{SyncUnsafeCell, UninitCell};
|
||||||
pub use self::waker::task_from_waker;
|
pub use self::waker::task_from_waker;
|
||||||
use super::SpawnToken;
|
use super::SpawnToken;
|
||||||
|
|
||||||
/// Task is spawned (has a future)
|
|
||||||
pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
|
|
||||||
/// Task is in the executor run queue
|
|
||||||
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
|
|
||||||
/// Task is in the executor timer queue
|
|
||||||
#[cfg(feature = "integrated-timers")]
|
|
||||||
pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
|
|
||||||
|
|
||||||
/// Raw task header for use in task pointers.
|
/// Raw task header for use in task pointers.
|
||||||
pub(crate) struct TaskHeader {
|
pub(crate) struct TaskHeader {
|
||||||
pub(crate) state: AtomicU32,
|
pub(crate) state: State,
|
||||||
pub(crate) run_queue_item: RunQueueItem,
|
pub(crate) run_queue_item: RunQueueItem,
|
||||||
pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>,
|
pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>,
|
||||||
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
|
||||||
@ -116,7 +116,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
raw: TaskHeader {
|
raw: TaskHeader {
|
||||||
state: AtomicU32::new(0),
|
state: State::new(),
|
||||||
run_queue_item: RunQueueItem::new(),
|
run_queue_item: RunQueueItem::new(),
|
||||||
executor: SyncUnsafeCell::new(None),
|
executor: SyncUnsafeCell::new(None),
|
||||||
// Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
|
// Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
|
||||||
@ -161,7 +161,7 @@ impl<F: Future + 'static> TaskStorage<F> {
|
|||||||
match future.poll(&mut cx) {
|
match future.poll(&mut cx) {
|
||||||
Poll::Ready(_) => {
|
Poll::Ready(_) => {
|
||||||
this.future.drop_in_place();
|
this.future.drop_in_place();
|
||||||
this.raw.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel);
|
this.raw.state.despawn();
|
||||||
|
|
||||||
#[cfg(feature = "integrated-timers")]
|
#[cfg(feature = "integrated-timers")]
|
||||||
this.raw.expires_at.set(Instant::MAX);
|
this.raw.expires_at.set(Instant::MAX);
|
||||||
@ -193,11 +193,7 @@ impl<F: Future + 'static> AvailableTask<F> {
|
|||||||
///
|
///
|
||||||
/// This function returns `None` if a task has already been spawned and has not finished running.
|
/// This function returns `None` if a task has already been spawned and has not finished running.
|
||||||
pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> {
|
pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> {
|
||||||
task.raw
|
task.raw.state.spawn().then(|| Self { task })
|
||||||
.state
|
|
||||||
.compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire)
|
|
||||||
.ok()
|
|
||||||
.map(|_| Self { task })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
||||||
@ -394,8 +390,7 @@ impl SyncExecutor {
|
|||||||
#[cfg(feature = "integrated-timers")]
|
#[cfg(feature = "integrated-timers")]
|
||||||
task.expires_at.set(Instant::MAX);
|
task.expires_at.set(Instant::MAX);
|
||||||
|
|
||||||
let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
|
if !task.state.run_dequeue() {
|
||||||
if state & STATE_SPAWNED == 0 {
|
|
||||||
// If task is not running, ignore it. This can happen in the following scenario:
|
// If task is not running, ignore it. This can happen in the following scenario:
|
||||||
// - Task gets dequeued, poll starts
|
// - Task gets dequeued, poll starts
|
||||||
// - While task is being polled, it gets woken. It gets placed in the queue.
|
// - While task is being polled, it gets woken. It gets placed in the queue.
|
||||||
@ -546,18 +541,7 @@ impl Executor {
|
|||||||
/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
|
/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
|
||||||
pub fn wake_task(task: TaskRef) {
|
pub fn wake_task(task: TaskRef) {
|
||||||
let header = task.header();
|
let header = task.header();
|
||||||
|
if header.state.run_enqueue() {
|
||||||
let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
|
|
||||||
// If already scheduled, or if not started,
|
|
||||||
if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Mark it as scheduled
|
|
||||||
Some(state | STATE_RUN_QUEUED)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if res.is_ok() {
|
|
||||||
// We have just marked the task as scheduled, so enqueue it.
|
// We have just marked the task as scheduled, so enqueue it.
|
||||||
unsafe {
|
unsafe {
|
||||||
let executor = header.executor.get().unwrap_unchecked();
|
let executor = header.executor.get().unwrap_unchecked();
|
||||||
@ -571,18 +555,7 @@ pub fn wake_task(task: TaskRef) {
|
|||||||
/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
|
/// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`].
|
||||||
pub fn wake_task_no_pend(task: TaskRef) {
|
pub fn wake_task_no_pend(task: TaskRef) {
|
||||||
let header = task.header();
|
let header = task.header();
|
||||||
|
if header.state.run_enqueue() {
|
||||||
let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
|
|
||||||
// If already scheduled, or if not started,
|
|
||||||
if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Mark it as scheduled
|
|
||||||
Some(state | STATE_RUN_QUEUED)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if res.is_ok() {
|
|
||||||
// We have just marked the task as scheduled, so enqueue it.
|
// We have just marked the task as scheduled, so enqueue it.
|
||||||
unsafe {
|
unsafe {
|
||||||
let executor = header.executor.get().unwrap_unchecked();
|
let executor = header.executor.get().unwrap_unchecked();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||||
use atomic_polyfill::{AtomicPtr, Ordering};
|
|
||||||
|
|
||||||
use super::{TaskHeader, TaskRef};
|
use super::{TaskHeader, TaskRef};
|
||||||
use crate::raw::util::SyncUnsafeCell;
|
use crate::raw::util::SyncUnsafeCell;
|
75
embassy-executor/src/raw/run_queue_critical_section.rs
Normal file
75
embassy-executor/src/raw/run_queue_critical_section.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use core::cell::Cell;
|
||||||
|
|
||||||
|
use critical_section::{CriticalSection, Mutex};
|
||||||
|
|
||||||
|
use super::TaskRef;
|
||||||
|
|
||||||
|
pub(crate) struct RunQueueItem {
|
||||||
|
next: Mutex<Cell<Option<TaskRef>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunQueueItem {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
next: Mutex::new(Cell::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Atomic task queue using a very, very simple lock-free linked-list queue:
|
||||||
|
///
|
||||||
|
/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
|
||||||
|
///
|
||||||
|
/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
|
||||||
|
/// null. Then the batch is iterated following the next pointers until null is reached.
|
||||||
|
///
|
||||||
|
/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
|
||||||
|
/// for our purposes: it can't create fairness problems since the next batch won't run until the
|
||||||
|
/// current batch is completely processed, so even if a task enqueues itself instantly (for example
|
||||||
|
/// by waking its own waker) can't prevent other tasks from running.
|
||||||
|
pub(crate) struct RunQueue {
|
||||||
|
head: Mutex<Cell<Option<TaskRef>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunQueue {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
head: Mutex::new(Cell::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enqueues an item. Returns true if the queue was empty.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `item` must NOT be already enqueued in any queue.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let prev = self.head.borrow(cs).replace(Some(task));
|
||||||
|
task.header().run_queue_item.next.borrow(cs).set(prev);
|
||||||
|
|
||||||
|
prev.is_none()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Empty the queue, then call `on_task` for each task that was in the queue.
|
||||||
|
/// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
|
||||||
|
/// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
|
||||||
|
pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
|
||||||
|
// Atomically empty the queue.
|
||||||
|
let mut next = critical_section::with(|cs| self.head.borrow(cs).take());
|
||||||
|
|
||||||
|
// Iterate the linked list of tasks that were previously in the queue.
|
||||||
|
while let Some(task) = next {
|
||||||
|
// If the task re-enqueues itself, the `next` pointer will get overwritten.
|
||||||
|
// Therefore, first read the next pointer, and only then process the task.
|
||||||
|
|
||||||
|
// safety: we know if the task is enqueued, no one else will touch the `next` pointer.
|
||||||
|
let cs = unsafe { CriticalSection::new() };
|
||||||
|
next = task.header().run_queue_item.next.borrow(cs).get();
|
||||||
|
|
||||||
|
on_task(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
embassy-executor/src/raw/state_atomics.rs
Normal file
73
embassy-executor/src/raw/state_atomics.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
|
/// Task is spawned (has a future)
|
||||||
|
pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
|
||||||
|
/// Task is in the executor run queue
|
||||||
|
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
|
||||||
|
/// Task is in the executor timer queue
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
|
||||||
|
|
||||||
|
pub(crate) struct State {
|
||||||
|
state: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> State {
|
||||||
|
Self {
|
||||||
|
state: AtomicU32::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If task is idle, mark it as spawned + run_queued and return true.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn spawn(&self) -> bool {
|
||||||
|
self.state
|
||||||
|
.compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire)
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn despawn(&self) {
|
||||||
|
self.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_enqueue(&self) -> bool {
|
||||||
|
self.state
|
||||||
|
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
|
||||||
|
// If already scheduled, or if not started,
|
||||||
|
if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// Mark it as scheduled
|
||||||
|
Some(state | STATE_RUN_QUEUED)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as run-queued. Return whether the task is spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_dequeue(&self) -> bool {
|
||||||
|
let state = self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel);
|
||||||
|
state & STATE_SPAWNED != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before)
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_enqueue(&self) -> bool {
|
||||||
|
let old_state = self.state.fetch_or(STATE_TIMER_QUEUED, Ordering::AcqRel);
|
||||||
|
old_state & STATE_TIMER_QUEUED == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as timer-queued.
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_dequeue(&self) {
|
||||||
|
self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::AcqRel);
|
||||||
|
}
|
||||||
|
}
|
103
embassy-executor/src/raw/state_atomics_arm.rs
Normal file
103
embassy-executor/src/raw/state_atomics_arm.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
|
||||||
|
|
||||||
|
// Must be kept in sync with the layout of `State`!
|
||||||
|
pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
|
||||||
|
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8;
|
||||||
|
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub(crate) struct State {
|
||||||
|
/// Task is spawned (has a future)
|
||||||
|
spawned: AtomicBool,
|
||||||
|
/// Task is in the executor run queue
|
||||||
|
run_queued: AtomicBool,
|
||||||
|
/// Task is in the executor timer queue
|
||||||
|
timer_queued: AtomicBool,
|
||||||
|
pad: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> State {
|
||||||
|
Self {
|
||||||
|
spawned: AtomicBool::new(false),
|
||||||
|
run_queued: AtomicBool::new(false),
|
||||||
|
timer_queued: AtomicBool::new(false),
|
||||||
|
pad: AtomicBool::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_u32(&self) -> &AtomicU32 {
|
||||||
|
unsafe { &*(self as *const _ as *const AtomicU32) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If task is idle, mark it as spawned + run_queued and return true.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn spawn(&self) -> bool {
|
||||||
|
compiler_fence(Ordering::Release);
|
||||||
|
let r = self
|
||||||
|
.as_u32()
|
||||||
|
.compare_exchange(
|
||||||
|
0,
|
||||||
|
STATE_SPAWNED | STATE_RUN_QUEUED,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
Ordering::Relaxed,
|
||||||
|
)
|
||||||
|
.is_ok();
|
||||||
|
compiler_fence(Ordering::Acquire);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn despawn(&self) {
|
||||||
|
compiler_fence(Ordering::Release);
|
||||||
|
self.spawned.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_enqueue(&self) -> bool {
|
||||||
|
unsafe {
|
||||||
|
loop {
|
||||||
|
let state: u32;
|
||||||
|
asm!("ldrex {}, [{}]", out(reg) state, in(reg) self, options(nostack));
|
||||||
|
|
||||||
|
if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) {
|
||||||
|
asm!("clrex", options(nomem, nostack));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let outcome: usize;
|
||||||
|
let new_state = state | STATE_RUN_QUEUED;
|
||||||
|
asm!("strex {}, {}, [{}]", out(reg) outcome, in(reg) new_state, in(reg) self, options(nostack));
|
||||||
|
if outcome == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as run-queued. Return whether the task is spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_dequeue(&self) -> bool {
|
||||||
|
compiler_fence(Ordering::Release);
|
||||||
|
|
||||||
|
let r = self.spawned.load(Ordering::Relaxed);
|
||||||
|
self.run_queued.store(false, Ordering::Relaxed);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before)
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_enqueue(&self) -> bool {
|
||||||
|
!self.timer_queued.swap(true, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as timer-queued.
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_dequeue(&self) {
|
||||||
|
self.timer_queued.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
93
embassy-executor/src/raw/state_critical_section.rs
Normal file
93
embassy-executor/src/raw/state_critical_section.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use core::cell::Cell;
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
|
||||||
|
/// Task is spawned (has a future)
|
||||||
|
pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
|
||||||
|
/// Task is in the executor run queue
|
||||||
|
pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
|
||||||
|
/// Task is in the executor timer queue
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
|
||||||
|
|
||||||
|
pub(crate) struct State {
|
||||||
|
state: Mutex<Cell<u32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> State {
|
||||||
|
Self {
|
||||||
|
state: Mutex::new(Cell::new(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update<R>(&self, f: impl FnOnce(&mut u32) -> R) -> R {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let s = self.state.borrow(cs);
|
||||||
|
let mut val = s.get();
|
||||||
|
let r = f(&mut val);
|
||||||
|
s.set(val);
|
||||||
|
r
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If task is idle, mark it as spawned + run_queued and return true.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn spawn(&self) -> bool {
|
||||||
|
self.update(|s| {
|
||||||
|
if *s == 0 {
|
||||||
|
*s = STATE_SPAWNED | STATE_RUN_QUEUED;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn despawn(&self) {
|
||||||
|
self.update(|s| *s &= !STATE_SPAWNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_enqueue(&self) -> bool {
|
||||||
|
self.update(|s| {
|
||||||
|
if (*s & STATE_RUN_QUEUED != 0) || (*s & STATE_SPAWNED == 0) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
*s |= STATE_RUN_QUEUED;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as run-queued. Return whether the task is spawned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run_dequeue(&self) -> bool {
|
||||||
|
self.update(|s| {
|
||||||
|
let ok = *s & STATE_SPAWNED != 0;
|
||||||
|
*s &= !STATE_RUN_QUEUED;
|
||||||
|
ok
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before)
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_enqueue(&self) -> bool {
|
||||||
|
self.update(|s| {
|
||||||
|
let ok = *s & STATE_TIMER_QUEUED == 0;
|
||||||
|
*s |= STATE_TIMER_QUEUED;
|
||||||
|
ok
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmark the task as timer-queued.
|
||||||
|
#[cfg(feature = "integrated-timers")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn timer_dequeue(&self) {
|
||||||
|
self.update(|s| *s &= !STATE_TIMER_QUEUED);
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
|
|
||||||
use atomic_polyfill::Ordering;
|
|
||||||
use embassy_time::Instant;
|
use embassy_time::Instant;
|
||||||
|
|
||||||
use super::{TaskRef, STATE_TIMER_QUEUED};
|
use super::TaskRef;
|
||||||
use crate::raw::util::SyncUnsafeCell;
|
use crate::raw::util::SyncUnsafeCell;
|
||||||
|
|
||||||
pub(crate) struct TimerQueueItem {
|
pub(crate) struct TimerQueueItem {
|
||||||
@ -32,10 +31,7 @@ impl TimerQueue {
|
|||||||
pub(crate) unsafe fn update(&self, p: TaskRef) {
|
pub(crate) unsafe fn update(&self, p: TaskRef) {
|
||||||
let task = p.header();
|
let task = p.header();
|
||||||
if task.expires_at.get() != Instant::MAX {
|
if task.expires_at.get() != Instant::MAX {
|
||||||
let old_state = task.state.fetch_or(STATE_TIMER_QUEUED, Ordering::AcqRel);
|
if task.state.timer_enqueue() {
|
||||||
let is_new = old_state & STATE_TIMER_QUEUED == 0;
|
|
||||||
|
|
||||||
if is_new {
|
|
||||||
task.timer_queue_item.next.set(self.head.get());
|
task.timer_queue_item.next.set(self.head.get());
|
||||||
self.head.set(Some(p));
|
self.head.set(Some(p));
|
||||||
}
|
}
|
||||||
@ -75,7 +71,7 @@ impl TimerQueue {
|
|||||||
} else {
|
} else {
|
||||||
// Remove it
|
// Remove it
|
||||||
prev.set(task.timer_queue_item.next.get());
|
prev.set(task.timer_queue_item.next.get());
|
||||||
task.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::AcqRel);
|
task.state.timer_dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-futures"
|
name = "embassy-futures"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "no-std, no-alloc utilities for working with futures"
|
description = "no-std, no-alloc utilities for working with futures"
|
||||||
repository = "https://github.com/embassy-rs/embassy"
|
repository = "https://github.com/embassy-rs/embassy"
|
||||||
|
@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- Avoid never resolving `TcpIo::read` when the output buffer is empty.
|
- Avoid never resolving `TcpIo::read` when the output buffer is empty.
|
||||||
|
- Update to `smoltcp` git.
|
||||||
|
- Forward constants from `smoltcp` in DNS query results so changing DNS result size in `smoltcp` properly propagates.
|
||||||
|
|
||||||
## 0.2.1 - 2023-10-31
|
## 0.2.1 - 2023-10-31
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ features = ["nightly", "defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "me
|
|||||||
default = []
|
default = []
|
||||||
std = []
|
std = []
|
||||||
|
|
||||||
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt"]
|
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"]
|
||||||
|
|
||||||
nightly = ["dep:embedded-io-async", "dep:embedded-nal-async"]
|
nightly = ["dep:embedded-io-async", "dep:embedded-nal-async"]
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ igmp = ["smoltcp/proto-igmp"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "9b791ae3057e10f7afcb70c67deb5daf714293a9", default-features = false, features = [
|
smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp.git", rev = "b57e2f9e70e82a13f31d5ea17e55232c11cc2b2d", default-features = false, features = [
|
||||||
"socket",
|
"socket",
|
||||||
"async",
|
"async",
|
||||||
] }
|
] }
|
||||||
|
@ -63,7 +63,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make a query for a given name and return the corresponding IP addresses.
|
/// Make a query for a given name and return the corresponding IP addresses.
|
||||||
pub async fn query(&self, name: &str, qtype: DnsQueryType) -> Result<Vec<IpAddress, 1>, Error> {
|
pub async fn query(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
qtype: DnsQueryType,
|
||||||
|
) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, Error> {
|
||||||
self.stack.dns_query(name, qtype).await
|
self.stack.dns_query(name, qtype).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,7 +494,11 @@ impl<D: Driver> Stack<D> {
|
|||||||
|
|
||||||
/// Make a query for a given name and return the corresponding IP addresses.
|
/// Make a query for a given name and return the corresponding IP addresses.
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
|
pub async fn dns_query(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
qtype: dns::DnsQueryType,
|
||||||
|
) -> Result<Vec<IpAddress, { smoltcp::config::DNS_MAX_RESULT_COUNT }>, dns::Error> {
|
||||||
// For A and AAAA queries we try detect whether `name` is just an IP address
|
// For A and AAAA queries we try detect whether `name` is just an IP address
|
||||||
match qtype {
|
match qtype {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
@ -12,7 +12,7 @@ use core::cmp::min;
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||||
@ -41,7 +41,9 @@ mod sealed {
|
|||||||
|
|
||||||
pub rx_waker: AtomicWaker,
|
pub rx_waker: AtomicWaker,
|
||||||
pub rx_buf: RingBuffer,
|
pub rx_buf: RingBuffer,
|
||||||
pub rx_bufs: AtomicU8,
|
pub rx_started: AtomicBool,
|
||||||
|
pub rx_started_count: AtomicU8,
|
||||||
|
pub rx_ended_count: AtomicU8,
|
||||||
pub rx_ppi_ch: AtomicU8,
|
pub rx_ppi_ch: AtomicU8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,7 +67,9 @@ impl State {
|
|||||||
|
|
||||||
rx_waker: AtomicWaker::new(),
|
rx_waker: AtomicWaker::new(),
|
||||||
rx_buf: RingBuffer::new(),
|
rx_buf: RingBuffer::new(),
|
||||||
rx_bufs: AtomicU8::new(0),
|
rx_started: AtomicBool::new(false),
|
||||||
|
rx_started_count: AtomicU8::new(0),
|
||||||
|
rx_ended_count: AtomicU8::new(0),
|
||||||
rx_ppi_ch: AtomicU8::new(0),
|
rx_ppi_ch: AtomicU8::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,28 +108,20 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
|||||||
s.rx_waker.wake();
|
s.rx_waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not RXing, start.
|
if r.events_endrx.read().bits() != 0 {
|
||||||
if s.rx_bufs.load(Ordering::Relaxed) == 0 {
|
//trace!(" irq_rx: endrx");
|
||||||
let (ptr, len) = rx.push_buf();
|
r.events_endrx.reset();
|
||||||
if len >= half_len {
|
|
||||||
//trace!(" irq_rx: starting {:?}", half_len);
|
|
||||||
s.rx_bufs.store(1, Ordering::Relaxed);
|
|
||||||
|
|
||||||
// Set up the DMA read
|
let val = s.rx_ended_count.load(Ordering::Relaxed);
|
||||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
|
||||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
|
|
||||||
|
|
||||||
// Start UARTE Receive transaction
|
|
||||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
|
||||||
rx.push_done(half_len);
|
|
||||||
r.intenset.write(|w| w.rxstarted().set());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.events_rxstarted.read().bits() != 0 {
|
if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) {
|
||||||
//trace!(" irq_rx: rxstarted");
|
//trace!(" irq_rx: rxstarted");
|
||||||
let (ptr, len) = rx.push_buf();
|
let (ptr, len) = rx.push_buf();
|
||||||
if len >= half_len {
|
if len >= half_len {
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
|
||||||
//trace!(" irq_rx: starting second {:?}", half_len);
|
//trace!(" irq_rx: starting second {:?}", half_len);
|
||||||
|
|
||||||
// Set up the DMA read
|
// Set up the DMA read
|
||||||
@ -134,11 +130,50 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
|
|||||||
|
|
||||||
let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
|
let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Enable endrx -> startrx PPI channel.
|
||||||
|
// From this point on, if endrx happens, startrx is automatically fired.
|
||||||
ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
|
ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
|
||||||
|
|
||||||
|
// It is possible that endrx happened BEFORE enabling the PPI. In this case
|
||||||
|
// the PPI channel doesn't trigger, and we'd hang. We have to detect this
|
||||||
|
// and manually start.
|
||||||
|
|
||||||
|
// check again in case endrx has happened between the last check and now.
|
||||||
|
if r.events_endrx.read().bits() != 0 {
|
||||||
|
//trace!(" irq_rx: endrx");
|
||||||
|
r.events_endrx.reset();
|
||||||
|
|
||||||
|
let val = s.rx_ended_count.load(Ordering::Relaxed);
|
||||||
|
s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rx_ended = s.rx_ended_count.load(Ordering::Relaxed);
|
||||||
|
let rx_started = s.rx_started_count.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
// If we started the same amount of transfers as ended, the last rxend has
|
||||||
|
// already occured.
|
||||||
|
let rxend_happened = rx_started == rx_ended;
|
||||||
|
|
||||||
|
// Check if the PPI channel is still enabled. The PPI channel disables itself
|
||||||
|
// when it fires, so if it's still enabled it hasn't fired.
|
||||||
|
let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0;
|
||||||
|
|
||||||
|
// if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed.
|
||||||
|
// this condition also naturally matches if `!started`, needed to kickstart the DMA.
|
||||||
|
if rxend_happened && ppi_ch_enabled {
|
||||||
|
//trace!("manually starting.");
|
||||||
|
|
||||||
|
// disable the ppi ch, it's of no use anymore.
|
||||||
|
ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) });
|
||||||
|
|
||||||
|
// manually start
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
|
||||||
rx.push_done(half_len);
|
rx.push_done(half_len);
|
||||||
|
|
||||||
r.events_rxstarted.reset();
|
s.rx_started_count.store(rx_started.wrapping_add(1), Ordering::Relaxed);
|
||||||
|
s.rx_started.store(true, Ordering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
//trace!(" irq_rx: rxstarted no buf");
|
//trace!(" irq_rx: rxstarted no buf");
|
||||||
r.intenclr.write(|w| w.rxstarted().clear());
|
r.intenclr.write(|w| w.rxstarted().clear());
|
||||||
@ -282,6 +317,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
|
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
|
|
||||||
|
let hwfc = cts.is_some();
|
||||||
|
|
||||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||||
|
|
||||||
@ -303,7 +340,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
// Initialize state
|
// Initialize state
|
||||||
let s = U::buffered_state();
|
let s = U::buffered_state();
|
||||||
s.tx_count.store(0, Ordering::Relaxed);
|
s.tx_count.store(0, Ordering::Relaxed);
|
||||||
s.rx_bufs.store(0, Ordering::Relaxed);
|
s.rx_started_count.store(0, Ordering::Relaxed);
|
||||||
|
s.rx_ended_count.store(0, Ordering::Relaxed);
|
||||||
let len = tx_buffer.len();
|
let len = tx_buffer.len();
|
||||||
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||||
let len = rx_buffer.len();
|
let len = rx_buffer.len();
|
||||||
@ -311,7 +349,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
|
|
||||||
// Configure
|
// Configure
|
||||||
r.config.write(|w| {
|
r.config.write(|w| {
|
||||||
w.hwfc().bit(false);
|
w.hwfc().bit(hwfc);
|
||||||
w.parity().variant(config.parity);
|
w.parity().variant(config.parity);
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
@ -333,6 +371,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
w.endtx().set();
|
w.endtx().set();
|
||||||
w.rxstarted().set();
|
w.rxstarted().set();
|
||||||
w.error().set();
|
w.error().set();
|
||||||
|
w.endrx().set();
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,5 +94,5 @@ pio = {version= "0.2.1" }
|
|||||||
rp2040-boot2 = "0.3"
|
rp2040-boot2 = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
embassy-executor = { version = "0.3.1", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
|
embassy-executor = { version = "0.3.3", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
|
||||||
static_cell = { version = "2" }
|
static_cell = { version = "2" }
|
||||||
|
@ -39,7 +39,7 @@ embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", fea
|
|||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||||
embassy-executor = { version = "0.3.1", path = "../embassy-executor", optional = true }
|
embassy-executor = { version = "0.3.3", path = "../embassy-executor", optional = true }
|
||||||
|
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
|
||||||
@ -58,7 +58,7 @@ rand_core = "0.6.3"
|
|||||||
sdio-host = "0.5.0"
|
sdio-host = "0.5.0"
|
||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -1137,6 +1137,23 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========
|
||||||
|
// Write peripheral_interrupts module.
|
||||||
|
let mut mt = TokenStream::new();
|
||||||
|
for p in METADATA.peripherals {
|
||||||
|
let mut pt = TokenStream::new();
|
||||||
|
|
||||||
|
for irq in p.interrupts {
|
||||||
|
let iname = format_ident!("{}", irq.interrupt);
|
||||||
|
let sname = format_ident!("{}", irq.signal);
|
||||||
|
pt.extend(quote!(pub type #sname = crate::interrupt::typelevel::#iname;));
|
||||||
|
}
|
||||||
|
|
||||||
|
let pname = format_ident!("{}", p.name);
|
||||||
|
mt.extend(quote!(pub mod #pname { #pt }));
|
||||||
|
}
|
||||||
|
g.extend(quote!(#[allow(non_camel_case_types)] pub mod peripheral_interrupts { #mt }));
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Write foreach_foo! macrotables
|
// Write foreach_foo! macrotables
|
||||||
|
|
||||||
@ -1295,6 +1312,9 @@ fn main() {
|
|||||||
|
|
||||||
let mut m = String::new();
|
let mut m = String::new();
|
||||||
|
|
||||||
|
// DO NOT ADD more macros like these.
|
||||||
|
// These turned to be a bad idea!
|
||||||
|
// Instead, make build.rs generate the final code.
|
||||||
make_table(&mut m, "foreach_flash_region", &flash_regions_table);
|
make_table(&mut m, "foreach_flash_region", &flash_regions_table);
|
||||||
make_table(&mut m, "foreach_interrupt", &interrupts_table);
|
make_table(&mut m, "foreach_interrupt", &interrupts_table);
|
||||||
make_table(&mut m, "foreach_peripheral", &peripherals_table);
|
make_table(&mut m, "foreach_peripheral", &peripherals_table);
|
||||||
|
@ -299,19 +299,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
|
|
||||||
pub fn request_stop(&mut self) {
|
pub fn request_stop(&mut self) {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
|
ch.cr().modify(|w| {
|
||||||
// Disable the channel. Keep the IEs enabled so the irqs still fire.
|
w.set_susp(true);
|
||||||
ch.cr().write(|w| {
|
|
||||||
w.set_tcie(true);
|
|
||||||
w.set_useie(true);
|
|
||||||
w.set_dteie(true);
|
|
||||||
w.set_suspie(true);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
let ch = self.channel.regs().ch(self.channel.num());
|
let ch = self.channel.regs().ch(self.channel.num());
|
||||||
!ch.sr().read().tcf()
|
let sr = ch.sr().read();
|
||||||
|
!sr.tcf() && !sr.suspf()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the total remaining transfers for the channel
|
/// Gets the total remaining transfers for the channel
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
|
|
||||||
#[cfg_attr(i2c_v1, path = "v1.rs")]
|
#[cfg_attr(i2c_v1, path = "v1.rs")]
|
||||||
#[cfg_attr(i2c_v2, path = "v2.rs")]
|
#[cfg_attr(i2c_v2, path = "v2.rs")]
|
||||||
mod _version;
|
mod _version;
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::peripherals;
|
use crate::peripherals;
|
||||||
|
|
||||||
@ -23,6 +26,20 @@ pub enum Error {
|
|||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
#[allow(unused)]
|
||||||
|
pub waker: AtomicWaker,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
waker: AtomicWaker::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Instance: crate::rcc::RccPeripheral {
|
pub trait Instance: crate::rcc::RccPeripheral {
|
||||||
fn regs() -> crate::pac::i2c::I2c;
|
fn regs() -> crate::pac::i2c::I2c;
|
||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
@ -30,7 +47,8 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: sealed::Instance + 'static {
|
pub trait Instance: sealed::Instance + 'static {
|
||||||
type Interrupt: interrupt::typelevel::Interrupt;
|
type EventInterrupt: interrupt::typelevel::Interrupt;
|
||||||
|
type ErrorInterrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_trait!(SclPin, Instance);
|
pin_trait!(SclPin, Instance);
|
||||||
@ -38,21 +56,148 @@ pin_trait!(SdaPin, Instance);
|
|||||||
dma_trait!(RxDma, Instance);
|
dma_trait!(RxDma, Instance);
|
||||||
dma_trait!(TxDma, Instance);
|
dma_trait!(TxDma, Instance);
|
||||||
|
|
||||||
foreach_interrupt!(
|
/// Interrupt handler.
|
||||||
($inst:ident, i2c, $block:ident, EV, $irq:ident) => {
|
pub struct EventInterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
_version::on_interrupt::<T>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ErrorInterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
_version::on_interrupt::<T>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach_peripheral!(
|
||||||
|
(i2c, $inst:ident) => {
|
||||||
impl sealed::Instance for peripherals::$inst {
|
impl sealed::Instance for peripherals::$inst {
|
||||||
fn regs() -> crate::pac::i2c::I2c {
|
fn regs() -> crate::pac::i2c::I2c {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state() -> &'static State {
|
fn state() -> &'static sealed::State {
|
||||||
static STATE: State = State::new();
|
static STATE: sealed::State = sealed::State::new();
|
||||||
&STATE
|
&STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance for peripherals::$inst {
|
impl Instance for peripherals::$inst {
|
||||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
type EventInterrupt = crate::_generated::peripheral_interrupts::$inst::EV;
|
||||||
|
type ErrorInterrupt = crate::_generated::peripheral_interrupts::$inst::ER;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mod eh02 {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_read(address, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(address, write)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write_read(address, write, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-traits")]
|
||||||
|
mod eh1 {
|
||||||
|
use super::*;
|
||||||
|
use crate::dma::NoDma;
|
||||||
|
|
||||||
|
impl embedded_hal_1::i2c::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
|
||||||
|
match *self {
|
||||||
|
Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
|
||||||
|
Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
|
||||||
|
Self::Nack => {
|
||||||
|
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
|
||||||
|
}
|
||||||
|
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
|
||||||
|
Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
|
||||||
|
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_read(address, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write(address, write)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.blocking_write_read(address, write, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction(
|
||||||
|
&mut self,
|
||||||
|
_address: u8,
|
||||||
|
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))]
|
||||||
|
mod eha {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
|
||||||
|
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.read(address, read).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.write(address, write).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.write_read(address, write, read).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn transaction(
|
||||||
|
&mut self,
|
||||||
|
address: u8,
|
||||||
|
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let _ = address;
|
||||||
|
let _ = operations;
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,23 +1,33 @@
|
|||||||
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
|
use embassy_futures::select::{select, Either};
|
||||||
|
use embassy_hal_internal::drop::OnDrop;
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::dma::NoDma;
|
use super::*;
|
||||||
|
use crate::dma::{NoDma, Transfer};
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::gpio::Pull;
|
use crate::gpio::Pull;
|
||||||
use crate::i2c::{Error, Instance, SclPin, SdaPin};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac::i2c;
|
use crate::pac::i2c;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::{interrupt, Peripheral};
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Interrupt handler.
|
pub unsafe fn on_interrupt<T: Instance>() {
|
||||||
pub struct InterruptHandler<T: Instance> {
|
let regs = T::regs();
|
||||||
_phantom: PhantomData<T>,
|
// i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
|
||||||
}
|
// other stuff, so we wake the task on every interrupt.
|
||||||
|
T::state().waker.wake();
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
critical_section::with(|_| {
|
||||||
unsafe fn on_interrupt() {}
|
// Clear event interrupt flag.
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_itevten(false);
|
||||||
|
w.set_iterren(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -27,14 +37,6 @@ pub struct Config {
|
|||||||
pub scl_pullup: bool,
|
pub scl_pullup: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State {}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
pub(crate) const fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
phantom: PhantomData<&'d mut T>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -48,7 +50,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
_peri: impl Peripheral<P = T> + 'd,
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
|
||||||
|
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
|
||||||
|
+ 'd,
|
||||||
tx_dma: impl Peripheral<P = TXDMA> + 'd,
|
tx_dma: impl Peripheral<P = TXDMA> + 'd,
|
||||||
rx_dma: impl Peripheral<P = RXDMA> + 'd,
|
rx_dma: impl Peripheral<P = RXDMA> + 'd,
|
||||||
freq: Hertz,
|
freq: Hertz,
|
||||||
@ -98,6 +102,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
reg.set_pe(true);
|
reg.set_pe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unsafe { T::EventInterrupt::enable() };
|
||||||
|
unsafe { T::ErrorInterrupt::enable() };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
tx_dma,
|
tx_dma,
|
||||||
@ -105,40 +112,58 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
|
fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> {
|
||||||
// Note that flags should only be cleared once they have been registered. If flags are
|
// Note that flags should only be cleared once they have been registered. If flags are
|
||||||
// cleared otherwise, there may be an inherent race condition and flags may be missed.
|
// cleared otherwise, there may be an inherent race condition and flags may be missed.
|
||||||
let sr1 = T::regs().sr1().read();
|
let sr1 = T::regs().sr1().read();
|
||||||
|
|
||||||
if sr1.timeout() {
|
if sr1.timeout() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_timeout(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_timeout(false);
|
||||||
|
});
|
||||||
return Err(Error::Timeout);
|
return Err(Error::Timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr1.pecerr() {
|
if sr1.pecerr() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_pecerr(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_pecerr(false);
|
||||||
|
});
|
||||||
return Err(Error::Crc);
|
return Err(Error::Crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr1.ovr() {
|
if sr1.ovr() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_ovr(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_ovr(false);
|
||||||
|
});
|
||||||
return Err(Error::Overrun);
|
return Err(Error::Overrun);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr1.af() {
|
if sr1.af() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_af(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_af(false);
|
||||||
|
});
|
||||||
return Err(Error::Nack);
|
return Err(Error::Nack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr1.arlo() {
|
if sr1.arlo() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_arlo(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_arlo(false);
|
||||||
|
});
|
||||||
return Err(Error::Arbitration);
|
return Err(Error::Arbitration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The errata indicates that BERR may be incorrectly detected. It recommends ignoring and
|
// The errata indicates that BERR may be incorrectly detected. It recommends ignoring and
|
||||||
// clearing the BERR bit instead.
|
// clearing the BERR bit instead.
|
||||||
if sr1.berr() {
|
if sr1.berr() {
|
||||||
T::regs().sr1().modify(|reg| reg.set_berr(false));
|
T::regs().sr1().write(|reg| {
|
||||||
|
reg.0 = !0;
|
||||||
|
reg.set_berr(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sr1)
|
Ok(sr1)
|
||||||
@ -157,13 +182,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait until START condition was generated
|
// Wait until START condition was generated
|
||||||
while !self.check_and_clear_error_flags()?.start() {
|
while !Self::check_and_clear_error_flags()?.start() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also wait until signalled we're master and everything is waiting for us
|
// Also wait until signalled we're master and everything is waiting for us
|
||||||
while {
|
while {
|
||||||
self.check_and_clear_error_flags()?;
|
Self::check_and_clear_error_flags()?;
|
||||||
|
|
||||||
let sr2 = T::regs().sr2().read();
|
let sr2 = T::regs().sr2().read();
|
||||||
!sr2.msl() && !sr2.busy()
|
!sr2.msl() && !sr2.busy()
|
||||||
@ -177,7 +202,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
// Wait until address was sent
|
// Wait until address was sent
|
||||||
// Wait for the address to be acknowledged
|
// Wait for the address to be acknowledged
|
||||||
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
||||||
while !self.check_and_clear_error_flags()?.addr() {
|
while !Self::check_and_clear_error_flags()?.addr() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +222,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
// Wait until we're ready for sending
|
// Wait until we're ready for sending
|
||||||
while {
|
while {
|
||||||
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
|
||||||
!self.check_and_clear_error_flags()?.txe()
|
!Self::check_and_clear_error_flags()?.txe()
|
||||||
} {
|
} {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
@ -208,7 +233,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
// Wait until byte is transferred
|
// Wait until byte is transferred
|
||||||
while {
|
while {
|
||||||
// Check for any potential error conditions.
|
// Check for any potential error conditions.
|
||||||
!self.check_and_clear_error_flags()?.btf()
|
!Self::check_and_clear_error_flags()?.btf()
|
||||||
} {
|
} {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
@ -219,7 +244,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
|
fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
|
||||||
while {
|
while {
|
||||||
// Check for any potential error conditions.
|
// Check for any potential error conditions.
|
||||||
self.check_and_clear_error_flags()?;
|
Self::check_and_clear_error_flags()?;
|
||||||
|
|
||||||
!T::regs().sr1().read().rxne()
|
!T::regs().sr1().read().rxne()
|
||||||
} {
|
} {
|
||||||
@ -244,7 +269,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Wait until START condition was generated
|
// Wait until START condition was generated
|
||||||
while !self.check_and_clear_error_flags()?.start() {
|
while !Self::check_and_clear_error_flags()?.start() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +286,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
// Wait until address was sent
|
// Wait until address was sent
|
||||||
// Wait for the address to be acknowledged
|
// Wait for the address to be acknowledged
|
||||||
while !self.check_and_clear_error_flags()?.addr() {
|
while !Self::check_and_clear_error_flags()?.addr() {
|
||||||
check_timeout()?;
|
check_timeout()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +361,322 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
|
||||||
self.blocking_write_read_timeout(addr, write, read, || Ok(()))
|
self.blocking_write_read_timeout(addr, write, read, || Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Async
|
||||||
|
|
||||||
|
#[inline] // pretty sure this should always be inlined
|
||||||
|
fn enable_interrupts() -> () {
|
||||||
|
T::regs().cr2().modify(|w| {
|
||||||
|
w.set_iterren(true);
|
||||||
|
w.set_itevten(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
|
{
|
||||||
|
let dma_transfer = unsafe {
|
||||||
|
let regs = T::regs();
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
// DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register.
|
||||||
|
w.set_dmaen(true);
|
||||||
|
w.set_itbufen(false);
|
||||||
|
});
|
||||||
|
// Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event.
|
||||||
|
let dst = regs.dr().as_ptr() as *mut u8;
|
||||||
|
|
||||||
|
let ch = &mut self.tx_dma;
|
||||||
|
let request = ch.request();
|
||||||
|
Transfer::new_write(ch, request, write, dst, Default::default())
|
||||||
|
};
|
||||||
|
|
||||||
|
let on_drop = OnDrop::new(|| {
|
||||||
|
let regs = T::regs();
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_dmaen(false);
|
||||||
|
w.set_iterren(false);
|
||||||
|
w.set_itevten(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::enable_interrupts();
|
||||||
|
|
||||||
|
// Send a START condition
|
||||||
|
T::regs().cr1().modify(|reg| {
|
||||||
|
reg.set_start(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
let state = T::state();
|
||||||
|
|
||||||
|
// Wait until START condition was generated
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(sr1) => {
|
||||||
|
if sr1.start() {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Also wait until signalled we're master and everything is waiting for us
|
||||||
|
Self::enable_interrupts();
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(_) => {
|
||||||
|
let sr2 = T::regs().sr2().read();
|
||||||
|
if !sr2.msl() && !sr2.busy() {
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Set up current address, we're trying to talk to
|
||||||
|
T::regs().dr().write(|reg| reg.set_dr(address << 1));
|
||||||
|
Self::enable_interrupts();
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(sr1) => {
|
||||||
|
if sr1.addr() {
|
||||||
|
// Clear the ADDR condition by reading SR2.
|
||||||
|
T::regs().sr2().read();
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Self::enable_interrupts();
|
||||||
|
let poll_error = poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
// Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other
|
||||||
|
// identical poll_fn check_and_clear matches.
|
||||||
|
Err(e) => Poll::Ready(Err::<T, Error>(e)),
|
||||||
|
Ok(_) => Poll::Pending,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for either the DMA transfer to successfully finish, or an I2C error to occur.
|
||||||
|
match select(dma_transfer, poll_error).await {
|
||||||
|
Either::Second(Err(e)) => Err(e),
|
||||||
|
_ => Ok(()),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
// The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too.
|
||||||
|
|
||||||
|
// 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
|
||||||
|
// requests then wait for a BTF event before programming the Stop condition.”
|
||||||
|
|
||||||
|
// TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it?
|
||||||
|
T::regs().cr2().modify(|w| {
|
||||||
|
w.set_dmaen(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::enable_interrupts();
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(sr1) => {
|
||||||
|
if sr1.btf() {
|
||||||
|
T::regs().cr1().modify(|w| {
|
||||||
|
w.set_stop(true);
|
||||||
|
});
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
// Wait for STOP condition to transmit.
|
||||||
|
Self::enable_interrupts();
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
if T::regs().cr1().read().stop() {
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
drop(on_drop);
|
||||||
|
|
||||||
|
// Fallthrough is success
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
RXDMA: crate::i2c::RxDma<T>,
|
||||||
|
{
|
||||||
|
let state = T::state();
|
||||||
|
let buffer_len = buffer.len();
|
||||||
|
|
||||||
|
let dma_transfer = unsafe {
|
||||||
|
let regs = T::regs();
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
// DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register.
|
||||||
|
w.set_itbufen(false);
|
||||||
|
w.set_dmaen(true);
|
||||||
|
});
|
||||||
|
// Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event.
|
||||||
|
let src = regs.dr().as_ptr() as *mut u8;
|
||||||
|
|
||||||
|
let ch = &mut self.rx_dma;
|
||||||
|
let request = ch.request();
|
||||||
|
Transfer::new_read(ch, request, src, buffer, Default::default())
|
||||||
|
};
|
||||||
|
|
||||||
|
let on_drop = OnDrop::new(|| {
|
||||||
|
let regs = T::regs();
|
||||||
|
regs.cr2().modify(|w| {
|
||||||
|
w.set_dmaen(false);
|
||||||
|
w.set_iterren(false);
|
||||||
|
w.set_itevten(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::enable_interrupts();
|
||||||
|
|
||||||
|
// Send a START condition and set ACK bit
|
||||||
|
T::regs().cr1().modify(|reg| {
|
||||||
|
reg.set_start(true);
|
||||||
|
reg.set_ack(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait until START condition was generated
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(sr1) => {
|
||||||
|
if sr1.start() {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Also wait until signalled we're master and everything is waiting for us
|
||||||
|
Self::enable_interrupts();
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
// blocking read didn’t have a check_and_clear call here, but blocking write did so
|
||||||
|
// I’m adding it here in case that was an oversight.
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(_) => {
|
||||||
|
let sr2 = T::regs().sr2().read();
|
||||||
|
if !sr2.msl() && !sr2.busy() {
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Set up current address, we're trying to talk to
|
||||||
|
T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1));
|
||||||
|
|
||||||
|
// Wait for the address to be acknowledged
|
||||||
|
|
||||||
|
Self::enable_interrupts();
|
||||||
|
poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
Ok(sr1) => {
|
||||||
|
if sr1.addr() {
|
||||||
|
// 18.3.8: When a single byte must be received: the NACK must be programmed during EV6
|
||||||
|
// event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. Then the
|
||||||
|
// user can program the STOP condition either after clearing ADDR flag, or in the
|
||||||
|
// DMA Transfer Complete interrupt routine.
|
||||||
|
if buffer_len == 1 {
|
||||||
|
T::regs().cr1().modify(|w| {
|
||||||
|
w.set_ack(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Clear condition by reading SR2
|
||||||
|
T::regs().sr2().read();
|
||||||
|
|
||||||
|
// Wait for bytes to be received, or an error to occur.
|
||||||
|
Self::enable_interrupts();
|
||||||
|
let poll_error = poll_fn(|cx| {
|
||||||
|
state.waker.register(cx.waker());
|
||||||
|
|
||||||
|
match Self::check_and_clear_error_flags() {
|
||||||
|
Err(e) => Poll::Ready(Err::<T, Error>(e)),
|
||||||
|
_ => Poll::Pending,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match select(dma_transfer, poll_error).await {
|
||||||
|
Either::Second(Err(e)) => Err(e),
|
||||||
|
_ => Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// v1 blocking waits for STOP to be written, the manual says to write the STOP bit yourself.
|
||||||
|
// what to do…
|
||||||
|
// Wait for the STOP to be sent.
|
||||||
|
// while T::regs().cr1().read().stop() {
|
||||||
|
// check_timeout()?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Fallthrough is success
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn write_read(&mut self, _address: u8, _write: &[u8], _read: &mut [u8]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
RXDMA: crate::i2c::RxDma<T>,
|
||||||
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
||||||
@ -344,77 +685,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_read(addr, read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write(addr, write)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write_read(addr, write, read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "unstable-traits")]
|
|
||||||
mod eh1 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl embedded_hal_1::i2c::Error for Error {
|
|
||||||
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
|
|
||||||
match *self {
|
|
||||||
Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
|
|
||||||
Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
|
|
||||||
Self::Nack => {
|
|
||||||
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
|
|
||||||
}
|
|
||||||
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
|
|
||||||
Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> {
|
|
||||||
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_read(address, read)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write(address, write)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write_read(address, write, read)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction(
|
|
||||||
&mut self,
|
|
||||||
_address: u8,
|
|
||||||
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
Fast,
|
Fast,
|
||||||
Standard,
|
Standard,
|
||||||
|
@ -1,48 +1,51 @@
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
#[cfg(feature = "time")]
|
|
||||||
use embassy_hal_internal::drop::OnDrop;
|
use embassy_hal_internal::drop::OnDrop;
|
||||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
use embassy_time::{Duration, Instant};
|
use embassy_time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::dma::NoDma;
|
use super::*;
|
||||||
#[cfg(feature = "time")]
|
use crate::dma::{NoDma, Transfer};
|
||||||
use crate::dma::Transfer;
|
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::gpio::Pull;
|
use crate::gpio::Pull;
|
||||||
use crate::i2c::{Error, Instance, SclPin, SdaPin};
|
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac::i2c;
|
use crate::pac::i2c;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::{interrupt, Peripheral};
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Interrupt handler.
|
#[cfg(feature = "time")]
|
||||||
pub struct InterruptHandler<T: Instance> {
|
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
|
||||||
_phantom: PhantomData<T>,
|
let deadline = Instant::now() + timeout;
|
||||||
|
move || {
|
||||||
|
if Instant::now() > deadline {
|
||||||
|
Err(Error::Timeout)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
#[cfg(not(feature = "time"))]
|
||||||
unsafe fn on_interrupt() {
|
pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> {
|
||||||
let regs = T::regs();
|
move || Ok(())
|
||||||
let isr = regs.isr().read();
|
}
|
||||||
|
|
||||||
if isr.tcr() || isr.tc() {
|
pub unsafe fn on_interrupt<T: Instance>() {
|
||||||
T::state().waker.wake();
|
let regs = T::regs();
|
||||||
}
|
let isr = regs.isr().read();
|
||||||
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
|
|
||||||
// the interrupt
|
if isr.tcr() || isr.tc() {
|
||||||
critical_section::with(|_| {
|
T::state().waker.wake();
|
||||||
regs.cr1().modify(|w| w.set_tcie(false));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
|
||||||
|
// the interrupt
|
||||||
|
critical_section::with(|_| {
|
||||||
|
regs.cr1().modify(|w| w.set_tcie(false));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -65,18 +68,6 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State {
|
|
||||||
waker: AtomicWaker,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
pub(crate) const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
waker: AtomicWaker::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -92,7 +83,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
|
||||||
|
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
|
||||||
|
+ 'd,
|
||||||
tx_dma: impl Peripheral<P = TXDMA> + 'd,
|
tx_dma: impl Peripheral<P = TXDMA> + 'd,
|
||||||
rx_dma: impl Peripheral<P = RXDMA> + 'd,
|
rx_dma: impl Peripheral<P = RXDMA> + 'd,
|
||||||
freq: Hertz,
|
freq: Hertz,
|
||||||
@ -138,8 +131,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
reg.set_pe(true);
|
reg.set_pe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
T::Interrupt::unpend();
|
unsafe { T::EventInterrupt::enable() };
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::ErrorInterrupt::enable() };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_peri: peri,
|
_peri: peri,
|
||||||
@ -260,21 +253,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn flush_txdr(&self) {
|
fn flush_txdr(&self) {
|
||||||
//if $i2c.isr.read().txis().bit_is_set() {
|
|
||||||
//$i2c.txdr.write(|w| w.txdata().bits(0));
|
|
||||||
//}
|
|
||||||
|
|
||||||
if T::regs().isr().read().txis() {
|
if T::regs().isr().read().txis() {
|
||||||
T::regs().txdr().write(|w| w.set_txdata(0));
|
T::regs().txdr().write(|w| w.set_txdata(0));
|
||||||
}
|
}
|
||||||
if !T::regs().isr().read().txe() {
|
if !T::regs().isr().read().txe() {
|
||||||
T::regs().isr().modify(|w| w.set_txe(true))
|
T::regs().isr().modify(|w| w.set_txe(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If TXDR is not flagged as empty, write 1 to flush it
|
|
||||||
//if $i2c.isr.read().txe().is_not_empty() {
|
|
||||||
//$i2c.isr.write(|w| w.txe().set_bit());
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
|
||||||
@ -437,7 +421,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
async fn write_dma_internal(
|
async fn write_dma_internal(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
@ -528,7 +511,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
async fn read_dma_internal(
|
async fn read_dma_internal(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u8,
|
address: u8,
|
||||||
@ -610,42 +592,38 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// Async public API
|
// Async public API
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
||||||
where
|
|
||||||
TXDMA: crate::i2c::TxDma<T>,
|
|
||||||
{
|
|
||||||
self.write_timeout(address, write, self.timeout).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
TXDMA: crate::i2c::TxDma<T>,
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
{
|
{
|
||||||
if write.is_empty() {
|
if write.is_empty() {
|
||||||
self.write_internal(address, write, true, timeout_fn(timeout))
|
self.write_internal(address, write, true, timeout_fn(self.timeout))
|
||||||
} else {
|
} else {
|
||||||
embassy_time::with_timeout(
|
embassy_time::with_timeout(
|
||||||
timeout,
|
self.timeout,
|
||||||
self.write_dma_internal(address, write, true, true, timeout_fn(timeout)),
|
self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(Err(Error::Timeout))
|
.unwrap_or(Err(Error::Timeout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(not(feature = "time"))]
|
||||||
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
|
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
TXDMA: crate::i2c::TxDma<T>,
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
{
|
{
|
||||||
self.write_vectored_timeout(address, write, self.timeout).await
|
if write.is_empty() {
|
||||||
|
self.write_internal(address, write, true, no_timeout_fn())
|
||||||
|
} else {
|
||||||
|
self.write_dma_internal(address, write, true, true, no_timeout_fn())
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error>
|
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
TXDMA: crate::i2c::TxDma<T>,
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
{
|
{
|
||||||
@ -661,8 +639,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
let is_last = next.is_none();
|
let is_last = next.is_none();
|
||||||
|
|
||||||
embassy_time::with_timeout(
|
embassy_time::with_timeout(
|
||||||
timeout,
|
self.timeout,
|
||||||
self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)),
|
self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(Err(Error::Timeout))?;
|
.unwrap_or(Err(Error::Timeout))?;
|
||||||
@ -672,66 +650,79 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "time"))]
|
||||||
|
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
TXDMA: crate::i2c::TxDma<T>,
|
||||||
|
{
|
||||||
|
if write.is_empty() {
|
||||||
|
return Err(Error::ZeroLengthTransfer);
|
||||||
|
}
|
||||||
|
let mut iter = write.iter();
|
||||||
|
|
||||||
|
let mut first = true;
|
||||||
|
let mut current = iter.next();
|
||||||
|
while let Some(c) = current {
|
||||||
|
let next = iter.next();
|
||||||
|
let is_last = next.is_none();
|
||||||
|
|
||||||
|
self.write_dma_internal(address, c, first, is_last, no_timeout_fn())
|
||||||
|
.await?;
|
||||||
|
first = false;
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
RXDMA: crate::i2c::RxDma<T>,
|
RXDMA: crate::i2c::RxDma<T>,
|
||||||
{
|
{
|
||||||
self.read_timeout(address, buffer, self.timeout).await
|
if buffer.is_empty() {
|
||||||
|
self.read_internal(address, buffer, false, timeout_fn(self.timeout))
|
||||||
|
} else {
|
||||||
|
embassy_time::with_timeout(
|
||||||
|
self.timeout,
|
||||||
|
self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap_or(Err(Error::Timeout))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(not(feature = "time"))]
|
||||||
pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error>
|
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
RXDMA: crate::i2c::RxDma<T>,
|
RXDMA: crate::i2c::RxDma<T>,
|
||||||
{
|
{
|
||||||
if buffer.is_empty() {
|
if buffer.is_empty() {
|
||||||
self.read_internal(address, buffer, false, timeout_fn(timeout))
|
self.read_internal(address, buffer, false, no_timeout_fn())
|
||||||
} else {
|
} else {
|
||||||
embassy_time::with_timeout(
|
self.read_dma_internal(address, buffer, false, no_timeout_fn()).await
|
||||||
timeout,
|
|
||||||
self.read_dma_internal(address, buffer, false, timeout_fn(timeout)),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap_or(Err(Error::Timeout))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
|
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
|
||||||
where
|
|
||||||
TXDMA: super::TxDma<T>,
|
|
||||||
RXDMA: super::RxDma<T>,
|
|
||||||
{
|
|
||||||
self.write_read_timeout(address, write, read, self.timeout).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
pub async fn write_read_timeout(
|
|
||||||
&mut self,
|
|
||||||
address: u8,
|
|
||||||
write: &[u8],
|
|
||||||
read: &mut [u8],
|
|
||||||
timeout: Duration,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
TXDMA: super::TxDma<T>,
|
TXDMA: super::TxDma<T>,
|
||||||
RXDMA: super::RxDma<T>,
|
RXDMA: super::RxDma<T>,
|
||||||
{
|
{
|
||||||
let start_instant = Instant::now();
|
let start_instant = Instant::now();
|
||||||
let check_timeout = timeout_fn(timeout);
|
let check_timeout = timeout_fn(self.timeout);
|
||||||
if write.is_empty() {
|
if write.is_empty() {
|
||||||
self.write_internal(address, write, false, &check_timeout)?;
|
self.write_internal(address, write, false, &check_timeout)?;
|
||||||
} else {
|
} else {
|
||||||
embassy_time::with_timeout(
|
embassy_time::with_timeout(
|
||||||
timeout,
|
self.timeout,
|
||||||
self.write_dma_internal(address, write, true, true, &check_timeout),
|
self.write_dma_internal(address, write, true, true, &check_timeout),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(Err(Error::Timeout))?;
|
.unwrap_or(Err(Error::Timeout))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let time_left_until_timeout = timeout - Instant::now().duration_since(start_instant);
|
let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant);
|
||||||
|
|
||||||
if read.is_empty() {
|
if read.is_empty() {
|
||||||
self.read_internal(address, read, true, &check_timeout)?;
|
self.read_internal(address, read, true, &check_timeout)?;
|
||||||
@ -747,6 +738,28 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "time"))]
|
||||||
|
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
TXDMA: super::TxDma<T>,
|
||||||
|
RXDMA: super::RxDma<T>,
|
||||||
|
{
|
||||||
|
let no_timeout = no_timeout_fn();
|
||||||
|
if write.is_empty() {
|
||||||
|
self.write_internal(address, write, false, &no_timeout)?;
|
||||||
|
} else {
|
||||||
|
self.write_dma_internal(address, write, true, true, &no_timeout).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if read.is_empty() {
|
||||||
|
self.read_internal(address, read, true, &no_timeout)?;
|
||||||
|
} else {
|
||||||
|
self.read_dma_internal(address, read, true, &no_timeout).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// Blocking public API
|
// Blocking public API
|
||||||
|
|
||||||
@ -955,35 +968,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
mod eh02 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_read(address, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write(address, write)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write_read(address, write, read)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// I2C Stop Configuration
|
/// I2C Stop Configuration
|
||||||
///
|
///
|
||||||
/// Peripheral options for generating the STOP condition
|
/// Peripheral options for generating the STOP condition
|
||||||
@ -1108,83 +1092,6 @@ impl Timings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable-traits")]
|
|
||||||
mod eh1 {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl embedded_hal_1::i2c::Error for Error {
|
|
||||||
fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
|
|
||||||
match *self {
|
|
||||||
Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus,
|
|
||||||
Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
|
|
||||||
Self::Nack => {
|
|
||||||
embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown)
|
|
||||||
}
|
|
||||||
Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
Self::Crc => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun,
|
|
||||||
Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> {
|
|
||||||
type Error = Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> {
|
|
||||||
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_read(address, read)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write(address, write)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.blocking_write_read(address, write, read)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction(
|
|
||||||
&mut self,
|
|
||||||
_address: u8,
|
|
||||||
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))]
|
|
||||||
mod eha {
|
|
||||||
use super::super::{RxDma, TxDma};
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
|
|
||||||
async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.read(address, read).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.write(address, write).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
|
||||||
self.write_read(address, write, read).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn transaction(
|
|
||||||
&mut self,
|
|
||||||
address: u8,
|
|
||||||
operations: &mut [embedded_hal_1::i2c::Operation<'_>],
|
|
||||||
) -> Result<(), Self::Error> {
|
|
||||||
let _ = address;
|
|
||||||
let _ = operations;
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
||||||
type Config = Hertz;
|
type Config = Hertz;
|
||||||
type ConfigError = ();
|
type ConfigError = ();
|
||||||
@ -1201,15 +1108,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "time")]
|
|
||||||
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
|
|
||||||
let deadline = Instant::now() + timeout;
|
|
||||||
move || {
|
|
||||||
if Instant::now() > deadline {
|
|
||||||
Err(Error::Timeout)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -258,4 +258,4 @@ wasm-timer = { version = "0.2.5", optional = true }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "0.9"
|
serial_test = "0.9"
|
||||||
critical-section = { version = "1.1", features = ["std"] }
|
critical-section = { version = "1.1", features = ["std"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../embassy-executor", features = ["nightly"] }
|
embassy-executor = { version = "0.3.3", path = "../embassy-executor", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
|
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
|
||||||
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
|
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
|
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
|
||||||
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
|
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
|
||||||
|
@ -17,7 +17,7 @@ log = [
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time" }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ nightly = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
||||||
|
@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
|||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = [
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
] }
|
] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread",
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread",
|
||||||
"nightly",
|
"nightly",
|
||||||
"defmt",
|
"defmt",
|
||||||
"integrated-timers",
|
"integrated-timers",
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
|
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
|
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["log"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["log"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["log", "std", "nightly"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["log", "std", "nightly"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
|
||||||
embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
|
embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32c031c6 to your chip name, if necessary.
|
# Change stm32c031c6 to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -15,7 +15,7 @@ defmt = "0.3"
|
|||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
panic-probe = "0.3"
|
panic-probe = "0.3"
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
static_cell = { version = "2", features = ["nightly"]}
|
static_cell = { version = "2", features = ["nightly"]}
|
||||||
portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
|
portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32f103c8 to your chip name, if necessary.
|
# Change stm32f103c8 to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32f207zg to your chip name, if necessary.
|
# Change stm32f207zg to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32f303ze to your chip name, if necessary.
|
# Change stm32f303ze to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32f429zi to your chip name, if necessary.
|
# Change stm32f429zi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
|
||||||
|
@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32f767zi to your chip name, if necessary.
|
# Change stm32f767zi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||||
embedded-io-async = { version = "0.6.0" }
|
embedded-io-async = { version = "0.6.0" }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32g071rb to your chip name, if necessary.
|
# Change stm32g071rb to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32g491re to your chip name, if necessary.
|
# Change stm32g491re to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32h563zi to your chip name, if necessary.
|
# Change stm32h563zi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
|
||||||
embedded-io-async = { version = "0.6.0" }
|
embedded-io-async = { version = "0.6.0" }
|
||||||
|
@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32h743bi to your chip name, if necessary.
|
# Change stm32h743bi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
|
||||||
embedded-io-async = { version = "0.6.0" }
|
embedded-io-async = { version = "0.6.0" }
|
||||||
|
@ -19,7 +19,8 @@ const HEIGHT: usize = 100;
|
|||||||
static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2];
|
static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2];
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C1_EV => i2c::InterruptHandler<peripherals::I2C1>;
|
I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
|
||||||
|
I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
|
||||||
DCMI => dcmi::InterruptHandler<peripherals::DCMI>;
|
DCMI => dcmi::InterruptHandler<peripherals::DCMI>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -13,7 +13,7 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab
|
|||||||
# Change stm32l072cz to your chip name, if necessary.
|
# Change stm32l072cz to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
|
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
|
||||||
lora-phy = { version = "2", optional = true }
|
lora-phy = { version = "2", optional = true }
|
||||||
|
@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32l4s5vi to your chip name, if necessary.
|
# Change stm32l4s5vi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] }
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -16,7 +16,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F;
|
|||||||
const WHOAMI: u8 = 0x0F;
|
const WHOAMI: u8 = 0x0F;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
|
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>;
|
||||||
|
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
@ -40,7 +40,8 @@ use static_cell::make_static;
|
|||||||
use {embassy_stm32 as hal, panic_probe as _};
|
use {embassy_stm32 as hal, panic_probe as _};
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
I2C3_EV => i2c::InterruptHandler<peripherals::I2C3>;
|
I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>;
|
||||||
|
I2C3_ER => i2c::ErrorInterruptHandler<peripherals::I2C3>;
|
||||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32l552ze to your chip name, if necessary.
|
# Change stm32l552ze to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32u585ai to your chip name, if necessary.
|
# Change stm32u585ai to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
|
||||||
embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
|
embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true }
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
# Change stm32wl55jc-cm4 to your chip name, if necessary.
|
# Change stm32wl55jc-cm4 to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
||||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
|
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
|
||||||
|
@ -9,7 +9,7 @@ crate-type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["log"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["log"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
|
||||||
|
|
||||||
wasm-logger = "0.2.0"
|
wasm-logger = "0.2.0"
|
||||||
|
@ -9,10 +9,10 @@ teleprobe-meta = "1"
|
|||||||
|
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
|
||||||
embedded-io-async = { version = "0.6.0" }
|
embedded-io-async = { version = "0.6.0", features = ["defmt-03"] }
|
||||||
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
|
embassy-net = { version = "0.2.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
|
||||||
embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
|
embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
|
||||||
embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] }
|
embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] }
|
||||||
|
72
tests/nrf/src/bin/buffered_uart_full.rs
Normal file
72
tests/nrf/src/bin/buffered_uart_full.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
teleprobe_meta::target!(b"nrf52840-dk");
|
||||||
|
|
||||||
|
use defmt::{assert_eq, *};
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||||
|
use embedded_io_async::{Read, Write};
|
||||||
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let p = embassy_nrf::init(Default::default());
|
||||||
|
let mut config = uarte::Config::default();
|
||||||
|
config.parity = uarte::Parity::EXCLUDED;
|
||||||
|
config.baudrate = uarte::Baudrate::BAUD1M;
|
||||||
|
|
||||||
|
let mut tx_buffer = [0u8; 1024];
|
||||||
|
let mut rx_buffer = [0u8; 1024];
|
||||||
|
|
||||||
|
let mut u = BufferedUarte::new(
|
||||||
|
p.UARTE0,
|
||||||
|
p.TIMER0,
|
||||||
|
p.PPI_CH0,
|
||||||
|
p.PPI_CH1,
|
||||||
|
p.PPI_GROUP0,
|
||||||
|
Irqs,
|
||||||
|
p.P1_03,
|
||||||
|
p.P1_02,
|
||||||
|
config.clone(),
|
||||||
|
&mut rx_buffer,
|
||||||
|
&mut tx_buffer,
|
||||||
|
);
|
||||||
|
|
||||||
|
info!("uarte initialized!");
|
||||||
|
|
||||||
|
let (mut rx, mut tx) = u.split();
|
||||||
|
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
for (j, b) in buf.iter_mut().enumerate() {
|
||||||
|
*b = j as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write 1024b. This causes the rx buffer to get exactly full.
|
||||||
|
unwrap!(tx.write_all(&buf).await);
|
||||||
|
unwrap!(tx.flush().await);
|
||||||
|
|
||||||
|
// Read those 1024b.
|
||||||
|
unwrap!(rx.read_exact(&mut buf).await);
|
||||||
|
for (j, b) in buf.iter().enumerate() {
|
||||||
|
assert_eq!(*b, j as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The buffer should now be unclogged. Write 1024b again.
|
||||||
|
unwrap!(tx.write_all(&buf).await);
|
||||||
|
unwrap!(tx.flush().await);
|
||||||
|
|
||||||
|
// Read should work again.
|
||||||
|
unwrap!(rx.read_exact(&mut buf).await);
|
||||||
|
for (j, b) in buf.iter().enumerate() {
|
||||||
|
assert_eq!(*b, j as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
|
critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
teleprobe-meta = "1.1"
|
teleprobe-meta = "1.1"
|
||||||
|
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] }
|
||||||
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
|
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
@ -48,7 +48,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"]
|
|||||||
teleprobe-meta = "1"
|
teleprobe-meta = "1"
|
||||||
|
|
||||||
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.3.3", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
|
||||||
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
|
Reference in New Issue
Block a user