aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/radio/ble.rs14
-rw-r--r--embassy-nrf/src/radio/ieee802154.rs109
-rw-r--r--embassy-nrf/src/radio/mod.rs28
3 files changed, 61 insertions, 90 deletions
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
index 93c701de0..846ac98af 100644
--- a/embassy-nrf/src/radio/ble.rs
+++ b/embassy-nrf/src/radio/ble.rs
@@ -8,8 +8,6 @@ use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
9pub use pac::radio::mode::MODE_A as Mode; 9pub use pac::radio::mode::MODE_A as Mode;
10use pac::radio::pcnf0::PLEN_A as PreambleLength; 10use pac::radio::pcnf0::PLEN_A as PreambleLength;
11use pac::radio::state::STATE_A as RadioState;
12pub use pac::radio::txpower::TXPOWER_A as TxPower;
13 11
14use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
15pub use crate::radio::Error; 13pub use crate::radio::Error;
@@ -111,17 +109,7 @@ impl<'d, T: Instance> Radio<'d, T> {
111 109
112 #[allow(dead_code)] 110 #[allow(dead_code)]
113 fn trace_state(&self) { 111 fn trace_state(&self) {
114 match self.state() { 112 super::trace_state(T::regs())
115 RadioState::DISABLED => trace!("radio:state:DISABLED"),
116 RadioState::RX_RU => trace!("radio:state:RX_RU"),
117 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
118 RadioState::RX => trace!("radio:state:RX"),
119 RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
120 RadioState::TX_RU => trace!("radio:state:TX_RU"),
121 RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
122 RadioState::TX => trace!("radio:state:TX"),
123 RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
124 }
125 } 113 }
126 114
127 /// Set the radio mode 115 /// Set the radio mode
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
index 91c6dbd3b..2de53b392 100644
--- a/embassy-nrf/src/radio/ieee802154.rs
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -1,19 +1,17 @@
1//! IEEE 802.15.4 radio 1//! IEEE 802.15.4 radio driver
2 2
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8use pac::radio::state::STATE_A as RadioState;
9use pac::radio::txpower::TXPOWER_A as TxPower;
10 8
11use super::{Error, Instance, InterruptHandler}; 9use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower};
12use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
13use crate::interrupt::{self}; 11use crate::interrupt::{self};
14use crate::{pac, Peripheral}; 12use crate::Peripheral;
15 13
16/// Default Start of Frame Delimiter = `0xA7` (IEEE compliant) 14/// Default (IEEE compliant) Start of Frame Delimiter
17pub const DEFAULT_SFD: u8 = 0xA7; 15pub const DEFAULT_SFD: u8 = 0xA7;
18 16
19// TODO expose the other variants in `pac::CCAMODE_A` 17// TODO expose the other variants in `pac::CCAMODE_A`
@@ -32,35 +30,14 @@ pub enum Cca {
32 }, 30 },
33} 31}
34 32
35fn get_state(radio: &pac::radio::RegisterBlock) -> RadioState { 33/// IEEE 802.15.4 radio driver.
36 match radio.state.read().state().variant() {
37 Some(state) => state,
38 None => unreachable!(),
39 }
40}
41
42fn trace_state(state: RadioState) {
43 match state {
44 RadioState::DISABLED => trace!("radio:state:DISABLED"),
45 RadioState::RX_RU => trace!("radio:state:RX_RU"),
46 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
47 RadioState::RX => trace!("radio:state:RX"),
48 RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
49 RadioState::TX_RU => trace!("radio:state:TX_RU"),
50 RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
51 RadioState::TX => trace!("radio:state:TX"),
52 RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
53 }
54}
55
56/// Radio driver.
57pub struct Radio<'d, T: Instance> { 34pub struct Radio<'d, T: Instance> {
58 _p: PeripheralRef<'d, T>, 35 _p: PeripheralRef<'d, T>,
59 needs_enable: bool, 36 needs_enable: bool,
60} 37}
61 38
62impl<'d, T: Instance> Radio<'d, T> { 39impl<'d, T: Instance> Radio<'d, T> {
63 /// Create a new radio driver. 40 /// Create a new IEEE 802.15.4 radio driver.
64 pub fn new( 41 pub fn new(
65 radio: impl Peripheral<P = T> + 'd, 42 radio: impl Peripheral<P = T> + 'd,
66 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 43 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -81,40 +58,43 @@ impl<'d, T: Instance> Radio<'d, T> {
81 // Configure CRC polynomial and init 58 // Configure CRC polynomial and init
82 r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021)); 59 r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021));
83 r.crcinit.write(|w| w.crcinit().bits(0)); 60 r.crcinit.write(|w| w.crcinit().bits(0));
84 // Configure packet layout
85 // 8-bit on air length
86 // S0 length, zero bytes
87 // S1 length, zero bytes
88 // S1 included in RAM if S1 length > 0, No.
89 // Code Indicator length, 0
90 // Preamble length 32-bit zero
91 // Exclude CRC
92 // No TERM field
93 r.pcnf0.write(|w| { 61 r.pcnf0.write(|w| {
62 // 8-bit on air length
94 w.lflen() 63 w.lflen()
95 .bits(8) 64 .bits(8)
65 // Zero bytes S0 field length
96 .s0len() 66 .s0len()
97 .clear_bit() 67 .clear_bit()
68 // Zero bytes S1 field length
98 .s1len() 69 .s1len()
99 .bits(0) 70 .bits(0)
71 // Do not include S1 field in RAM if S1 length > 0
100 .s1incl() 72 .s1incl()
101 .clear_bit() 73 .clear_bit()
74 // Zero code Indicator length
102 .cilen() 75 .cilen()
103 .bits(0) 76 .bits(0)
77 // 32-bit zero preamble
104 .plen() 78 .plen()
105 ._32bit_zero() 79 ._32bit_zero()
80 // Include CRC in length
106 .crcinc() 81 .crcinc()
107 .include() 82 .include()
108 }); 83 });
109 r.pcnf1.write(|w| { 84 r.pcnf1.write(|w| {
85 // Maximum packet length
110 w.maxlen() 86 w.maxlen()
111 .bits(Packet::MAX_PSDU_LEN) 87 .bits(Packet::MAX_PSDU_LEN)
88 // Zero static length
112 .statlen() 89 .statlen()
113 .bits(0) 90 .bits(0)
91 // Zero base address length
114 .balen() 92 .balen()
115 .bits(0) 93 .bits(0)
94 // Little-endian
116 .endian() 95 .endian()
117 .clear_bit() 96 .clear_bit()
97 // Disable packet whitening
118 .whiteen() 98 .whiteen()
119 .clear_bit() 99 .clear_bit()
120 }); 100 });
@@ -208,16 +188,9 @@ impl<'d, T: Instance> Radio<'d, T> {
208 while self.state() != state {} 188 while self.state() != state {}
209 } 189 }
210 190
191 /// Get the current radio state
211 fn state(&self) -> RadioState { 192 fn state(&self) -> RadioState {
212 let r = T::regs(); 193 state(T::regs())
213 match r.state.read().state().variant() {
214 Some(state) => state,
215 None => unreachable!(),
216 }
217 }
218
219 fn trace_state(&self) {
220 trace_state(self.state());
221 } 194 }
222 195
223 /// Moves the radio from any state to the DISABLED state 196 /// Moves the radio from any state to the DISABLED state
@@ -227,20 +200,17 @@ impl<'d, T: Instance> Radio<'d, T> {
227 loop { 200 loop {
228 match self.state() { 201 match self.state() {
229 RadioState::DISABLED => return, 202 RadioState::DISABLED => return,
230 203 // idle or ramping up
231 RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => { 204 RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => {
232 r.tasks_disable.write(|w| w.tasks_disable().set_bit()); 205 r.tasks_disable.write(|w| w.tasks_disable().set_bit());
233
234 self.wait_for_radio_state(RadioState::DISABLED); 206 self.wait_for_radio_state(RadioState::DISABLED);
235 return; 207 return;
236 } 208 }
237
238 // ramping down 209 // ramping down
239 RadioState::RX_DISABLE | RadioState::TX_DISABLE => { 210 RadioState::RX_DISABLE | RadioState::TX_DISABLE => {
240 self.wait_for_radio_state(RadioState::DISABLED); 211 self.wait_for_radio_state(RadioState::DISABLED);
241 return; 212 return;
242 } 213 }
243
244 // cancel ongoing transfer or ongoing CCA 214 // cancel ongoing transfer or ongoing CCA
245 RadioState::RX => { 215 RadioState::RX => {
246 r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit()); 216 r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit());
@@ -262,35 +232,27 @@ impl<'d, T: Instance> Radio<'d, T> {
262 232
263 /// Moves the radio to the RXIDLE state 233 /// Moves the radio to the RXIDLE state
264 fn receive_prepare(&mut self) { 234 fn receive_prepare(&mut self) {
265 let state = self.state(); 235 // clear related events
266 236 T::regs().events_ccabusy.reset();
267 let disable = match state { 237 T::regs().events_phyend.reset();
238 // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE
239 let disable = match self.state() {
268 RadioState::DISABLED => false, 240 RadioState::DISABLED => false,
269 RadioState::RX_DISABLE => true,
270 RadioState::TX_DISABLE => true,
271 RadioState::RX_IDLE => self.needs_enable, 241 RadioState::RX_IDLE => self.needs_enable,
272 // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE 242 _ => true,
273 RadioState::TX_IDLE => true,
274 _ => unreachable!(),
275 }; 243 };
276 if disable { 244 if disable {
277 trace!("Receive Setup");
278 self.trace_state();
279 self.disable(); 245 self.disable();
280 } 246 }
281 self.needs_enable = false; 247 self.needs_enable = false;
282 } 248 }
283 249
250 /// Prepare radio for receiving a packet
284 fn receive_start(&mut self, packet: &mut Packet) { 251 fn receive_start(&mut self, packet: &mut Packet) {
285 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's 252 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
286 // allocated in RAM 253 // allocated in RAM
287 let r = T::regs(); 254 let r = T::regs();
288 255
289 // clear related events
290 r.events_framestart.reset();
291 r.events_ccabusy.reset();
292 r.events_phyend.reset();
293
294 self.receive_prepare(); 256 self.receive_prepare();
295 257
296 // Configure shortcuts 258 // Configure shortcuts
@@ -314,15 +276,13 @@ impl<'d, T: Instance> Radio<'d, T> {
314 } 276 }
315 } 277 }
316 278
279 /// Cancel receiving packet
317 fn receive_cancel() { 280 fn receive_cancel() {
318 let r = T::regs(); 281 let r = T::regs();
319 r.shorts.reset(); 282 r.shorts.reset();
320 if r.events_framestart.read().events_framestart().bit_is_set() {
321 // TODO: Is there a way to finish receiving this frame
322 }
323 r.tasks_stop.write(|w| w.tasks_stop().set_bit()); 283 r.tasks_stop.write(|w| w.tasks_stop().set_bit());
324 loop { 284 loop {
325 match get_state(r) { 285 match state(r) {
326 RadioState::DISABLED | RadioState::RX_IDLE => break, 286 RadioState::DISABLED | RadioState::RX_IDLE => break,
327 _ => (), 287 _ => (),
328 } 288 }
@@ -336,7 +296,7 @@ impl<'d, T: Instance> Radio<'d, T> {
336 /// This methods returns the `Ok` variant if the CRC included the packet was successfully 296 /// This methods returns the `Ok` variant if the CRC included the packet was successfully
337 /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet` 297 /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
338 /// will be updated with the received packet's data 298 /// will be updated with the received packet's data
339 pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), u16> { 299 pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> {
340 let s = T::state(); 300 let s = T::state();
341 let r = T::regs(); 301 let r = T::regs();
342 302
@@ -369,7 +329,7 @@ impl<'d, T: Instance> Radio<'d, T> {
369 if r.crcstatus.read().crcstatus().bit_is_set() { 329 if r.crcstatus.read().crcstatus().bit_is_set() {
370 Ok(()) 330 Ok(())
371 } else { 331 } else {
372 Err(crc) 332 Err(Error::CrcFailed(crc))
373 } 333 }
374 } 334 }
375 335
@@ -387,11 +347,6 @@ impl<'d, T: Instance> Radio<'d, T> {
387 let s = T::state(); 347 let s = T::state();
388 let r = T::regs(); 348 let r = T::regs();
389 349
390 // clear related events
391 r.events_framestart.reset();
392 r.events_ccabusy.reset();
393 r.events_phyend.reset();
394
395 // enable radio to perform cca 350 // enable radio to perform cca
396 self.receive_prepare(); 351 self.receive_prepare();
397 352
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
index 9b3a6cf49..333dfb33d 100644
--- a/embassy-nrf/src/radio/mod.rs
+++ b/embassy-nrf/src/radio/mod.rs
@@ -15,6 +15,9 @@ use core::marker::PhantomData;
15 15
16use crate::{interrupt, pac, Peripheral}; 16use crate::{interrupt, pac, Peripheral};
17 17
18use pac::radio::state::STATE_A as RadioState;
19use pac::radio::txpower::TXPOWER_A as TxPower;
20
18/// RADIO error. 21/// RADIO error.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)] 22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -28,6 +31,8 @@ pub enum Error {
28 BufferNotInRAM, 31 BufferNotInRAM,
29 /// Clear channel assessment reported channel in use 32 /// Clear channel assessment reported channel in use
30 ChannelInUse, 33 ChannelInUse,
34 /// CRC check failed
35 CrcFailed(u16),
31} 36}
32 37
33/// Interrupt handler 38/// Interrupt handler
@@ -89,3 +94,26 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
89 /// Interrupt for this peripheral. 94 /// Interrupt for this peripheral.
90 type Interrupt: interrupt::typelevel::Interrupt; 95 type Interrupt: interrupt::typelevel::Interrupt;
91} 96}
97
98/// Get the state of the radio
99pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState {
100 match radio.state.read().state().variant() {
101 Some(state) => state,
102 None => unreachable!(),
103 }
104}
105
106#[allow(dead_code)]
107pub(crate) fn trace_state(radio: &pac::radio::RegisterBlock) {
108 match state(radio) {
109 RadioState::DISABLED => trace!("radio:state:DISABLED"),
110 RadioState::RX_RU => trace!("radio:state:RX_RU"),
111 RadioState::RX_IDLE => trace!("radio:state:RX_IDLE"),
112 RadioState::RX => trace!("radio:state:RX"),
113 RadioState::RX_DISABLE => trace!("radio:state:RX_DISABLE"),
114 RadioState::TX_RU => trace!("radio:state:TX_RU"),
115 RadioState::TX_IDLE => trace!("radio:state:TX_IDLE"),
116 RadioState::TX => trace!("radio:state:TX"),
117 RadioState::TX_DISABLE => trace!("radio:state:TX_DISABLE"),
118 }
119}