Merge branch 'embassy-rs:master' into master
This commit is contained in:
		| @@ -617,6 +617,28 @@ mod eh02 { | |||||||
|             self.blocking_write_read(address, bytes, buffer) |             self.blocking_write_read(address, bytes, buffer) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, T, M> { | ||||||
|  |         type Error = Error; | ||||||
|  |  | ||||||
|  |         fn exec( | ||||||
|  |             &mut self, | ||||||
|  |             address: u8, | ||||||
|  |             operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>], | ||||||
|  |         ) -> Result<(), Self::Error> { | ||||||
|  |             Self::setup(address.into())?; | ||||||
|  |             for i in 0..operations.len() { | ||||||
|  |                 let last = i == operations.len() - 1; | ||||||
|  |                 match &mut operations[i] { | ||||||
|  |                     embedded_hal_02::blocking::i2c::Operation::Read(buf) => { | ||||||
|  |                         self.read_blocking_internal(buf, false, last)? | ||||||
|  |                     } | ||||||
|  |                     embedded_hal_02::blocking::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Ok(()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(feature = "unstable-traits")] | #[cfg(feature = "unstable-traits")] | ||||||
|   | |||||||
							
								
								
									
										178
									
								
								embassy-stm32/src/ipcc.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								embassy-stm32/src/ipcc.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | |||||||
|  | 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)] | ||||||
|  | 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<P = IPCC> + '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 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 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 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 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 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 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 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 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 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 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 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 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 as usize) } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn c2_is_active_flag(&self, channel: IpccChannel) -> bool { | ||||||
|  |         let regs = IPCC::regs(); | ||||||
|  |  | ||||||
|  |         unsafe { regs.cpu(1).sr().read().chf(channel as usize) } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     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)) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | unsafe fn _configure_pwr() { | ||||||
|  |     let rcc = crate::pac::RCC; | ||||||
|  |  | ||||||
|  |     // set RF wake-up clock = LSE | ||||||
|  |     rcc.csr().modify(|w| w.set_rfwkpsel(0b01)); | ||||||
|  | } | ||||||
| @@ -44,6 +44,8 @@ pub mod i2c; | |||||||
| #[cfg(crc)] | #[cfg(crc)] | ||||||
| pub mod crc; | pub mod crc; | ||||||
| pub mod flash; | pub mod flash; | ||||||
|  | #[cfg(stm32wb)] | ||||||
|  | pub mod ipcc; | ||||||
| pub mod pwm; | pub mod pwm; | ||||||
| #[cfg(quadspi)] | #[cfg(quadspi)] | ||||||
| pub mod qspi; | pub mod qspi; | ||||||
|   | |||||||
| @@ -497,28 +497,24 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||||||
|                 unreachable!(); |                 unreachable!(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if !enable_idle_line_detection { |             if enable_idle_line_detection { | ||||||
|                 transfer.await; |                 // 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); |         compiler_fence(Ordering::SeqCst); | ||||||
|  |  | ||||||
|         // future which completes when idle line is detected |         // future which completes when idle line or error is detected | ||||||
|         let idle = poll_fn(move |cx| { |         let abort = poll_fn(move |cx| { | ||||||
|             let s = T::state(); |             let s = T::state(); | ||||||
|  |  | ||||||
|             s.rx_waker.register(cx.waker()); |             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 |                 // Idle line detected | ||||||
|                 return Poll::Ready(Ok(())); |                 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 |         // wait for the first of DMA request or idle line detected to completes | ||||||
|         // select consumes its arguments |         // select consumes its arguments | ||||||
|         // when transfer is dropped, it will stop the DMA request |         // 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 |             // DMA transfer completed first | ||||||
|             Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted), |             Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted), | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user