aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/ipcc.rs
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-06-17 12:00:33 -0500
committerxoviat <[email protected]>2023-06-17 12:00:33 -0500
commit6b5d55eb29aa55795cfdf98593feba2f53b85b9c (patch)
tree8bf1c67f2464dcf17245fd97360915cbe6a79005 /embassy-stm32/src/ipcc.rs
parentb0a2f0c4fec5358063e6323bf9f9ee001341c473 (diff)
stm32/wpan: convert to new ipcc
Diffstat (limited to 'embassy-stm32/src/ipcc.rs')
-rw-r--r--embassy-stm32/src/ipcc.rs274
1 files changed, 189 insertions, 85 deletions
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 28f51baa5..609c4d2c3 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,7 +1,77 @@
1use core::future::poll_fn;
2use core::task::Poll;
3
4use atomic_polyfill::{compiler_fence, Ordering};
5
1use self::sealed::Instance; 6use self::sealed::Instance;
7use crate::interrupt;
8use crate::interrupt::typelevel::Interrupt;
2use crate::peripherals::IPCC; 9use crate::peripherals::IPCC;
3use crate::rcc::sealed::RccPeripheral; 10use crate::rcc::sealed::RccPeripheral;
4 11
12/// Interrupt handler.
13pub struct ReceiveInterruptHandler {}
14
15impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
16 unsafe fn on_interrupt() {
17 let regs = IPCC::regs();
18
19 let channels = [
20 IpccChannel::Channel1,
21 IpccChannel::Channel2,
22 IpccChannel::Channel3,
23 IpccChannel::Channel4,
24 IpccChannel::Channel5,
25 IpccChannel::Channel6,
26 ];
27
28 // Status register gives channel occupied status. For rx, use cpu1.
29 let sr = unsafe { regs.cpu(1).sr().read() };
30 regs.cpu(0).mr().modify(|w| {
31 for channel in channels {
32 if sr.chf(channel as usize) {
33 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
34 w.set_chom(channel as usize, true);
35
36 // There shouldn't be a race because the channel is masked only if the interrupt has fired
37 IPCC::state().rx_waker_for(channel).wake();
38 }
39 }
40 })
41 }
42}
43
44pub struct TransmitInterruptHandler {}
45
46impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
47 unsafe fn on_interrupt() {
48 let regs = IPCC::regs();
49
50 let channels = [
51 IpccChannel::Channel1,
52 IpccChannel::Channel2,
53 IpccChannel::Channel3,
54 IpccChannel::Channel4,
55 IpccChannel::Channel5,
56 IpccChannel::Channel6,
57 ];
58
59 // Status register gives channel occupied status. For tx, use cpu0.
60 let sr = unsafe { regs.cpu(0).sr().read() };
61 regs.cpu(0).mr().modify(|w| {
62 for channel in channels {
63 if !sr.chf(channel as usize) {
64 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
65 w.set_chfm(channel as usize, true);
66
67 // There shouldn't be a race because the channel is masked only if the interrupt has fired
68 IPCC::state().tx_waker_for(channel).wake();
69 }
70 }
71 });
72 }
73}
74
5#[non_exhaustive] 75#[non_exhaustive]
6#[derive(Clone, Copy, Default)] 76#[derive(Clone, Copy, Default)]
7pub struct Config { 77pub struct Config {
@@ -20,13 +90,6 @@ pub enum IpccChannel {
20 Channel6 = 5, 90 Channel6 = 5,
21} 91}
22 92
23pub mod sealed {
24 pub trait Instance: crate::rcc::RccPeripheral {
25 fn regs() -> crate::pac::ipcc::Ipcc;
26 fn set_cpu2(enabled: bool);
27 }
28}
29
30pub struct Ipcc; 93pub struct Ipcc;
31 94
32impl Ipcc { 95impl Ipcc {
@@ -45,129 +108,170 @@ impl Ipcc {
45 w.set_txfie(true); 108 w.set_txfie(true);
46 }) 109 })
47 } 110 }
48 }
49 111
50 pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) { 112 // enable interrupts
51 let regs = IPCC::regs(); 113 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
114 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
52 115
53 // If bit is set to 1 then interrupt is disabled 116 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
54 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) } 117 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
55 } 118 }
56 119
57 pub fn c1_get_rx_channel(channel: IpccChannel) -> bool { 120 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
121 pub async fn send(channel: IpccChannel, f: impl FnOnce()) {
58 let regs = IPCC::regs(); 122 let regs = IPCC::regs();
59 123
60 // If bit is set to 1 then interrupt is disabled 124 Self::flush(channel).await;
61 unsafe { !regs.cpu(0).mr().read().chom(channel as usize) } 125 compiler_fence(Ordering::SeqCst);
62 }
63 126
64 #[allow(dead_code)] 127 f();
65 pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) {
66 let regs = IPCC::regs();
67
68 // If bit is set to 1 then interrupt is disabled
69 unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
70 }
71 128
72 #[allow(dead_code)] 129 compiler_fence(Ordering::SeqCst);
73 pub fn c2_get_rx_channel(channel: IpccChannel) -> bool {
74 let regs = IPCC::regs();
75 130
76 // If bit is set to 1 then interrupt is disabled 131 trace!("ipcc: ch {}: send data", channel as u8);
77 unsafe { !regs.cpu(1).mr().read().chom(channel as usize) } 132 unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
78 } 133 }
79 134
80 pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) { 135 /// Wait for the tx channel to become clear
136 pub async fn flush(channel: IpccChannel) {
81 let regs = IPCC::regs(); 137 let regs = IPCC::regs();
82 138
83 // If bit is set to 1 then interrupt is disabled 139 // This is a race, but is nice for debugging
84 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } 140 if unsafe { regs.cpu(0).sr().read() }.chf(channel as usize) {
85 } 141 trace!("ipcc: ch {}: wait for tx free", channel as u8);
142 }
86 143
87 pub fn c1_get_tx_channel(channel: IpccChannel) -> bool { 144 poll_fn(|cx| {
88 let regs = IPCC::regs(); 145 IPCC::state().tx_waker_for(channel).register(cx.waker());
146 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
147 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)) }
89 148
90 // If bit is set to 1 then interrupt is disabled 149 compiler_fence(Ordering::SeqCst);
91 unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
92 }
93 150
94 #[allow(dead_code)] 151 if !unsafe { regs.cpu(0).sr().read() }.chf(channel as usize) {
95 pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) { 152 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
96 let regs = IPCC::regs(); 153 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)) }
97 154
98 // If bit is set to 1 then interrupt is disabled 155 Poll::Ready(())
99 unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) } 156 } else {
157 Poll::Pending
158 }
159 })
160 .await;
100 } 161 }
101 162
102 #[allow(dead_code)] 163 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
103 pub fn c2_get_tx_channel(channel: IpccChannel) -> bool { 164 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R {
104 let regs = IPCC::regs(); 165 let regs = IPCC::regs();
105 166
106 // If bit is set to 1 then interrupt is disabled 167 loop {
107 unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) } 168 // This is a race, but is nice for debugging
108 } 169 if !unsafe { regs.cpu(1).sr().read() }.chf(channel as usize) {
170 trace!("ipcc: ch {}: wait for rx occupied", channel as u8);
171 }
109 172
110 /// clears IPCC receive channel status for CPU1 173 poll_fn(|cx| {
111 pub fn c1_clear_flag_channel(channel: IpccChannel) { 174 IPCC::state().rx_waker_for(channel).register(cx.waker());
112 let regs = IPCC::regs(); 175 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
176 unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)) }
113 177
114 trace!("ipcc: ch {}: clear rx", channel as u8); 178 compiler_fence(Ordering::SeqCst);
115 unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
116 }
117 179
118 #[allow(dead_code)] 180 if unsafe { regs.cpu(1).sr().read() }.chf(channel as usize) {
119 /// clears IPCC receive channel status for CPU2 181 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
120 pub fn c2_clear_flag_channel(channel: IpccChannel) { 182 unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)) }
121 let regs = IPCC::regs();
122 183
123 unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) } 184 Poll::Ready(())
124 } 185 } else {
186 Poll::Pending
187 }
188 })
189 .await;
125 190
126 pub fn c1_set_flag_channel(channel: IpccChannel) { 191 trace!("ipcc: ch {}: read data", channel as u8);
127 let regs = IPCC::regs(); 192 compiler_fence(Ordering::SeqCst);
128 193
129 unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) } 194 match f() {
130 } 195 Some(ret) => return ret,
196 None => {}
197 }
131 198
132 #[allow(dead_code)] 199 trace!("ipcc: ch {}: clear rx", channel as u8);
133 pub fn c2_set_flag_channel(channel: IpccChannel) { 200 compiler_fence(Ordering::SeqCst);
134 let regs = IPCC::regs(); 201 // If the channel is clear and the read function returns none, fetch more data
202 unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
203 }
204 }
205}
135 206
136 unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) } 207impl sealed::Instance for crate::peripherals::IPCC {
208 fn regs() -> crate::pac::ipcc::Ipcc {
209 crate::pac::IPCC
137 } 210 }
138 211
139 pub fn c1_is_active_flag(channel: IpccChannel) -> bool { 212 fn set_cpu2(enabled: bool) {
140 let regs = IPCC::regs(); 213 unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
214 }
141 215
142 unsafe { regs.cpu(0).sr().read().chf(channel as usize) } 216 fn state() -> &'static self::sealed::State {
217 static STATE: self::sealed::State = self::sealed::State::new();
218 &STATE
143 } 219 }
220}
144 221
145 pub fn c2_is_active_flag(channel: IpccChannel) -> bool { 222pub(crate) mod sealed {
146 let regs = IPCC::regs(); 223 use embassy_sync::waitqueue::AtomicWaker;
147 224
148 unsafe { regs.cpu(1).sr().read().chf(channel as usize) } 225 use super::*;
149 }
150 226
151 pub fn is_tx_pending(channel: IpccChannel) -> bool { 227 pub struct State {
152 !Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel) 228 rx_wakers: [AtomicWaker; 6],
229 tx_wakers: [AtomicWaker; 6],
153 } 230 }
154 231
155 pub fn is_rx_pending(channel: IpccChannel) -> bool { 232 impl State {
156 Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel) 233 pub const fn new() -> Self {
157 } 234 const WAKER: AtomicWaker = AtomicWaker::new();
158}
159 235
160impl sealed::Instance for crate::peripherals::IPCC { 236 Self {
161 fn regs() -> crate::pac::ipcc::Ipcc { 237 rx_wakers: [WAKER; 6],
162 crate::pac::IPCC 238 tx_wakers: [WAKER; 6],
239 }
240 }
241
242 pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
243 match channel {
244 IpccChannel::Channel1 => &self.rx_wakers[0],
245 IpccChannel::Channel2 => &self.rx_wakers[1],
246 IpccChannel::Channel3 => &self.rx_wakers[2],
247 IpccChannel::Channel4 => &self.rx_wakers[3],
248 IpccChannel::Channel5 => &self.rx_wakers[4],
249 IpccChannel::Channel6 => &self.rx_wakers[5],
250 }
251 }
252
253 pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
254 match channel {
255 IpccChannel::Channel1 => &self.tx_wakers[0],
256 IpccChannel::Channel2 => &self.tx_wakers[1],
257 IpccChannel::Channel3 => &self.tx_wakers[2],
258 IpccChannel::Channel4 => &self.tx_wakers[3],
259 IpccChannel::Channel5 => &self.tx_wakers[4],
260 IpccChannel::Channel6 => &self.tx_wakers[5],
261 }
262 }
163 } 263 }
164 264
165 fn set_cpu2(enabled: bool) { 265 pub trait Instance: crate::rcc::RccPeripheral {
166 unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) } 266 fn regs() -> crate::pac::ipcc::Ipcc;
267 fn set_cpu2(enabled: bool);
268 fn state() -> &'static State;
167 } 269 }
168} 270}
169 271
170unsafe fn _configure_pwr() { 272unsafe fn _configure_pwr() {
273 // TODO: move this to RCC
274
171 let pwr = crate::pac::PWR; 275 let pwr = crate::pac::PWR;
172 let rcc = crate::pac::RCC; 276 let rcc = crate::pac::RCC;
173 277