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 = []
gpiote = []
## Enable radio driver
-radio = ["dep:jewel"]
+radio = []
## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz
time-driver-rtc1 = ["_time-driver"]
@@ -153,8 +153,6 @@ embedded-storage-async = "0.4.0"
cfg-if = "1.0.0"
document-features = "0.2.7"
-jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel", optional = true }
-
nrf51-pac = { version = "0.12.0", optional = true }
nrf52805-pac = { version = "0.12.0", optional = true }
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;
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
-use jewel::phy::{Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, CRC_POLY, MAX_PDU_LENGTH};
-use pac::radio::mode::MODE_A as PacMode;
+pub use pac::radio::mode::MODE_A as Mode;
use pac::radio::pcnf0::PLEN_A as PreambleLength;
-// Re-export SVD variants to allow user to directly set values.
-pub use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower};
+use pac::radio::state::STATE_A as RadioState;
+pub use pac::radio::txpower::TXPOWER_A as TxPower;
use crate::interrupt::typelevel::Interrupt;
use crate::radio::*;
@@ -51,11 +50,6 @@ impl<'d, T: Instance> Radio<'d, T> {
radio: impl Peripheral
+ 'd,
_irq: impl interrupt::typelevel::Binding> + 'd,
) -> Self {
- // From 5.4.1 of the nRF52840 Product Specification:
- // > The HFXO must be running to use the RADIO or the calibration mechanism associated with the 32.768 kHz RC oscillator.
- // Currently the jewel crate don't implement the calibration mechanism, so we need to ensure that the HFXO is running
- utils::check_xtal();
-
into_ref!(radio);
let r = T::regs();
@@ -113,18 +107,6 @@ impl<'d, T: Instance> Radio<'d, T> {
.three()
});
- r.crcpoly.write(|w| unsafe {
- // Configure the CRC polynomial
- // Each term in the CRC polynomial is mapped to a bit in this
- // register which index corresponds to the term's exponent.
- // The least significant term/bit is hard-wired internally to
- // 1, and bit number 0 of the register content is ignored by
- // the hardware. The following example is for an 8 bit CRC
- // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
- w.crcpoly().bits(CRC_POLY & 0xFFFFFF)
- });
- // The CRC initial value varies depending of the PDU type
-
// Ch map between 2400 MHZ .. 2500 MHz
// All modes use this range
r.frequency.write(|w| w.map().default());
@@ -140,9 +122,7 @@ impl<'d, T: Instance> Radio<'d, T> {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
- let mut radio = Self { _p: radio };
-
- radio
+ Self { _p: radio }
}
#[allow(dead_code)]
@@ -186,7 +166,6 @@ impl<'d, T: Instance> Radio<'d, T> {
trace!("radio drop: stopped");
});
- /* Config interrupt */
// trace!("radio:enable interrupt");
// Clear some remnant side-effects (I'm unsure if this is needed)
r.events_end.reset();
@@ -238,34 +217,34 @@ impl<'d, T: Instance> Radio<'d, T> {
r.events_disabled.reset();
}
}
-}
-impl<'d, T: Instance> BleRadio for Radio<'d, T> {
- type Error = Error;
-
- fn set_mode(&mut self, mode: Mode) {
+ /// Set the radio mode
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_mode(&mut self, mode: Mode) {
let r = T::regs();
- r.mode.write(|w| {
- w.mode().variant(match mode {
- Mode::Ble1mbit => PacMode::BLE_1MBIT,
- //Mode::Ble2mbit => PacMode::BLE_2MBIT,
- })
- });
+ r.mode.write(|w| w.mode().variant(mode));
r.pcnf0.write(|w| {
w.plen().variant(match mode {
- Mode::Ble1mbit => PreambleLength::_8BIT,
- //Mode::Ble2mbit => PreambleLength::_16BIT,
+ Mode::BLE_1MBIT => PreambleLength::_8BIT,
+ Mode::BLE_2MBIT => PreambleLength::_16BIT,
+ Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE,
+ _ => unimplemented!(),
})
});
}
- fn set_header_size(&mut self, header_size: HeaderSize) {
+ /// Set the header size changing the S1 field
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_header_expansion(&mut self, use_s1_field: bool) {
let r = T::regs();
- let s1len: u8 = match header_size {
- HeaderSize::TwoBytes => 0,
- HeaderSize::ThreeBytes => 8, // bits
+ // s1 len in bits
+ let s1len: u8 = match use_s1_field {
+ false => 0,
+ true => 8,
};
r.pcnf0.write(|w| unsafe {
@@ -283,16 +262,36 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> {
});
}
- fn set_channel(&mut self, channel: Channel) {
+ /// Set initial data whitening value
+ /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream
+ /// On BLE the initial value is the channel index | 0x40
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_whitening_init(&mut self, whitening_init: u8) {
+ let r = T::regs();
+
+ r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) });
+ }
+
+ /// Set the central frequency to be used
+ /// It should be in the range 2400..2500
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_frequency(&mut self, frequency: u32) {
+ assert!(2400 <= frequency && frequency <= 2500);
let r = T::regs();
r.frequency
- .write(|w| unsafe { w.frequency().bits((channel.central_frequency() - 2400) as u8) });
- r.datawhiteiv
- .write(|w| unsafe { w.datawhiteiv().bits(channel.whitening_init()) });
+ .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) });
}
- fn set_access_address(&mut self, access_address: u32) {
+ /// Set the acess address
+ /// This address is always constants for advertising
+ /// And a random value generate on each connection
+ /// It is used to filter the packages
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_access_address(&mut self, access_address: u32) {
let r = T::regs();
// Configure logical address
@@ -327,44 +326,55 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> {
});
}
- fn set_crc_init(&mut self, crc_init: u32) {
+ /// Set the CRC polynomial
+ /// It only uses the 24 least significant bits
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_crc_poly(&mut self, crc_poly: u32) {
+ let r = T::regs();
+
+ r.crcpoly.write(|w| unsafe {
+ // Configure the CRC polynomial
+ // Each term in the CRC polynomial is mapped to a bit in this
+ // register which index corresponds to the term's exponent.
+ // The least significant term/bit is hard-wired internally to
+ // 1, and bit number 0 of the register content is ignored by
+ // the hardware. The following example is for an 8 bit CRC
+ // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
+ w.crcpoly().bits(crc_poly & 0xFFFFFF)
+ });
+ }
+
+ /// Set the CRC init value
+ /// It only uses the 24 least significant bits
+ /// The CRC initial value varies depending of the PDU type
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_crc_init(&mut self, crc_init: u32) {
let r = T::regs();
r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) });
}
- fn set_tx_power(&mut self, power_db: i8) {
+ /// Set the radio tx power
+ ///
+ /// The radio must be disabled before calling this function
+ pub fn set_tx_power(&mut self, tx_power: TxPower) {
let r = T::regs();
- let tx_power: TxPower = match power_db {
- 8..=i8::MAX => TxPower::POS8D_BM,
- 7 => TxPower::POS7D_BM,
- 6 => TxPower::POS6D_BM,
- 5 => TxPower::POS5D_BM,
- 4 => TxPower::POS4D_BM,
- 3 => TxPower::POS3D_BM,
- 1..=2 => TxPower::POS2D_BM,
- -3..=0 => TxPower::_0D_BM,
- -7..=-4 => TxPower::NEG4D_BM,
- -11..=-8 => TxPower::NEG8D_BM,
- -15..=-12 => TxPower::NEG12D_BM,
- -19..=-16 => TxPower::NEG16D_BM,
- -29..=-20 => TxPower::NEG20D_BM,
- -39..=-30 => TxPower::NEG30D_BM,
- i8::MIN..=-40 => TxPower::NEG40D_BM,
- };
-
r.txpower.write(|w| w.txpower().variant(tx_power));
}
- fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
+ /// Set buffer to read/write
+ ///
+ /// This method is unsound. You should guarantee that the buffer will live
+ /// for the life time of the transmission or if the buffer will be modified.
+ /// Also if the buffer is smaller than the packet length, the radio will
+ /// read/write memory out of the buffer bounds.
+ pub fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
// Because we are serializing the buffer, we should always have the buffer in RAM
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
- if buffer.len() > MAX_PDU_LENGTH {
- return Err(Error::BufferTooLong);
- }
-
let r = T::regs();
// Here we are considering that the length of the packet is
@@ -379,7 +389,7 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> {
}
/// Send packet
- async fn transmit(&mut self) {
+ pub async fn transmit(&mut self) {
let r = T::regs();
self.trigger_and_wait_end(move || {
@@ -390,8 +400,8 @@ impl<'d, T: Instance> BleRadio for Radio<'d, T> {
.await;
}
- /// Send packet
- async fn receive(&mut self) {
+ /// Receive packet
+ pub async fn receive(&mut self) {
let r = T::regs();
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 interrupt::typelevel::Handler for InterruptHandl
}
}
-pub(crate) mod utils {
- use super::*;
-
- // Check if the HFCLK is XTAL is enabled
- pub fn check_xtal() {
- // safe: only reading the value
- let is_xtal = unsafe {
- let r = &*pac::CLOCK::ptr();
- r.hfclkstat.read().src().is_xtal()
- };
- assert!(is_xtal, "HFCLK must be XTAL");
- }
-}
-
pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker;
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" }
embedded-hal-bus = { version = "0.1", features = ["async"] }
num-integer = { version = "0.1.45", default-features = false }
microfft = "0.5.0"
-jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel"}
-
-[patch.crates-io]
-embassy-time = { version = "0.3.0", path = "../../embassy-time"}
[profile.release]
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 @@
-#![no_std]
-#![no_main]
-
-use defmt::{info, unwrap};
-use embassy_executor::Spawner;
-use embassy_nrf::{bind_interrupts, peripherals, radio};
-use embassy_time::Timer;
-use jewel::phy::Radio;
-use {defmt_rtt as _, panic_probe as _};
-
-bind_interrupts!(struct Irqs {
- RADIO => radio::InterruptHandler;
-});
-
-// For a high-level API look on jewel examples
-#[embassy_executor::main]
-async fn main(_spawner: Spawner) {
- let mut config = embassy_nrf::config::Config::default();
- config.hfclk_source = embassy_nrf::config::HfclkSource::ExternalXtal;
- let p = embassy_nrf::init(config);
-
- info!("Starting BLE radio");
- let mut radio = radio::ble::Radio::new(p.RADIO, Irqs);
-
- let pdu = [
- 0x46u8, // ADV_NONCONN_IND, Random address,
- 0x18, // Length of payload
- 0x27, 0xdc, 0xd0, 0xe8, 0xe1, 0xff, // Adress
- 0x02, 0x01, 0x06, // Flags
- 0x03, 0x03, 0x09, 0x18, // Complete list of 16-bit UUIDs available
- 0x0A, 0x09, // Length, Type: Device name
- b'H', b'e', b'l', b'l', b'o', b'R', b'u', b's', b't',
- ];
-
- unwrap!(radio.set_buffer(pdu.as_ref()));
-
- loop {
- info!("Sending packet");
- radio.transmit().await;
- Timer::after_millis(500).await;
- }
-}