From 8399d96e24ead9415d4f35b940478dd4f3d54fcb Mon Sep 17 00:00:00 2001 From: anton smeenk Date: Fri, 10 Nov 2023 18:00:59 +0100 Subject: [PATCH] Removed global static channel_out and moved to interrupt state. TODO: make feature switch for slave specific stuff --- embassy-stm32/src/i2c/v2.rs | 5 ++- embassy-stm32/src/i2c/v2slave.rs | 35 +++++++-------- examples/stm32g0/Embed.toml | 43 ------------------- examples/stm32g0/src/bin/i2c_slave.rs | 3 +- .../stm32g0/src/bin/i2c_slave_arbitration.rs | 5 ++- 5 files changed, 24 insertions(+), 67 deletions(-) delete mode 100644 examples/stm32g0/Embed.toml diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 6c4e0a4c..54cdd1ca 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -10,13 +10,14 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; #[cfg(feature = "time")] use futures::task::Poll; -use super::v2slave::SlaveState; +use super::v2slave::{SlaveState, SlaveTransaction, SLAVE_QUEUE_DEPTH}; use crate::dma::NoDma; #[cfg(feature = "time")] use crate::dma::Transfer; @@ -106,6 +107,7 @@ impl Default for Config { pub struct State { pub(crate) waker: AtomicWaker, + pub(crate) channel_out: Channel, pub(crate) mutex: Mutex>, } @@ -113,6 +115,7 @@ impl State { pub(crate) const fn new() -> Self { Self { waker: AtomicWaker::new(), + channel_out: Channel::new(), mutex: Mutex::new(RefCell::new(SlaveState::new())), } } diff --git a/embassy-stm32/src/i2c/v2slave.rs b/embassy-stm32/src/i2c/v2slave.rs index be40ff91..dea392d8 100644 --- a/embassy-stm32/src/i2c/v2slave.rs +++ b/embassy-stm32/src/i2c/v2slave.rs @@ -1,17 +1,15 @@ use core::result::Result; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::channel::Channel; +use embassy_sync::channel::{Channel, Receiver}; use stm32_metapac::i2c; use super::{AddressIndex, I2c, Instance}; use crate::i2c::{Dir, Error}; -// Declare a CHANNEL for all other tasks to communicate with this driver -static CHANNEL_OUT: Channel = Channel::new(); pub type I2cBuffer = [u8; SLAVE_BUFFER_SIZE]; pub const SLAVE_BUFFER_SIZE: usize = 64; -const SLAVE_QUEUE_DEPTH: usize = 5; +pub const SLAVE_QUEUE_DEPTH: usize = 5; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[repr(usize)] @@ -324,6 +322,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) }) } + pub fn slave_prepare_write(&self) -> Result<(), Error> { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.prepare_write(); + Ok(()) + }) + } pub fn slave_reset(&self) { T::state().mutex.lock(|f| { @@ -338,23 +343,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { state_m.error_count_reset() }) } - pub fn slave_prepare_write(&self) { - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - state_m.prepare_write(); - }); - } - /// wait until a slave transaction is finished, and return tuple address, direction, data size and error - pub async fn slave_transaction(&self) -> SlaveTransaction { - let result = CHANNEL_OUT.receive().await; - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - state_m.prepare_write(); - }); - result + /// Get a copy of the receiver for the channel_out. User code can await on this receiver + pub fn slave_transaction_receiver( + &self, + ) -> Receiver<'static, CriticalSectionRawMutex, SlaveTransaction, SLAVE_QUEUE_DEPTH> { + T::state().channel_out.receiver() } - pub(crate) fn slave_interupt_handler(state_m: &mut SlaveState, regs: &i2c::I2c) { // ============================================ slave interrupt state_m machine let isr = regs.isr().read(); @@ -402,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let transaction = state_m.take_transaction(); match transaction { Some(t) => { - if let Err(_) = CHANNEL_OUT.try_send(t) { + if let Err(_) = T::state().channel_out.try_send(t) { state_m.error_count += 1; } } diff --git a/examples/stm32g0/Embed.toml b/examples/stm32g0/Embed.toml deleted file mode 100644 index 84775124..00000000 --- a/examples/stm32g0/Embed.toml +++ /dev/null @@ -1,43 +0,0 @@ -[default.probe] -protocol = "Swd" -# USB vendor ID -# usb_vid = "6790" -# USB product ID -# usb_pid = "29987" - -[default.flashing] -enabled = true - -[default.reset] -# Whether or not the target should be reset. -# When flashing is enabled as well, the target will be reset after flashing. -enabled = true -# Whether or not the target should be halted after reset. -halt_afterwards = false - -[default.general] -# The chip name of the chip to be debugged. -#chip = "STM32G030J6Mx" -chip = "STM32G070CBTx" -# A list of chip descriptions to be loaded during runtime. -chip_descriptions = [] -# The default log level to be used. -log_level = "Warn" - -[default.rtt] -enabled = false -# A list of channel associations to be displayed. If left empty, all channels are displayed. -channels = [ - # { up = 0, down = 0, name = "name" } -] -# The duration in ms for which the logger should retry to attach to RTT. -timeout = 3000 -# Whether timestamps in the RTTUI are enabled -show_timestamps = true - -[default.gdb] -# Whether or not a GDB server should be opened after flashing. -# This is exclusive and cannot be used with RTT at the moment. -enabled = false -# The connection string in host:port format wher the GDB server will open a socket. -# gdb_connection_string \ No newline at end of file diff --git a/examples/stm32g0/src/bin/i2c_slave.rs b/examples/stm32g0/src/bin/i2c_slave.rs index 538622dc..03d76078 100644 --- a/examples/stm32g0/src/bin/i2c_slave.rs +++ b/examples/stm32g0/src/bin/i2c_slave.rs @@ -123,6 +123,7 @@ async fn main(spawner: Spawner) { // start of the actual test i2c.slave_start_listen().unwrap(); + let receiver = i2c.slave_transaction_receiver(); loop { counter += 1; writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); @@ -143,7 +144,7 @@ async fn main(spawner: Spawner) { writeln!(&mut writer, "Waiting for master activity\r").unwrap(); - let t = i2c.slave_transaction().await; + let t = receiver.receive().await; let dir = t.dir(); tcount += 1; // preparations for the next round diff --git a/examples/stm32g0/src/bin/i2c_slave_arbitration.rs b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs index 2fa526f9..76a1dbd1 100644 --- a/examples/stm32g0/src/bin/i2c_slave_arbitration.rs +++ b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs @@ -10,7 +10,7 @@ use core::fmt::{self, Write}; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; // use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::i2c::{I2c, AddressIndex}; +use embassy_stm32::i2c::{AddressIndex, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::usart::UartTx; use embassy_stm32::{bind_interrupts, i2c, peripherals, usart}; @@ -83,6 +83,7 @@ async fn main(_spawner: Spawner) { // start of the actual test i2c.slave_start_listen().unwrap(); + let receiver = i2c.slave_transaction_receiver(); loop { counter += 1; writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); @@ -94,7 +95,7 @@ async fn main(_spawner: Spawner) { writeln!(&mut writer, "Waiting for master activity\r").unwrap(); - let t = i2c.slave_transaction().await; + let t = receiver.receive().await; writeln!( &mut writer, "Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r",