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