From 8c733c29cc2f48385acc537e7057af7d29174f8c Mon Sep 17 00:00:00 2001 From: OueslatiGhaith Date: Thu, 27 Apr 2023 16:03:22 +0100 Subject: add IPCC peripheral for stm32wb --- embassy-stm32/src/ipcc.rs | 186 ++++++++++++++++++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + 2 files changed, 188 insertions(+) create mode 100644 embassy-stm32/src/ipcc.rs (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs new file mode 100644 index 000000000..e5ec58ada --- /dev/null +++ b/embassy-stm32/src/ipcc.rs @@ -0,0 +1,186 @@ +use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; + +use crate::peripherals::IPCC; + +#[non_exhaustive] +#[derive(Clone, Copy, Default)] +pub struct Config { + // TODO: add IPCC peripheral configuration, if any, here + // reserved for future use +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub enum IpccChannel { + Channel1 = 0, + Channel2 = 1, + Channel3 = 2, + Channel4 = 3, + Channel5 = 4, + Channel6 = 5, +} + +pub(crate) mod sealed { + pub trait Instance: crate::rcc::RccPeripheral { + fn regs() -> crate::pac::ipcc::Ipcc; + fn set_cpu2(enabled: bool); + } +} + +pub struct Ipcc<'d> { + _peri: PeripheralRef<'d, IPCC>, +} + +impl<'d> Ipcc<'d> { + pub fn new(peri: impl Peripheral

+ 'd, _config: Config) -> Self { + into_ref!(peri); + + Self { _peri: peri } + } + + pub fn init(&mut self) { + IPCC::enable(); + IPCC::reset(); + IPCC::set_cpu2(true); + + unsafe { _configure_pwr() }; + + let regs = IPCC::regs(); + + unsafe { + regs.cpu(0).cr().modify(|w| { + w.set_rxoie(true); + w.set_txfie(true); + }) + } + } + + pub fn c1_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel.into(), !enabled)) } + } + + pub fn c1_get_rx_channel(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { !regs.cpu(0).mr().read().chom(channel.into()) } + } + + pub fn c2_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel.into(), !enabled)) } + } + + pub fn c2_get_rx_channel(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { !regs.cpu(1).mr().read().chom(channel.into()) } + } + + pub fn c1_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel.into(), !enabled)) } + } + + pub fn c1_get_tx_channel(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { !regs.cpu(0).mr().read().chfm(channel.into()) } + } + + pub fn c2_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel.into(), !enabled)) } + } + + pub fn c2_get_tx_channel(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + // If bit is set to 1 then interrupt is disabled + unsafe { !regs.cpu(1).mr().read().chfm(channel.into()) } + } + + /// clears IPCC receive channel status for CPU1 + pub fn c1_clear_flag_channel(&mut self, channel: IpccChannel) { + let regs = IPCC::regs(); + + unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel.into(), true)) } + } + + /// clears IPCC receive channel status for CPU2 + pub fn c2_clear_flag_channel(&mut self, channel: IpccChannel) { + let regs = IPCC::regs(); + + unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel.into(), true)) } + } + + pub fn c1_set_flag_channel(&mut self, channel: IpccChannel) { + let regs = IPCC::regs(); + + unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel.into(), true)) } + } + + pub fn c2_set_flag_channel(&mut self, channel: IpccChannel) { + let regs = IPCC::regs(); + + unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel.into(), true)) } + } + + pub fn c1_is_active_flag(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + unsafe { regs.cpu(0).sr().read().chf(channel.into()) } + } + + pub fn c2_is_active_flag(&self, channel: IpccChannel) -> bool { + let regs = IPCC::regs(); + + unsafe { regs.cpu(1).sr().read().chf(channel.into()) } + } + + pub fn is_tx_pending(&self, channel: IpccChannel) -> bool { + !self.c1_is_active_flag(channel) && self.c1_get_tx_channel(channel) + } + + pub fn is_rx_pending(&self, channel: IpccChannel) -> bool { + self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel) + } +} + +impl sealed::Instance for crate::peripherals::IPCC { + fn regs() -> crate::pac::ipcc::Ipcc { + crate::pac::IPCC + } + + fn set_cpu2(enabled: bool) { + unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) } + } +} + +/// extension trait that constrains the [`Ipcc`] peripheral +pub trait IpccExt<'d> { + fn constrain(self) -> Ipcc<'d>; +} +impl<'d> IpccExt<'d> for IPCC { + fn constrain(self) -> Ipcc<'d> { + Ipcc { _peri: self.into_ref() } + } +} + +unsafe fn _configure_pwr() { + let rcc = crate::pac::RCC; + + // set RF wake-up clock = LSE + rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index f0fc152ce..2f7892db2 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -44,6 +44,8 @@ pub mod i2c; #[cfg(crc)] pub mod crc; pub mod flash; +#[cfg(stm32wb)] +pub mod ipcc; pub mod pwm; #[cfg(quadspi)] pub mod qspi; -- cgit From 3ba73b5ff45084e8d9a662220981f7d503aba251 Mon Sep 17 00:00:00 2001 From: OueslatiGhaith Date: Thu, 27 Apr 2023 16:08:57 +0100 Subject: fixed mistake with casting channel to a usize --- embassy-stm32/src/ipcc.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index e5ec58ada..43105c1d1 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -59,94 +59,94 @@ impl<'d> Ipcc<'d> { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel.into(), !enabled)) } + unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } } pub fn c1_get_rx_channel(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { !regs.cpu(0).mr().read().chom(channel.into()) } + unsafe { !regs.cpu(0).mr().read().chom(channel as usize) } } pub fn c2_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel.into(), !enabled)) } + unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } } pub fn c2_get_rx_channel(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { !regs.cpu(1).mr().read().chom(channel.into()) } + unsafe { !regs.cpu(1).mr().read().chom(channel as usize) } } pub fn c1_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel.into(), !enabled)) } + unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } } pub fn c1_get_tx_channel(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { !regs.cpu(0).mr().read().chfm(channel.into()) } + unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) } } pub fn c2_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel.into(), !enabled)) } + unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } } pub fn c2_get_tx_channel(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); // If bit is set to 1 then interrupt is disabled - unsafe { !regs.cpu(1).mr().read().chfm(channel.into()) } + unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) } } /// clears IPCC receive channel status for CPU1 pub fn c1_clear_flag_channel(&mut self, channel: IpccChannel) { let regs = IPCC::regs(); - unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel.into(), true)) } + unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) } } /// clears IPCC receive channel status for CPU2 pub fn c2_clear_flag_channel(&mut self, channel: IpccChannel) { let regs = IPCC::regs(); - unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel.into(), true)) } + unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) } } pub fn c1_set_flag_channel(&mut self, channel: IpccChannel) { let regs = IPCC::regs(); - unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel.into(), true)) } + unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } } pub fn c2_set_flag_channel(&mut self, channel: IpccChannel) { let regs = IPCC::regs(); - unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel.into(), true)) } + unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) } } pub fn c1_is_active_flag(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); - unsafe { regs.cpu(0).sr().read().chf(channel.into()) } + unsafe { regs.cpu(0).sr().read().chf(channel as usize) } } pub fn c2_is_active_flag(&self, channel: IpccChannel) -> bool { let regs = IPCC::regs(); - unsafe { regs.cpu(1).sr().read().chf(channel.into()) } + unsafe { regs.cpu(1).sr().read().chf(channel as usize) } } pub fn is_tx_pending(&self, channel: IpccChannel) -> bool { -- cgit From d960bf344ad58b2ce8132d27c1130a69bfd725b1 Mon Sep 17 00:00:00 2001 From: OueslatiGhaith Date: Thu, 27 Apr 2023 16:22:41 +0100 Subject: fixed missing imports --- embassy-stm32/src/ipcc.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 43105c1d1..a54cf8faf 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -1,6 +1,8 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; +use crate::ipcc::sealed::Instance; use crate::peripherals::IPCC; +use crate::rcc::sealed::RccPeripheral; #[non_exhaustive] #[derive(Clone, Copy, Default)] -- cgit From 29cc661dca449e404fa37ba4d8aff3580eb6fe78 Mon Sep 17 00:00:00 2001 From: OueslatiGhaith Date: Fri, 28 Apr 2023 10:17:01 +0100 Subject: removed constrain method --- embassy-stm32/src/ipcc.rs | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index a54cf8faf..903aeca30 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -170,16 +170,6 @@ impl sealed::Instance for crate::peripherals::IPCC { } } -/// extension trait that constrains the [`Ipcc`] peripheral -pub trait IpccExt<'d> { - fn constrain(self) -> Ipcc<'d>; -} -impl<'d> IpccExt<'d> for IPCC { - fn constrain(self) -> Ipcc<'d> { - Ipcc { _peri: self.into_ref() } - } -} - unsafe fn _configure_pwr() { let rcc = crate::pac::RCC; -- cgit From b77794c9a70d35ea027454a678ac24e215a62c13 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Apr 2023 21:43:03 -0500 Subject: stm32/uart: abort on error --- embassy-stm32/src/usart/mod.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'embassy-stm32/src') diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index b8656b586..266561659 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -497,28 +497,24 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { unreachable!(); } - if !enable_idle_line_detection { - transfer.await; + if enable_idle_line_detection { + // clear idle flag + let sr = sr(r).read(); + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile(); + clear_interrupt_flags(r, sr); - return Ok(ReadCompletionEvent::DmaCompleted); + // enable idle interrupt + r.cr1().modify(|w| { + w.set_idleie(true); + }); } - - // clear idle flag - let sr = sr(r).read(); - // This read also clears the error and idle interrupt flags on v1. - rdr(r).read_volatile(); - clear_interrupt_flags(r, sr); - - // enable idle interrupt - r.cr1().modify(|w| { - w.set_idleie(true); - }); } compiler_fence(Ordering::SeqCst); - // future which completes when idle line is detected - let idle = poll_fn(move |cx| { + // future which completes when idle line or error is detected + let abort = poll_fn(move |cx| { let s = T::state(); s.rx_waker.register(cx.waker()); @@ -554,7 +550,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } - if sr.idle() { + if enable_idle_line_detection && sr.idle() { // Idle line detected return Poll::Ready(Ok(())); } @@ -565,7 +561,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { // wait for the first of DMA request or idle line detected to completes // select consumes its arguments // when transfer is dropped, it will stop the DMA request - let r = match select(transfer, idle).await { + let r = match select(transfer, abort).await { // DMA transfer completed first Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted), -- cgit