Skip to main content

m5stack_core/io/
shared_i2c.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
3use esp_hal::{Async, i2c::master::I2c};
4
5/// Shared I2C bus for cooperative tasks on APP core and init on PRO core.
6///
7/// # Safety
8/// `I2c<'static, Async>` is `!Send` due to `PhantomData<*const ()>`. The `unsafe impl
9/// Send/Sync` covers only that peripheral-type constraint; access is safe because:
10/// - AW9523B init runs on PRO core before APP core starts (no concurrent access)
11/// - PPS/AXP2101 tasks run cooperatively on APP core (never truly concurrent)
12/// `CriticalSectionRawMutex` is used for correctness: the mutex flag check is guarded
13/// against preemption from any context, at the cost of a brief global spinlock per
14/// lock/unlock. Safe because the CS is held only for the flag check, not across the
15/// I2C transaction (the lock guard is released at the next `.await`).
16pub struct SharedI2cBus(Mutex<CriticalSectionRawMutex, I2c<'static, Async>>);
17// Safety: see above.
18unsafe impl Send for SharedI2cBus {}
19unsafe impl Sync for SharedI2cBus {}
20
21impl SharedI2cBus {
22    pub const fn new(i2c: I2c<'static, Async>) -> Self {
23        Self(Mutex::new(i2c))
24    }
25
26    pub fn lock(
27        &self,
28    ) -> impl core::future::Future<
29        Output = embassy_sync::mutex::MutexGuard<'_, CriticalSectionRawMutex, I2c<'static, Async>>,
30    > {
31        self.0.lock()
32    }
33}