diff options
| author | Erik Bånvik <[email protected]> | 2024-03-05 01:03:10 +0100 |
|---|---|---|
| committer | Erik Bånvik <[email protected]> | 2024-03-05 01:03:10 +0100 |
| commit | c00f014f18e7ade176ed29cc06070466079d8268 (patch) | |
| tree | 24f429952e931464abcb27c626f61c9facebf04f | |
| parent | 0c4c996339ea7e70f40b0ad77a8850728ef9dcf8 (diff) | |
Some more unifying, documentation
| -rw-r--r-- | embassy-nrf/src/radio/ble.rs | 14 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/ieee802154.rs | 109 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/mod.rs | 28 |
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; | |||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | pub use pac::radio::mode::MODE_A as Mode; | 9 | pub use pac::radio::mode::MODE_A as Mode; |
| 10 | use pac::radio::pcnf0::PLEN_A as PreambleLength; | 10 | use pac::radio::pcnf0::PLEN_A as PreambleLength; |
| 11 | use pac::radio::state::STATE_A as RadioState; | ||
| 12 | pub use pac::radio::txpower::TXPOWER_A as TxPower; | ||
| 13 | 11 | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| 15 | pub use crate::radio::Error; | 13 | pub 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 | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 3 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | use pac::radio::state::STATE_A as RadioState; | ||
| 9 | use pac::radio::txpower::TXPOWER_A as TxPower; | ||
| 10 | 8 | ||
| 11 | use super::{Error, Instance, InterruptHandler}; | 9 | use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 10 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::interrupt::{self}; | 11 | use crate::interrupt::{self}; |
| 14 | use crate::{pac, Peripheral}; | 12 | use crate::Peripheral; |
| 15 | 13 | ||
| 16 | /// Default Start of Frame Delimiter = `0xA7` (IEEE compliant) | 14 | /// Default (IEEE compliant) Start of Frame Delimiter |
| 17 | pub const DEFAULT_SFD: u8 = 0xA7; | 15 | pub 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 | ||
| 35 | fn 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 | |||
| 42 | fn 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. | ||
| 57 | pub struct Radio<'d, T: Instance> { | 34 | pub 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 | ||
| 62 | impl<'d, T: Instance> Radio<'d, T> { | 39 | impl<'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 | ||
| 16 | use crate::{interrupt, pac, Peripheral}; | 16 | use crate::{interrupt, pac, Peripheral}; |
| 17 | 17 | ||
| 18 | use pac::radio::state::STATE_A as RadioState; | ||
| 19 | use 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 | ||
| 99 | pub(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)] | ||
| 107 | pub(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 | } | ||
