aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/i2c.rs22
-rw-r--r--embassy-stm32/src/ipcc.rs178
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/usart/mod.rs32
4 files changed, 216 insertions, 18 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 40e85c66f..cd5364393 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -617,6 +617,28 @@ mod eh02 {
617 self.blocking_write_read(address, bytes, buffer) 617 self.blocking_write_read(address, bytes, buffer)
618 } 618 }
619 } 619 }
620
621 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, T, M> {
622 type Error = Error;
623
624 fn exec(
625 &mut self,
626 address: u8,
627 operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>],
628 ) -> Result<(), Self::Error> {
629 Self::setup(address.into())?;
630 for i in 0..operations.len() {
631 let last = i == operations.len() - 1;
632 match &mut operations[i] {
633 embedded_hal_02::blocking::i2c::Operation::Read(buf) => {
634 self.read_blocking_internal(buf, false, last)?
635 }
636 embedded_hal_02::blocking::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
637 }
638 }
639 Ok(())
640 }
641 }
620} 642}
621 643
622#[cfg(feature = "unstable-traits")] 644#[cfg(feature = "unstable-traits")]
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
new file mode 100644
index 000000000..903aeca30
--- /dev/null
+++ b/embassy-stm32/src/ipcc.rs
@@ -0,0 +1,178 @@
1use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
2
3use crate::ipcc::sealed::Instance;
4use crate::peripherals::IPCC;
5use crate::rcc::sealed::RccPeripheral;
6
7#[non_exhaustive]
8#[derive(Clone, Copy, Default)]
9pub struct Config {
10 // TODO: add IPCC peripheral configuration, if any, here
11 // reserved for future use
12}
13
14#[derive(Debug, Clone, Copy)]
15#[repr(C)]
16pub enum IpccChannel {
17 Channel1 = 0,
18 Channel2 = 1,
19 Channel3 = 2,
20 Channel4 = 3,
21 Channel5 = 4,
22 Channel6 = 5,
23}
24
25pub(crate) mod sealed {
26 pub trait Instance: crate::rcc::RccPeripheral {
27 fn regs() -> crate::pac::ipcc::Ipcc;
28 fn set_cpu2(enabled: bool);
29 }
30}
31
32pub struct Ipcc<'d> {
33 _peri: PeripheralRef<'d, IPCC>,
34}
35
36impl<'d> Ipcc<'d> {
37 pub fn new(peri: impl Peripheral<P = IPCC> + 'd, _config: Config) -> Self {
38 into_ref!(peri);
39
40 Self { _peri: peri }
41 }
42
43 pub fn init(&mut self) {
44 IPCC::enable();
45 IPCC::reset();
46 IPCC::set_cpu2(true);
47
48 unsafe { _configure_pwr() };
49
50 let regs = IPCC::regs();
51
52 unsafe {
53 regs.cpu(0).cr().modify(|w| {
54 w.set_rxoie(true);
55 w.set_txfie(true);
56 })
57 }
58 }
59
60 pub fn c1_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) {
61 let regs = IPCC::regs();
62
63 // If bit is set to 1 then interrupt is disabled
64 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
65 }
66
67 pub fn c1_get_rx_channel(&self, channel: IpccChannel) -> bool {
68 let regs = IPCC::regs();
69
70 // If bit is set to 1 then interrupt is disabled
71 unsafe { !regs.cpu(0).mr().read().chom(channel as usize) }
72 }
73
74 pub fn c2_set_rx_channel(&mut self, channel: IpccChannel, enabled: bool) {
75 let regs = IPCC::regs();
76
77 // If bit is set to 1 then interrupt is disabled
78 unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
79 }
80
81 pub fn c2_get_rx_channel(&self, channel: IpccChannel) -> bool {
82 let regs = IPCC::regs();
83
84 // If bit is set to 1 then interrupt is disabled
85 unsafe { !regs.cpu(1).mr().read().chom(channel as usize) }
86 }
87
88 pub fn c1_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) {
89 let regs = IPCC::regs();
90
91 // If bit is set to 1 then interrupt is disabled
92 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
93 }
94
95 pub fn c1_get_tx_channel(&self, channel: IpccChannel) -> bool {
96 let regs = IPCC::regs();
97
98 // If bit is set to 1 then interrupt is disabled
99 unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
100 }
101
102 pub fn c2_set_tx_channel(&mut self, channel: IpccChannel, enabled: bool) {
103 let regs = IPCC::regs();
104
105 // If bit is set to 1 then interrupt is disabled
106 unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
107 }
108
109 pub fn c2_get_tx_channel(&self, channel: IpccChannel) -> bool {
110 let regs = IPCC::regs();
111
112 // If bit is set to 1 then interrupt is disabled
113 unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) }
114 }
115
116 /// clears IPCC receive channel status for CPU1
117 pub fn c1_clear_flag_channel(&mut self, channel: IpccChannel) {
118 let regs = IPCC::regs();
119
120 unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
121 }
122
123 /// clears IPCC receive channel status for CPU2
124 pub fn c2_clear_flag_channel(&mut self, channel: IpccChannel) {
125 let regs = IPCC::regs();
126
127 unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) }
128 }
129
130 pub fn c1_set_flag_channel(&mut self, channel: IpccChannel) {
131 let regs = IPCC::regs();
132
133 unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
134 }
135
136 pub fn c2_set_flag_channel(&mut self, channel: IpccChannel) {
137 let regs = IPCC::regs();
138
139 unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) }
140 }
141
142 pub fn c1_is_active_flag(&self, channel: IpccChannel) -> bool {
143 let regs = IPCC::regs();
144
145 unsafe { regs.cpu(0).sr().read().chf(channel as usize) }
146 }
147
148 pub fn c2_is_active_flag(&self, channel: IpccChannel) -> bool {
149 let regs = IPCC::regs();
150
151 unsafe { regs.cpu(1).sr().read().chf(channel as usize) }
152 }
153
154 pub fn is_tx_pending(&self, channel: IpccChannel) -> bool {
155 !self.c1_is_active_flag(channel) && self.c1_get_tx_channel(channel)
156 }
157
158 pub fn is_rx_pending(&self, channel: IpccChannel) -> bool {
159 self.c2_is_active_flag(channel) && self.c1_get_rx_channel(channel)
160 }
161}
162
163impl sealed::Instance for crate::peripherals::IPCC {
164 fn regs() -> crate::pac::ipcc::Ipcc {
165 crate::pac::IPCC
166 }
167
168 fn set_cpu2(enabled: bool) {
169 unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
170 }
171}
172
173unsafe fn _configure_pwr() {
174 let rcc = crate::pac::RCC;
175
176 // set RF wake-up clock = LSE
177 rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
178}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 24a26eddd..599041302 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -44,6 +44,8 @@ pub mod i2c;
44#[cfg(crc)] 44#[cfg(crc)]
45pub mod crc; 45pub mod crc;
46pub mod flash; 46pub mod flash;
47#[cfg(stm32wb)]
48pub mod ipcc;
47pub mod pwm; 49pub mod pwm;
48#[cfg(quadspi)] 50#[cfg(quadspi)]
49pub mod qspi; 51pub mod qspi;
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> {
497 unreachable!(); 497 unreachable!();
498 } 498 }
499 499
500 if !enable_idle_line_detection { 500 if enable_idle_line_detection {
501 transfer.await; 501 // clear idle flag
502 let sr = sr(r).read();
503 // This read also clears the error and idle interrupt flags on v1.
504 rdr(r).read_volatile();
505 clear_interrupt_flags(r, sr);
502 506
503 return Ok(ReadCompletionEvent::DmaCompleted); 507 // enable idle interrupt
508 r.cr1().modify(|w| {
509 w.set_idleie(true);
510 });
504 } 511 }
505
506 // clear idle flag
507 let sr = sr(r).read();
508 // This read also clears the error and idle interrupt flags on v1.
509 rdr(r).read_volatile();
510 clear_interrupt_flags(r, sr);
511
512 // enable idle interrupt
513 r.cr1().modify(|w| {
514 w.set_idleie(true);
515 });
516 } 512 }
517 513
518 compiler_fence(Ordering::SeqCst); 514 compiler_fence(Ordering::SeqCst);
519 515
520 // future which completes when idle line is detected 516 // future which completes when idle line or error is detected
521 let idle = poll_fn(move |cx| { 517 let abort = poll_fn(move |cx| {
522 let s = T::state(); 518 let s = T::state();
523 519
524 s.rx_waker.register(cx.waker()); 520 s.rx_waker.register(cx.waker());
@@ -554,7 +550,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
554 } 550 }
555 } 551 }
556 552
557 if sr.idle() { 553 if enable_idle_line_detection && sr.idle() {
558 // Idle line detected 554 // Idle line detected
559 return Poll::Ready(Ok(())); 555 return Poll::Ready(Ok(()));
560 } 556 }
@@ -565,7 +561,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
565 // wait for the first of DMA request or idle line detected to completes 561 // wait for the first of DMA request or idle line detected to completes
566 // select consumes its arguments 562 // select consumes its arguments
567 // when transfer is dropped, it will stop the DMA request 563 // when transfer is dropped, it will stop the DMA request
568 let r = match select(transfer, idle).await { 564 let r = match select(transfer, abort).await {
569 // DMA transfer completed first 565 // DMA transfer completed first
570 Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted), 566 Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted),
571 567