diff options
| author | Guilherme S. Salustiano <[email protected]> | 2024-02-07 18:04:29 +0100 |
|---|---|---|
| committer | Guilherme S. Salustiano <[email protected]> | 2024-02-07 18:04:29 +0100 |
| commit | 5f1b80d40b6d2ae1636fa46e8e5334c03adeb67d (patch) | |
| tree | 96ea8003d1c5c323498fb7cc2c86897b387cc19d | |
| parent | d408056a66be2183dbcde6840e69e53beb4a764b (diff) | |
remove jewel dependency
| -rw-r--r-- | embassy-nrf/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/ble.rs | 160 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/mod.rs | 14 | ||||
| -rw-r--r-- | examples/nrf52840/Cargo.toml | 4 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/radio_ble_advertising.rs | 42 |
5 files changed, 86 insertions, 138 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index dcdc7f313..9f35bd241 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -58,7 +58,7 @@ unstable-pac = [] | |||
| 58 | gpiote = [] | 58 | gpiote = [] |
| 59 | 59 | ||
| 60 | ## Enable radio driver | 60 | ## Enable radio driver |
| 61 | radio = ["dep:jewel"] | 61 | radio = [] |
| 62 | 62 | ||
| 63 | ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz | 63 | ## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz |
| 64 | time-driver-rtc1 = ["_time-driver"] | 64 | time-driver-rtc1 = ["_time-driver"] |
| @@ -153,8 +153,6 @@ embedded-storage-async = "0.4.0" | |||
| 153 | cfg-if = "1.0.0" | 153 | cfg-if = "1.0.0" |
| 154 | document-features = "0.2.7" | 154 | document-features = "0.2.7" |
| 155 | 155 | ||
| 156 | jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel", optional = true } | ||
| 157 | |||
| 158 | nrf51-pac = { version = "0.12.0", optional = true } | 156 | nrf51-pac = { version = "0.12.0", optional = true } |
| 159 | nrf52805-pac = { version = "0.12.0", optional = true } | 157 | nrf52805-pac = { version = "0.12.0", optional = true } |
| 160 | nrf52810-pac = { version = "0.12.0", optional = true } | 158 | nrf52810-pac = { version = "0.12.0", optional = true } |
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 64428fff5..def941796 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs | |||
| @@ -17,11 +17,10 @@ use core::task::Poll; | |||
| 17 | 17 | ||
| 18 | use embassy_hal_internal::drop::OnDrop; | 18 | use embassy_hal_internal::drop::OnDrop; |
| 19 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 19 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 20 | use jewel::phy::{Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, CRC_POLY, MAX_PDU_LENGTH}; | 20 | pub use pac::radio::mode::MODE_A as Mode; |
| 21 | use pac::radio::mode::MODE_A as PacMode; | ||
| 22 | use pac::radio::pcnf0::PLEN_A as PreambleLength; | 21 | use pac::radio::pcnf0::PLEN_A as PreambleLength; |
| 23 | // Re-export SVD variants to allow user to directly set values. | 22 | use pac::radio::state::STATE_A as RadioState; |
| 24 | pub use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; | 23 | pub use pac::radio::txpower::TXPOWER_A as TxPower; |
| 25 | 24 | ||
| 26 | use crate::interrupt::typelevel::Interrupt; | 25 | use crate::interrupt::typelevel::Interrupt; |
| 27 | use crate::radio::*; | 26 | use crate::radio::*; |
| @@ -51,11 +50,6 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 51 | radio: impl Peripheral<P = T> + 'd, | 50 | radio: impl Peripheral<P = T> + 'd, |
| 52 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 51 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 53 | ) -> Self { | 52 | ) -> Self { |
| 54 | // From 5.4.1 of the nRF52840 Product Specification: | ||
| 55 | // > The HFXO must be running to use the RADIO or the calibration mechanism associated with the 32.768 kHz RC oscillator. | ||
| 56 | // Currently the jewel crate don't implement the calibration mechanism, so we need to ensure that the HFXO is running | ||
| 57 | utils::check_xtal(); | ||
| 58 | |||
| 59 | into_ref!(radio); | 53 | into_ref!(radio); |
| 60 | 54 | ||
| 61 | let r = T::regs(); | 55 | let r = T::regs(); |
| @@ -113,18 +107,6 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 113 | .three() | 107 | .three() |
| 114 | }); | 108 | }); |
| 115 | 109 | ||
| 116 | r.crcpoly.write(|w| unsafe { | ||
| 117 | // Configure the CRC polynomial | ||
| 118 | // Each term in the CRC polynomial is mapped to a bit in this | ||
| 119 | // register which index corresponds to the term's exponent. | ||
| 120 | // The least significant term/bit is hard-wired internally to | ||
| 121 | // 1, and bit number 0 of the register content is ignored by | ||
| 122 | // the hardware. The following example is for an 8 bit CRC | ||
| 123 | // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . | ||
| 124 | w.crcpoly().bits(CRC_POLY & 0xFFFFFF) | ||
| 125 | }); | ||
| 126 | // The CRC initial value varies depending of the PDU type | ||
| 127 | |||
| 128 | // Ch map between 2400 MHZ .. 2500 MHz | 110 | // Ch map between 2400 MHZ .. 2500 MHz |
| 129 | // All modes use this range | 111 | // All modes use this range |
| 130 | r.frequency.write(|w| w.map().default()); | 112 | r.frequency.write(|w| w.map().default()); |
| @@ -140,9 +122,7 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 140 | T::Interrupt::unpend(); | 122 | T::Interrupt::unpend(); |
| 141 | unsafe { T::Interrupt::enable() }; | 123 | unsafe { T::Interrupt::enable() }; |
| 142 | 124 | ||
| 143 | let mut radio = Self { _p: radio }; | 125 | Self { _p: radio } |
| 144 | |||
| 145 | radio | ||
| 146 | } | 126 | } |
| 147 | 127 | ||
| 148 | #[allow(dead_code)] | 128 | #[allow(dead_code)] |
| @@ -186,7 +166,6 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 186 | trace!("radio drop: stopped"); | 166 | trace!("radio drop: stopped"); |
| 187 | }); | 167 | }); |
| 188 | 168 | ||
| 189 | /* Config interrupt */ | ||
| 190 | // trace!("radio:enable interrupt"); | 169 | // trace!("radio:enable interrupt"); |
| 191 | // Clear some remnant side-effects (I'm unsure if this is needed) | 170 | // Clear some remnant side-effects (I'm unsure if this is needed) |
| 192 | r.events_end.reset(); | 171 | r.events_end.reset(); |
| @@ -238,34 +217,34 @@ impl<'d, T: Instance> Radio<'d, T> { | |||
| 238 | r.events_disabled.reset(); | 217 | r.events_disabled.reset(); |
| 239 | } | 218 | } |
| 240 | } | 219 | } |
| 241 | } | ||
| 242 | 220 | ||
| 243 | impl<'d, T: Instance> BleRadio for Radio<'d, T> { | 221 | /// Set the radio mode |
| 244 | type Error = Error; | 222 | /// |
| 245 | 223 | /// The radio must be disabled before calling this function | |
| 246 | fn set_mode(&mut self, mode: Mode) { | 224 | pub fn set_mode(&mut self, mode: Mode) { |
| 247 | let r = T::regs(); | 225 | let r = T::regs(); |
| 248 | r.mode.write(|w| { | 226 | r.mode.write(|w| w.mode().variant(mode)); |
| 249 | w.mode().variant(match mode { | ||
| 250 | Mode::Ble1mbit => PacMode::BLE_1MBIT, | ||
| 251 | //Mode::Ble2mbit => PacMode::BLE_2MBIT, | ||
| 252 | }) | ||
| 253 | }); | ||
| 254 | 227 | ||
| 255 | r.pcnf0.write(|w| { | 228 | r.pcnf0.write(|w| { |
| 256 | w.plen().variant(match mode { | 229 | w.plen().variant(match mode { |
| 257 | Mode::Ble1mbit => PreambleLength::_8BIT, | 230 | Mode::BLE_1MBIT => PreambleLength::_8BIT, |
| 258 | //Mode::Ble2mbit => PreambleLength::_16BIT, | 231 | Mode::BLE_2MBIT => PreambleLength::_16BIT, |
| 232 | Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE, | ||
| 233 | _ => unimplemented!(), | ||
| 259 | }) | 234 | }) |
| 260 | }); | 235 | }); |
| 261 | } | 236 | } |
| 262 | 237 | ||
| 263 | fn set_header_size(&mut self, header_size: HeaderSize) { | 238 | /// Set the header size changing the S1 field |
| 239 | /// | ||
| 240 | /// The radio must be disabled before calling this function | ||
| 241 | pub fn set_header_expansion(&mut self, use_s1_field: bool) { | ||
| 264 | let r = T::regs(); | 242 | let r = T::regs(); |
| 265 | 243 | ||
| 266 | let s1len: u8 = match header_size { | 244 | // s1 len in bits |
| 267 | HeaderSize::TwoBytes => 0, | 245 | let s1len: u8 = match use_s1_field { |
| 268 | HeaderSize::ThreeBytes => 8, // bits | 246 | false => 0, |
| 247 | true => 8, | ||
| 269 | }; | 248 | }; |
| 270 | 249 | ||
| 271 | r.pcnf0.write(|w| unsafe { | 250 | r.pcnf0.write(|w| unsafe { |
| @@ -283,16 +262,36 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { | |||
| 283 | }); | 262 | }); |
| 284 | } | 263 | } |
| 285 | 264 | ||
| 286 | fn set_channel(&mut self, channel: Channel) { | 265 | /// Set initial data whitening value |
| 266 | /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream | ||
| 267 | /// On BLE the initial value is the channel index | 0x40 | ||
| 268 | /// | ||
| 269 | /// The radio must be disabled before calling this function | ||
| 270 | pub fn set_whitening_init(&mut self, whitening_init: u8) { | ||
| 271 | let r = T::regs(); | ||
| 272 | |||
| 273 | r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); | ||
| 274 | } | ||
| 275 | |||
| 276 | /// Set the central frequency to be used | ||
| 277 | /// It should be in the range 2400..2500 | ||
| 278 | /// | ||
| 279 | /// The radio must be disabled before calling this function | ||
| 280 | pub fn set_frequency(&mut self, frequency: u32) { | ||
| 281 | assert!(2400 <= frequency && frequency <= 2500); | ||
| 287 | let r = T::regs(); | 282 | let r = T::regs(); |
| 288 | 283 | ||
| 289 | r.frequency | 284 | r.frequency |
| 290 | .write(|w| unsafe { w.frequency().bits((channel.central_frequency() - 2400) as u8) }); | 285 | .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) }); |
| 291 | r.datawhiteiv | ||
| 292 | .write(|w| unsafe { w.datawhiteiv().bits(channel.whitening_init()) }); | ||
| 293 | } | 286 | } |
| 294 | 287 | ||
| 295 | fn set_access_address(&mut self, access_address: u32) { | 288 | /// Set the acess address |
| 289 | /// This address is always constants for advertising | ||
| 290 | /// And a random value generate on each connection | ||
| 291 | /// It is used to filter the packages | ||
| 292 | /// | ||
| 293 | /// The radio must be disabled before calling this function | ||
| 294 | pub fn set_access_address(&mut self, access_address: u32) { | ||
| 296 | let r = T::regs(); | 295 | let r = T::regs(); |
| 297 | 296 | ||
| 298 | // Configure logical address | 297 | // Configure logical address |
| @@ -327,44 +326,55 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { | |||
| 327 | }); | 326 | }); |
| 328 | } | 327 | } |
| 329 | 328 | ||
| 330 | fn set_crc_init(&mut self, crc_init: u32) { | 329 | /// Set the CRC polynomial |
| 330 | /// It only uses the 24 least significant bits | ||
| 331 | /// | ||
| 332 | /// The radio must be disabled before calling this function | ||
| 333 | pub fn set_crc_poly(&mut self, crc_poly: u32) { | ||
| 331 | let r = T::regs(); | 334 | let r = T::regs(); |
| 332 | 335 | ||
| 333 | r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); | 336 | r.crcpoly.write(|w| unsafe { |
| 337 | // Configure the CRC polynomial | ||
| 338 | // Each term in the CRC polynomial is mapped to a bit in this | ||
| 339 | // register which index corresponds to the term's exponent. | ||
| 340 | // The least significant term/bit is hard-wired internally to | ||
| 341 | // 1, and bit number 0 of the register content is ignored by | ||
| 342 | // the hardware. The following example is for an 8 bit CRC | ||
| 343 | // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . | ||
| 344 | w.crcpoly().bits(crc_poly & 0xFFFFFF) | ||
| 345 | }); | ||
| 334 | } | 346 | } |
| 335 | 347 | ||
| 336 | fn set_tx_power(&mut self, power_db: i8) { | 348 | /// Set the CRC init value |
| 349 | /// It only uses the 24 least significant bits | ||
| 350 | /// The CRC initial value varies depending of the PDU type | ||
| 351 | /// | ||
| 352 | /// The radio must be disabled before calling this function | ||
| 353 | pub fn set_crc_init(&mut self, crc_init: u32) { | ||
| 337 | let r = T::regs(); | 354 | let r = T::regs(); |
| 338 | 355 | ||
| 339 | let tx_power: TxPower = match power_db { | 356 | r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); |
| 340 | 8..=i8::MAX => TxPower::POS8D_BM, | 357 | } |
| 341 | 7 => TxPower::POS7D_BM, | 358 | |
| 342 | 6 => TxPower::POS6D_BM, | 359 | /// Set the radio tx power |
| 343 | 5 => TxPower::POS5D_BM, | 360 | /// |
| 344 | 4 => TxPower::POS4D_BM, | 361 | /// The radio must be disabled before calling this function |
| 345 | 3 => TxPower::POS3D_BM, | 362 | pub fn set_tx_power(&mut self, tx_power: TxPower) { |
| 346 | 1..=2 => TxPower::POS2D_BM, | 363 | let r = T::regs(); |
| 347 | -3..=0 => TxPower::_0D_BM, | ||
| 348 | -7..=-4 => TxPower::NEG4D_BM, | ||
| 349 | -11..=-8 => TxPower::NEG8D_BM, | ||
| 350 | -15..=-12 => TxPower::NEG12D_BM, | ||
| 351 | -19..=-16 => TxPower::NEG16D_BM, | ||
| 352 | -29..=-20 => TxPower::NEG20D_BM, | ||
| 353 | -39..=-30 => TxPower::NEG30D_BM, | ||
| 354 | i8::MIN..=-40 => TxPower::NEG40D_BM, | ||
| 355 | }; | ||
| 356 | 364 | ||
| 357 | r.txpower.write(|w| w.txpower().variant(tx_power)); | 365 | r.txpower.write(|w| w.txpower().variant(tx_power)); |
| 358 | } | 366 | } |
| 359 | 367 | ||
| 360 | fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 368 | /// Set buffer to read/write |
| 369 | /// | ||
| 370 | /// This method is unsound. You should guarantee that the buffer will live | ||
| 371 | /// for the life time of the transmission or if the buffer will be modified. | ||
| 372 | /// Also if the buffer is smaller than the packet length, the radio will | ||
| 373 | /// read/write memory out of the buffer bounds. | ||
| 374 | pub fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 361 | // Because we are serializing the buffer, we should always have the buffer in RAM | 375 | // Because we are serializing the buffer, we should always have the buffer in RAM |
| 362 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | 376 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; |
| 363 | 377 | ||
| 364 | if buffer.len() > MAX_PDU_LENGTH { | ||
| 365 | return Err(Error::BufferTooLong); | ||
| 366 | } | ||
| 367 | |||
| 368 | let r = T::regs(); | 378 | let r = T::regs(); |
| 369 | 379 | ||
| 370 | // Here we are considering that the length of the packet is | 380 | // Here we are considering that the length of the packet is |
| @@ -379,7 +389,7 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { | |||
| 379 | } | 389 | } |
| 380 | 390 | ||
| 381 | /// Send packet | 391 | /// Send packet |
| 382 | async fn transmit(&mut self) { | 392 | pub async fn transmit(&mut self) { |
| 383 | let r = T::regs(); | 393 | let r = T::regs(); |
| 384 | 394 | ||
| 385 | self.trigger_and_wait_end(move || { | 395 | self.trigger_and_wait_end(move || { |
| @@ -390,8 +400,8 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> { | |||
| 390 | .await; | 400 | .await; |
| 391 | } | 401 | } |
| 392 | 402 | ||
| 393 | /// Send packet | 403 | /// Receive packet |
| 394 | async fn receive(&mut self) { | 404 | pub async fn receive(&mut self) { |
| 395 | let r = T::regs(); | 405 | let r = T::regs(); |
| 396 | 406 | ||
| 397 | self.trigger_and_wait_end(move || { | 407 | self.trigger_and_wait_end(move || { |
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 91cc2c0a7..03f967f87 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs | |||
| @@ -29,20 +29,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 29 | } | 29 | } |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | pub(crate) mod utils { | ||
| 33 | use super::*; | ||
| 34 | |||
| 35 | // Check if the HFCLK is XTAL is enabled | ||
| 36 | pub fn check_xtal() { | ||
| 37 | // safe: only reading the value | ||
| 38 | let is_xtal = unsafe { | ||
| 39 | let r = &*pac::CLOCK::ptr(); | ||
| 40 | r.hfclkstat.read().src().is_xtal() | ||
| 41 | }; | ||
| 42 | assert!(is_xtal, "HFCLK must be XTAL"); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | pub(crate) mod sealed { | 32 | pub(crate) mod sealed { |
| 47 | use embassy_sync::waitqueue::AtomicWaker; | 33 | use embassy_sync::waitqueue::AtomicWaker; |
| 48 | 34 | ||
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 0239583cd..78dabe347 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -35,10 +35,6 @@ embedded-hal-async = { version = "1.0" } | |||
| 35 | embedded-hal-bus = { version = "0.1", features = ["async"] } | 35 | embedded-hal-bus = { version = "0.1", features = ["async"] } |
| 36 | num-integer = { version = "0.1.45", default-features = false } | 36 | num-integer = { version = "0.1.45", default-features = false } |
| 37 | microfft = "0.5.0" | 37 | microfft = "0.5.0" |
| 38 | jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel"} | ||
| 39 | |||
| 40 | [patch.crates-io] | ||
| 41 | embassy-time = { version = "0.3.0", path = "../../embassy-time"} | ||
| 42 | 38 | ||
| 43 | [profile.release] | 39 | [profile.release] |
| 44 | debug = 2 | 40 | debug = 2 |
diff --git a/examples/nrf52840/src/bin/radio_ble_advertising.rs b/examples/nrf52840/src/bin/radio_ble_advertising.rs deleted file mode 100644 index 8898c2418..000000000 --- a/examples/nrf52840/src/bin/radio_ble_advertising.rs +++ /dev/null | |||
| @@ -1,42 +0,0 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::{bind_interrupts, peripherals, radio}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use jewel::phy::Radio; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | RADIO => radio::InterruptHandler<peripherals::RADIO>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | // For a high-level API look on jewel examples | ||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = embassy_nrf::config::Config::default(); | ||
| 19 | config.hfclk_source = embassy_nrf::config::HfclkSource::ExternalXtal; | ||
| 20 | let p = embassy_nrf::init(config); | ||
| 21 | |||
| 22 | info!("Starting BLE radio"); | ||
| 23 | let mut radio = radio::ble::Radio::new(p.RADIO, Irqs); | ||
| 24 | |||
| 25 | let pdu = [ | ||
| 26 | 0x46u8, // ADV_NONCONN_IND, Random address, | ||
| 27 | 0x18, // Length of payload | ||
| 28 | 0x27, 0xdc, 0xd0, 0xe8, 0xe1, 0xff, // Adress | ||
| 29 | 0x02, 0x01, 0x06, // Flags | ||
| 30 | 0x03, 0x03, 0x09, 0x18, // Complete list of 16-bit UUIDs available | ||
| 31 | 0x0A, 0x09, // Length, Type: Device name | ||
| 32 | b'H', b'e', b'l', b'l', b'o', b'R', b'u', b's', b't', | ||
| 33 | ]; | ||
| 34 | |||
| 35 | unwrap!(radio.set_buffer(pdu.as_ref())); | ||
| 36 | |||
| 37 | loop { | ||
| 38 | info!("Sending packet"); | ||
| 39 | radio.transmit().await; | ||
| 40 | Timer::after_millis(500).await; | ||
| 41 | } | ||
| 42 | } | ||
