aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuilherme S. Salustiano <[email protected]>2024-02-07 18:04:29 +0100
committerGuilherme S. Salustiano <[email protected]>2024-02-07 18:04:29 +0100
commit5f1b80d40b6d2ae1636fa46e8e5334c03adeb67d (patch)
tree96ea8003d1c5c323498fb7cc2c86897b387cc19d
parentd408056a66be2183dbcde6840e69e53beb4a764b (diff)
remove jewel dependency
-rw-r--r--embassy-nrf/Cargo.toml4
-rw-r--r--embassy-nrf/src/radio/ble.rs160
-rw-r--r--embassy-nrf/src/radio/mod.rs14
-rw-r--r--examples/nrf52840/Cargo.toml4
-rw-r--r--examples/nrf52840/src/bin/radio_ble_advertising.rs42
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 = []
58gpiote = [] 58gpiote = []
59 59
60## Enable radio driver 60## Enable radio driver
61radio = ["dep:jewel"] 61radio = []
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
64time-driver-rtc1 = ["_time-driver"] 64time-driver-rtc1 = ["_time-driver"]
@@ -153,8 +153,6 @@ embedded-storage-async = "0.4.0"
153cfg-if = "1.0.0" 153cfg-if = "1.0.0"
154document-features = "0.2.7" 154document-features = "0.2.7"
155 155
156jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel", optional = true }
157
158nrf51-pac = { version = "0.12.0", optional = true } 156nrf51-pac = { version = "0.12.0", optional = true }
159nrf52805-pac = { version = "0.12.0", optional = true } 157nrf52805-pac = { version = "0.12.0", optional = true }
160nrf52810-pac = { version = "0.12.0", optional = true } 158nrf52810-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
18use embassy_hal_internal::drop::OnDrop; 18use embassy_hal_internal::drop::OnDrop;
19use embassy_hal_internal::{into_ref, PeripheralRef}; 19use embassy_hal_internal::{into_ref, PeripheralRef};
20use jewel::phy::{Channel, ChannelTrait, HeaderSize, Mode, Radio as BleRadio, CRC_POLY, MAX_PDU_LENGTH}; 20pub use pac::radio::mode::MODE_A as Mode;
21use pac::radio::mode::MODE_A as PacMode;
22use pac::radio::pcnf0::PLEN_A as PreambleLength; 21use pac::radio::pcnf0::PLEN_A as PreambleLength;
23// Re-export SVD variants to allow user to directly set values. 22use pac::radio::state::STATE_A as RadioState;
24pub use pac::radio::{state::STATE_A as RadioState, txpower::TXPOWER_A as TxPower}; 23pub use pac::radio::txpower::TXPOWER_A as TxPower;
25 24
26use crate::interrupt::typelevel::Interrupt; 25use crate::interrupt::typelevel::Interrupt;
27use crate::radio::*; 26use 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
243impl<'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
32pub(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
46pub(crate) mod sealed { 32pub(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" }
35embedded-hal-bus = { version = "0.1", features = ["async"] } 35embedded-hal-bus = { version = "0.1", features = ["async"] }
36num-integer = { version = "0.1.45", default-features = false } 36num-integer = { version = "0.1.45", default-features = false }
37microfft = "0.5.0" 37microfft = "0.5.0"
38jewel = { version = "0.1.0", git = "https://github.com/jewel-rs/jewel"}
39
40[patch.crates-io]
41embassy-time = { version = "0.3.0", path = "../../embassy-time"}
42 38
43[profile.release] 39[profile.release]
44debug = 2 40debug = 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
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_nrf::{bind_interrupts, peripherals, radio};
7use embassy_time::Timer;
8use jewel::phy::Radio;
9use {defmt_rtt as _, panic_probe as _};
10
11bind_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]
17async 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}