aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/ipcc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/ipcc.rs')
-rw-r--r--embassy-stm32/src/ipcc.rs250
1 files changed, 153 insertions, 97 deletions
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index e1d8b1c2a..10c4a820b 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,9 +1,11 @@
1//! Inter-Process Communication Controller (IPCC) 1//! Inter-Process Communication Controller (IPCC)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::marker::PhantomData;
4use core::sync::atomic::{Ordering, compiler_fence}; 5use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 6use core::task::Poll;
6 7
8use embassy_hal_internal::Peri;
7use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
8 10
9use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
@@ -17,25 +19,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
17 unsafe fn on_interrupt() { 19 unsafe fn on_interrupt() {
18 let regs = IPCC::regs(); 20 let regs = IPCC::regs();
19 21
20 let channels = [
21 IpccChannel::Channel1,
22 IpccChannel::Channel2,
23 IpccChannel::Channel3,
24 IpccChannel::Channel4,
25 IpccChannel::Channel5,
26 IpccChannel::Channel6,
27 ];
28
29 // Status register gives channel occupied status. For rx, use cpu1. 22 // Status register gives channel occupied status. For rx, use cpu1.
30 let sr = regs.cpu(1).sr().read(); 23 let sr = regs.cpu(1).sr().read();
31 regs.cpu(0).mr().modify(|w| { 24 regs.cpu(0).mr().modify(|w| {
32 for channel in channels { 25 for index in 0..5 {
33 if sr.chf(channel as usize) { 26 if sr.chf(index as usize) {
34 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 27 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
35 w.set_chom(channel as usize, true); 28 w.set_chom(index as usize, true);
36 29
37 // There shouldn't be a race because the channel is masked only if the interrupt has fired 30 // There shouldn't be a race because the channel is masked only if the interrupt has fired
38 IPCC::state().rx_waker_for(channel).wake(); 31 IPCC::state().rx_waker_for(index).wake();
39 } 32 }
40 } 33 }
41 }) 34 })
@@ -49,25 +42,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
49 unsafe fn on_interrupt() { 42 unsafe fn on_interrupt() {
50 let regs = IPCC::regs(); 43 let regs = IPCC::regs();
51 44
52 let channels = [
53 IpccChannel::Channel1,
54 IpccChannel::Channel2,
55 IpccChannel::Channel3,
56 IpccChannel::Channel4,
57 IpccChannel::Channel5,
58 IpccChannel::Channel6,
59 ];
60
61 // Status register gives channel occupied status. For tx, use cpu0. 45 // Status register gives channel occupied status. For tx, use cpu0.
62 let sr = regs.cpu(0).sr().read(); 46 let sr = regs.cpu(0).sr().read();
63 regs.cpu(0).mr().modify(|w| { 47 regs.cpu(0).mr().modify(|w| {
64 for channel in channels { 48 for index in 0..5 {
65 if !sr.chf(channel as usize) { 49 if !sr.chf(index as usize) {
66 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 50 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
67 w.set_chfm(channel as usize, true); 51 w.set_chfm(index as usize, true);
68 52
69 // There shouldn't be a race because the channel is masked only if the interrupt has fired 53 // There shouldn't be a race because the channel is masked only if the interrupt has fired
70 IPCC::state().tx_waker_for(channel).wake(); 54 IPCC::state().tx_waker_for(index).wake();
71 } 55 }
72 } 56 }
73 }); 57 });
@@ -82,76 +66,55 @@ pub struct Config {
82 // reserved for future use 66 // reserved for future use
83} 67}
84 68
85/// Channel. 69/// IPCC TX Channel
86#[allow(missing_docs)] 70pub struct IpccTxChannel<'a> {
87#[derive(Debug, Clone, Copy)] 71 index: u8,
88#[repr(C)] 72 _lifetime: PhantomData<&'a mut usize>,
89pub enum IpccChannel {
90 Channel1 = 0,
91 Channel2 = 1,
92 Channel3 = 2,
93 Channel4 = 3,
94 Channel5 = 4,
95 Channel6 = 5,
96} 73}
97 74
98/// IPCC driver. 75impl<'a> IpccTxChannel<'a> {
99pub struct Ipcc; 76 pub(crate) const fn new(index: u8) -> Self {
100 77 core::assert!(index < 6);
101impl Ipcc {
102 /// Enable IPCC.
103 pub fn enable(_config: Config) {
104 rcc::enable_and_reset::<IPCC>();
105 IPCC::set_cpu2(true);
106
107 let regs = IPCC::regs();
108
109 regs.cpu(0).cr().modify(|w| {
110 w.set_rxoie(true);
111 w.set_txfie(true);
112 });
113
114 // enable interrupts
115 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
116 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
117 78
118 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() }; 79 Self {
119 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() }; 80 index: index,
81 _lifetime: PhantomData,
82 }
120 } 83 }
121 84
122 /// Send data to an IPCC channel. The closure is called to write the data when appropriate. 85 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
123 pub async fn send(channel: IpccChannel, f: impl FnOnce()) { 86 pub async fn send(&mut self, f: impl FnOnce()) {
124 let regs = IPCC::regs(); 87 let regs = IPCC::regs();
125 88
126 Self::flush(channel).await; 89 self.flush().await;
127 90
128 f(); 91 f();
129 92
130 compiler_fence(Ordering::SeqCst); 93 compiler_fence(Ordering::SeqCst);
131 94
132 trace!("ipcc: ch {}: send data", channel as u8); 95 trace!("ipcc: ch {}: send data", self.index as u8);
133 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); 96 regs.cpu(0).scr().write(|w| w.set_chs(self.index as usize, true));
134 } 97 }
135 98
136 /// Wait for the tx channel to become clear 99 /// Wait for the tx channel to become clear
137 pub async fn flush(channel: IpccChannel) { 100 pub async fn flush(&mut self) {
138 let regs = IPCC::regs(); 101 let regs = IPCC::regs();
139 102
140 // This is a race, but is nice for debugging 103 // This is a race, but is nice for debugging
141 if regs.cpu(0).sr().read().chf(channel as usize) { 104 if regs.cpu(0).sr().read().chf(self.index as usize) {
142 trace!("ipcc: ch {}: wait for tx free", channel as u8); 105 trace!("ipcc: ch {}: wait for tx free", self.index as u8);
143 } 106 }
144 107
145 poll_fn(|cx| { 108 poll_fn(|cx| {
146 IPCC::state().tx_waker_for(channel).register(cx.waker()); 109 IPCC::state().tx_waker_for(self.index).register(cx.waker());
147 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 110 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
148 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)); 111 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, false));
149 112
150 compiler_fence(Ordering::SeqCst); 113 compiler_fence(Ordering::SeqCst);
151 114
152 if !regs.cpu(0).sr().read().chf(channel as usize) { 115 if !regs.cpu(0).sr().read().chf(self.index as usize) {
153 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 116 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
154 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 117 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
155 118
156 Poll::Ready(()) 119 Poll::Ready(())
157 } else { 120 } else {
@@ -160,27 +123,44 @@ impl Ipcc {
160 }) 123 })
161 .await; 124 .await;
162 } 125 }
126}
127
128/// IPCC RX Channel
129pub struct IpccRxChannel<'a> {
130 index: u8,
131 _lifetime: PhantomData<&'a mut usize>,
132}
133
134impl<'a> IpccRxChannel<'a> {
135 pub(crate) const fn new(index: u8) -> Self {
136 core::assert!(index < 6);
137
138 Self {
139 index: index,
140 _lifetime: PhantomData,
141 }
142 }
163 143
164 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. 144 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
165 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R { 145 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R {
166 let regs = IPCC::regs(); 146 let regs = IPCC::regs();
167 147
168 loop { 148 loop {
169 // This is a race, but is nice for debugging 149 // This is a race, but is nice for debugging
170 if !regs.cpu(1).sr().read().chf(channel as usize) { 150 if !regs.cpu(1).sr().read().chf(self.index as usize) {
171 trace!("ipcc: ch {}: wait for rx occupied", channel as u8); 151 trace!("ipcc: ch {}: wait for rx occupied", self.index as u8);
172 } 152 }
173 153
174 poll_fn(|cx| { 154 poll_fn(|cx| {
175 IPCC::state().rx_waker_for(channel).register(cx.waker()); 155 IPCC::state().rx_waker_for(self.index).register(cx.waker());
176 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 156 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
177 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)); 157 regs.cpu(0).mr().modify(|w| w.set_chom(self.index as usize, false));
178 158
179 compiler_fence(Ordering::SeqCst); 159 compiler_fence(Ordering::SeqCst);
180 160
181 if regs.cpu(1).sr().read().chf(channel as usize) { 161 if regs.cpu(1).sr().read().chf(self.index as usize) {
182 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 162 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
183 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 163 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
184 164
185 Poll::Ready(()) 165 Poll::Ready(())
186 } else { 166 } else {
@@ -189,21 +169,111 @@ impl Ipcc {
189 }) 169 })
190 .await; 170 .await;
191 171
192 trace!("ipcc: ch {}: read data", channel as u8); 172 trace!("ipcc: ch {}: read data", self.index as u8);
193 173
194 match f() { 174 match f() {
195 Some(ret) => return ret, 175 Some(ret) => return ret,
196 None => {} 176 None => {}
197 } 177 }
198 178
199 trace!("ipcc: ch {}: clear rx", channel as u8); 179 trace!("ipcc: ch {}: clear rx", self.index as u8);
200 compiler_fence(Ordering::SeqCst); 180 compiler_fence(Ordering::SeqCst);
201 // If the channel is clear and the read function returns none, fetch more data 181 // If the channel is clear and the read function returns none, fetch more data
202 regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)); 182 regs.cpu(0).scr().write(|w| w.set_chc(self.index as usize, true));
203 } 183 }
204 } 184 }
205} 185}
206 186
187/// IPCC Channel
188pub struct IpccChannel<'a> {
189 index: u8,
190 _lifetime: PhantomData<&'a mut usize>,
191}
192
193impl<'a> IpccChannel<'a> {
194 pub(crate) const fn new(number: u8) -> Self {
195 core::assert!(number > 0 && number <= 6);
196
197 Self {
198 index: number - 1,
199 _lifetime: PhantomData,
200 }
201 }
202
203 /// Split into a tx and rx channel
204 pub const fn split(self) -> (IpccTxChannel<'a>, IpccRxChannel<'a>) {
205 (IpccTxChannel::new(self.index), IpccRxChannel::new(self.index))
206 }
207}
208
209/// IPCC driver.
210pub struct Ipcc {
211 _private: (),
212}
213
214impl Ipcc {
215 /// Creates a new HardwareSemaphore instance.
216 pub fn new<'d>(
217 _peripheral: Peri<'d, crate::peripherals::IPCC>,
218 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
219 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>
220 + 'd,
221 _config: Config,
222 ) -> Self {
223 rcc::enable_and_reset::<IPCC>();
224 IPCC::set_cpu2(true);
225
226 let regs = IPCC::regs();
227
228 regs.cpu(0).cr().modify(|w| {
229 w.set_rxoie(true);
230 w.set_txfie(true);
231 });
232
233 // enable interrupts
234 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
235 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
236
237 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
238 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
239
240 Self { _private: () }
241 }
242
243 /// Split into a tx and rx channel
244 pub const fn split<'a>(self) -> [(IpccTxChannel<'a>, IpccRxChannel<'a>); 6] {
245 [
246 IpccChannel::new(1).split(),
247 IpccChannel::new(2).split(),
248 IpccChannel::new(3).split(),
249 IpccChannel::new(4).split(),
250 IpccChannel::new(5).split(),
251 IpccChannel::new(6).split(),
252 ]
253 }
254
255 /// Receive from a channel number
256 pub async unsafe fn receive<R>(number: u8, f: impl FnMut() -> Option<R>) -> R {
257 core::assert!(number > 0 && number <= 6);
258
259 IpccRxChannel::new(number - 1).receive(f).await
260 }
261
262 /// Send to a channel number
263 pub async unsafe fn send(number: u8, f: impl FnOnce()) {
264 core::assert!(number > 0 && number <= 6);
265
266 IpccTxChannel::new(number - 1).send(f).await
267 }
268
269 /// Send to a channel number
270 pub async unsafe fn flush(number: u8) {
271 core::assert!(number > 0 && number <= 6);
272
273 IpccTxChannel::new(number - 1).flush().await
274 }
275}
276
207impl SealedInstance for crate::peripherals::IPCC { 277impl SealedInstance for crate::peripherals::IPCC {
208 fn regs() -> crate::pac::ipcc::Ipcc { 278 fn regs() -> crate::pac::ipcc::Ipcc {
209 crate::pac::IPCC 279 crate::pac::IPCC
@@ -232,26 +302,12 @@ impl State {
232 } 302 }
233 } 303 }
234 304
235 const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 305 const fn rx_waker_for(&self, index: u8) -> &AtomicWaker {
236 match channel { 306 &self.rx_wakers[index as usize]
237 IpccChannel::Channel1 => &self.rx_wakers[0],
238 IpccChannel::Channel2 => &self.rx_wakers[1],
239 IpccChannel::Channel3 => &self.rx_wakers[2],
240 IpccChannel::Channel4 => &self.rx_wakers[3],
241 IpccChannel::Channel5 => &self.rx_wakers[4],
242 IpccChannel::Channel6 => &self.rx_wakers[5],
243 }
244 } 307 }
245 308
246 const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 309 const fn tx_waker_for(&self, index: u8) -> &AtomicWaker {
247 match channel { 310 &self.tx_wakers[index as usize]
248 IpccChannel::Channel1 => &self.tx_wakers[0],
249 IpccChannel::Channel2 => &self.tx_wakers[1],
250 IpccChannel::Channel3 => &self.tx_wakers[2],
251 IpccChannel::Channel4 => &self.tx_wakers[3],
252 IpccChannel::Channel5 => &self.tx_wakers[4],
253 IpccChannel::Channel6 => &self.tx_wakers[5],
254 }
255 } 311 }
256} 312}
257 313