aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md91
-rw-r--r--docs/examples/basic/.cargo/config.toml4
-rw-r--r--docs/examples/layer-by-layer/.cargo/config.toml3
-rw-r--r--docs/pages/getting_started.adoc2
-rw-r--r--docs/pages/new_project.adoc2
-rw-r--r--docs/pages/project_structure.adoc4
-rw-r--r--embassy-net/CHANGELOG.md4
-rw-r--r--embassy-nrf/src/radio/ble.rs394
-rw-r--r--embassy-nrf/src/radio/ieee802154.rs7
-rw-r--r--embassy-nrf/src/radio/mod.rs8
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-sync/src/signal.rs5
-rw-r--r--embassy-sync/src/watch.rs4
13 files changed, 70 insertions, 460 deletions
diff --git a/README.md b/README.md
index 383fb6671..669fa469b 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,55 @@
1# Embassy 1# Embassy
2 2
3Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. 3Embassy is the next-generation framework for embedded applications. Write safe, correct, and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries.
4
5## [Documentation](https://embassy.dev/book/index.html) - [API reference](https://docs.embassy.dev/) - [Website](https://embassy.dev/) - [Chat](https://matrix.to/#/#embassy-rs:matrix.org)
4 6
5## <a href="https://embassy.dev/book/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a>
6## Rust + async ❤️ embedded 7## Rust + async ❤️ embedded
7 8
8The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. 9The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector, or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system.
9 10
10Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is <a href="https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown">faster and smaller than one!</a> 11Rust's [async/await](https://rust-lang.github.io/async-book/) allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is [faster and smaller than one!](https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown)
11 12
12## Batteries included 13## Batteries included
13 14
14- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. 15- **Hardware Abstraction Layers
15 - <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families. 16 ** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
16 - <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. 17 - [embassy-stm32](https://docs.embassy.dev/embassy-stm32/), for all STM32 microcontroller families.
17 - <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 and RP23xx microcontrollers. 18 - [embassy-nrf](https://docs.embassy.dev/embassy-nrf/), for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series.
18 - <a href="https://docs.embassy.dev/embassy-mspm0/">embassy-mspm0</a>, for the Texas Instruments MSPM0 microcontrollers. 19 - [embassy-rp](https://docs.embassy.dev/embassy-rp/), for the Raspberry Pi RP2040 and RP23xx microcontrollers.
19 - <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips. 20 - [embassy-mspm0](https://docs.embassy.dev/embassy-mspm0/), for the Texas Instruments MSPM0 microcontrollers.
20 - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. 21 - [esp-rs](https://github.com/esp-rs), for the Espressif Systems ESP32 series of chips.
21 - <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips. 22 - Embassy HAL support for Espressif chips, as well as Async Wi-Fi, Bluetooth, and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
22 - <a href="https://github.com/AlexCharlton/mpfs-hal">mpfs-hal</a>, for the Microchip PolarFire SoC. 23 - [ch32-hal](https://github.com/ch32-rs/ch32-hal), for the WCH 32-bit RISC-V(CH32V) series of chips.
23 - <a href="https://github.com/py32-rs/py32-hal">py32-hal</a>, for the Puya Semiconductor PY32 series of microcontrollers. 24 - [mpfs-hal](https://github.com/AlexCharlton/mpfs-hal), for the Microchip PolarFire SoC.
24 25 - [py32-hal](https://github.com/py32-rs/py32-hal), for the Puya Semiconductor PY32 series of microcontrollers.
25- **Time that Just Works** -
26No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow.
27
28- **Real-time ready** -
29Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities, so that higher priority tasks preempt lower priority ones. See the <a href="https://github.com/embassy-rs/embassy/blob/master/examples/nrf52840/src/bin/multiprio.rs">example</a>.
30
31- **Low-power ready** -
32Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting.
33
34- **Networking** -
35The <a href="https://docs.embassy.dev/embassy-net/">embassy-net</a> network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
36 26
37- **Bluetooth** 27- **Time that Just Works** -
38 - The <a href="https://github.com/embassy-rs/trouble">trouble</a> crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the <a href="https://github.com/embassy-rs/bt-hci">bt-hci</a> traits (currently `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported). 28 No more messing with hardware timers. [embassy_time](https://docs.embassy.dev/embassy-time) provides Instant, Duration, and Timer types that are globally available and never overflow.
39 - The <a href="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. 29
40 - The <a href="https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan">embassy-stm32-wpan</a> crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. 30- **Real-time ready** -
31 Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities so that higher priority tasks preempt lower priority ones. See the [example](https://github.com/embassy-rs/embassy/blob/master/examples/nrf52840/src/bin/multiprio.rs).
41 32
42- **LoRa** - The <a href="https://github.com/lora-rs/lora-rs">lora-rs</a> project provides an async LoRa and LoRaWAN stack that works well on Embassy. 33- **Low-power ready** -
34 Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting.
35
36- **Networking** -
37 The [embassy-net](https://docs.embassy.dev/embassy-net/) network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP, and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
38
39- **Bluetooth**
40 - The [trouble](https://github.com/embassy-rs/trouble) crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the [bt-hci](https://github.com/embassy-rs/bt-hci) traits (currently
41 `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported).
42 - The [nrf-softdevice](https://github.com/embassy-rs/nrf-softdevice) crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
43 - The [embassy-stm32-wpan](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan) crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers.
43 44
44- **USB** - 45- **LoRa** -
45<a href="https://docs.embassy.dev/embassy-usb/">embassy-usb</a> implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. 46 The [lora-rs](https://github.com/lora-rs/lora-rs) project provides an async LoRa and LoRaWAN stack that works well on Embassy.
46 47
47- **Bootloader and DFU** - 48- **USB** -
48<a href="https://github.com/embassy-rs/embassy/tree/master/embassy-boot">embassy-boot</a> is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. 49 [embassy-usb](https://docs.embassy.dev/embassy-usb/) implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
49 50
51- **Bootloader and DFU** -
52 [embassy-boot](https://github.com/embassy-rs/embassy/tree/master/embassy-boot) is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
50 53
51## Sneak peek 54## Sneak peek
52 55
@@ -93,13 +96,15 @@ async fn main(spawner: Spawner) {
93 96
94## Examples 97## Examples
95 98
96Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example: 99Examples are found in the
100`examples/` folder separated by the chip manufacturer they are designed to run on. For example:
97 101
98* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. 102* `examples/nrf52840` run on the
99* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). 103 `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards.
100* `examples/stm32xx` for the various STM32 families. 104* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095).
101* `examples/rp` are for the RP2040 chip. 105* `examples/stm32xx` for the various STM32 families.
102* `examples/std` are designed to run locally on your PC. 106* `examples/rp` are for the RP2040 chip.
107* `examples/std` are designed to run locally on your PC.
103 108
104### Running examples 109### Running examples
105 110
@@ -126,7 +131,7 @@ cargo run --release --bin blinky
126 131
127For more help getting started, see [Getting Started][1] and [Running the Examples][2]. 132For more help getting started, see [Getting Started][1] and [Running the Examples][2].
128 133
129## Developing Embassy with Rust Analyzer based editors 134## Developing Embassy with Rust Analyzer-based editors
130 135
131The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/) 136The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/)
132and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer 137and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer
@@ -136,7 +141,7 @@ please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects
136## Minimum supported Rust version (MSRV) 141## Minimum supported Rust version (MSRV)
137 142
138Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might* 143Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might*
139compile with older versions but that may change in any new patch release. 144compile with older versions, but that may change in any new patch release.
140 145
141## Why the name? 146## Why the name?
142 147
diff --git a/docs/examples/basic/.cargo/config.toml b/docs/examples/basic/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/docs/examples/basic/.cargo/config.toml
+++ b/docs/examples/basic/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/docs/examples/layer-by-layer/.cargo/config.toml b/docs/examples/layer-by-layer/.cargo/config.toml
index 3012f05dc..f30d9e446 100644
--- a/docs/examples/layer-by-layer/.cargo/config.toml
+++ b/docs/examples/layer-by-layer/.cargo/config.toml
@@ -1,5 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip STM32L475VG" 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32L475VG"
3 4
4rustflags = [ 5rustflags = [
5 "-C", "link-arg=--nmagic", 6 "-C", "link-arg=--nmagic",
diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc
index 954f3fd28..d1f65a885 100644
--- a/docs/pages/getting_started.adoc
+++ b/docs/pages/getting_started.adoc
@@ -66,7 +66,7 @@ If everything worked correctly, you should see a blinking LED on your board, and
66[source] 66[source]
67---- 67----
68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s 68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
69 Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky` 69 Running `probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky`
70(HOST) INFO flashing program (71.36 KiB) 70(HOST) INFO flashing program (71.36 KiB)
71(HOST) INFO success! 71(HOST) INFO success!
72──────────────────────────────────────────────────────────────────────────────── 72────────────────────────────────────────────────────────────────────────────────
diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc
index af1cb75c5..cd943b4f6 100644
--- a/docs/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -150,7 +150,7 @@ stm32g474-example
150# Before upgrading check that everything is available on all tier1 targets here: 150# Before upgrading check that everything is available on all tier1 targets here:
151# https://rust-lang.github.io/rustup-components-history 151# https://rust-lang.github.io/rustup-components-history
152[toolchain] 152[toolchain]
153channel = "nightly-2023-11-01" 153channel = "1.85"
154components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 154components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
155targets = ["thumbv7em-none-eabi"] 155targets = ["thumbv7em-none-eabi"]
156---- 156----
diff --git a/docs/pages/project_structure.adoc b/docs/pages/project_structure.adoc
index 722ec8d9d..227508b97 100644
--- a/docs/pages/project_structure.adoc
+++ b/docs/pages/project_structure.adoc
@@ -85,9 +85,9 @@ A minimal example:
85[source,toml] 85[source,toml]
86---- 86----
87[toolchain] 87[toolchain]
88channel = "nightly-2023-08-19" # <- as of writing, this is the exact rust version embassy uses 88channel = "1.85" # <- as of writing, this is the exact rust version embassy uses
89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size" 89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size"
90targets = [ 90targets = [
91 "thumbv6m-none-eabi" # <-change for your platform 91 "thumbv6m-none-eabi" # <- change for your platform
92] 92]
93---- 93----
diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md
index cfee5f3cf..8773772ce 100644
--- a/embassy-net/CHANGELOG.md
+++ b/embassy-net/CHANGELOG.md
@@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9 9
10No unreleased changes yet... Quick, go send a PR! 10No unreleased changes yet... Quick, go send a PR!
11 11
12## 0.7 - 2025-02-14 12## 0.7 - 2025-05-06
13 13
14- don't infinite loop if udp::send methods receive a buffer too large to ever be sent 14- don't infinite loop if udp::send methods receive a buffer too large to ever be sent
15- add ICMP sockets and a ping utility 15- add ICMP sockets and a ping utility
16- configurable rate_limit for the ping utility
17- Feature match udp sockets
16 18
17## 0.6 - 2025-01-05 19## 0.6 - 2025-01-05
18 20
diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs
deleted file mode 100644
index d42bbe5f6..000000000
--- a/embassy-nrf/src/radio/ble.rs
+++ /dev/null
@@ -1,394 +0,0 @@
1//! Radio driver implementation focused on Bluetooth Low-Energy transmission.
2
3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::Poll;
6
7use embassy_hal_internal::drop::OnDrop;
8pub use pac::radio::vals::Mode;
9#[cfg(not(feature = "_nrf51"))]
10use pac::radio::vals::Plen as PreambleLength;
11
12use crate::interrupt::typelevel::Interrupt;
13use crate::pac::radio::vals;
14use crate::radio::*;
15pub use crate::radio::{Error, TxPower};
16use crate::util::slice_in_ram_or;
17use crate::Peri;
18
19/// Radio driver.
20pub struct Radio<'d, T: Instance> {
21 _p: Peri<'d, T>,
22}
23
24impl<'d, T: Instance> Radio<'d, T> {
25 /// Create a new radio driver.
26 pub fn new(
27 radio: Peri<'d, T>,
28 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
29 ) -> Self {
30 let r = T::regs();
31
32 r.pcnf1().write(|w| {
33 // It is 0 bytes long in a standard BLE packet
34 w.set_statlen(0);
35 // MaxLen configures the maximum packet payload plus add-on size in
36 // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure
37 // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means
38 // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a
39 // packet larger than MAXLEN, the payload will be truncated at MAXLEN
40 //
41 // To simplify the implementation, It is setted as the maximum value
42 // and the length of the packet is controlled only by the LENGTH field in the packet
43 w.set_maxlen(255);
44 // Configure the length of the address field in the packet
45 // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address
46 // The base address is truncated from the least significant byte if the BALEN is less than 4
47 //
48 // BLE address is always 4 bytes long
49 w.set_balen(3); // 3 bytes base address (+ 1 prefix);
50 // Configure the endianess
51 // For BLE is always little endian (LSB first)
52 w.set_endian(vals::Endian::LITTLE);
53 // Data whitening is used to avoid long sequences of zeros or
54 // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream.
55 // The whitener and de-whitener are defined the same way,
56 // using a 7-bit linear feedback shift register with the
57 // polynomial x7 + x4 + 1.
58 //
59 // In BLE Whitening shall be applied on the PDU and CRC of all
60 // Link Layer packets and is performed after the CRC generation
61 // in the transmitter. No other parts of the packets are whitened.
62 // De-whitening is performed before the CRC checking in the receiver
63 // Before whitening or de-whitening, the shift register should be
64 // initialized based on the channel index.
65 w.set_whiteen(true);
66 });
67
68 // Configure CRC
69 r.crccnf().write(|w| {
70 // In BLE the CRC shall be calculated on the PDU of all Link Layer
71 // packets (even if the packet is encrypted).
72 // It skips the address field
73 w.set_skipaddr(vals::Skipaddr::SKIP);
74 // In BLE 24-bit CRC = 3 bytes
75 w.set_len(vals::Len::THREE);
76 });
77
78 // Ch map between 2400 MHZ .. 2500 MHz
79 // All modes use this range
80 #[cfg(not(feature = "_nrf51"))]
81 r.frequency().write(|w| w.set_map(vals::Map::DEFAULT));
82
83 // Configure shortcuts to simplify and speed up sending and receiving packets.
84 r.shorts().write(|w| {
85 // start transmission/recv immediately after ramp-up
86 // disable radio when transmission/recv is done
87 w.set_ready_start(true);
88 w.set_end_disable(true);
89 });
90
91 // Enable NVIC interrupt
92 T::Interrupt::unpend();
93 unsafe { T::Interrupt::enable() };
94
95 Self { _p: radio }
96 }
97
98 fn state(&self) -> RadioState {
99 super::state(T::regs())
100 }
101
102 /// Set the radio mode
103 ///
104 /// The radio must be disabled before calling this function
105 pub fn set_mode(&mut self, mode: Mode) {
106 assert!(self.state() == RadioState::DISABLED);
107
108 let r = T::regs();
109 r.mode().write(|w| w.set_mode(mode));
110
111 #[cfg(not(feature = "_nrf51"))]
112 r.pcnf0().write(|w| {
113 w.set_plen(match mode {
114 Mode::BLE_1MBIT => PreambleLength::_8BIT,
115 Mode::BLE_2MBIT => PreambleLength::_16BIT,
116 #[cfg(any(
117 feature = "nrf52811",
118 feature = "nrf52820",
119 feature = "nrf52833",
120 feature = "nrf52840",
121 feature = "_nrf5340-net"
122 ))]
123 Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE,
124 _ => unimplemented!(),
125 })
126 });
127 }
128
129 /// Set the header size changing the S1's len field
130 ///
131 /// The radio must be disabled before calling this function
132 pub fn set_header_expansion(&mut self, use_s1_field: bool) {
133 assert!(self.state() == RadioState::DISABLED);
134
135 let r = T::regs();
136
137 // s1 len in bits
138 let s1len: u8 = match use_s1_field {
139 false => 0,
140 true => 8,
141 };
142
143 r.pcnf0().write(|w| {
144 // Configure S0 to 1 byte length, this will represent the Data/Adv header flags
145 w.set_s0len(true);
146 // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload
147 // and also be used to know how many bytes to read/write from/to the buffer
148 w.set_lflen(0);
149 // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE.
150 w.set_s1len(s1len);
151 });
152 }
153
154 /// Set initial data whitening value
155 /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream
156 /// On BLE the initial value is the channel index | 0x40
157 ///
158 /// The radio must be disabled before calling this function
159 pub fn set_whitening_init(&mut self, whitening_init: u8) {
160 assert!(self.state() == RadioState::DISABLED);
161
162 let r = T::regs();
163
164 r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init));
165 }
166
167 /// Set the central frequency to be used
168 /// It should be in the range 2400..2500
169 ///
170 /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change)
171 pub fn set_frequency(&mut self, frequency: u32) {
172 assert!(self.state() == RadioState::DISABLED);
173 assert!((2400..=2500).contains(&frequency));
174
175 let r = T::regs();
176
177 r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8));
178 }
179
180 /// Set the acess address
181 /// This address is always constants for advertising
182 /// And a random value generate on each connection
183 /// It is used to filter the packages
184 ///
185 /// The radio must be disabled before calling this function
186 pub fn set_access_address(&mut self, access_address: u32) {
187 assert!(self.state() == RadioState::DISABLED);
188
189 let r = T::regs();
190
191 // Configure logical address
192 // The byte ordering on air is always least significant byte first for the address
193 // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA
194 // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA
195 r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8));
196
197 // The base address is truncated from the least significant byte (because the BALEN is less than 4)
198 // So it shifts the address to the right
199 r.base0().write_value(access_address << 8);
200
201 // Don't match tx address
202 r.txaddress().write(|w| w.set_txaddress(0));
203
204 // Match on logical address
205 // This config only filter the packets by the address,
206 // so only packages send to the previous address
207 // will finish the reception (TODO: check the explanation)
208 r.rxaddresses().write(|w| {
209 w.set_addr0(true);
210 w.set_addr1(true);
211 w.set_addr2(true);
212 w.set_addr3(true);
213 w.set_addr4(true);
214 });
215 }
216
217 /// Set the CRC polynomial
218 /// It only uses the 24 least significant bits
219 ///
220 /// The radio must be disabled before calling this function
221 pub fn set_crc_poly(&mut self, crc_poly: u32) {
222 assert!(self.state() == RadioState::DISABLED);
223
224 let r = T::regs();
225
226 r.crcpoly().write(|w| {
227 // Configure the CRC polynomial
228 // Each term in the CRC polynomial is mapped to a bit in this
229 // register which index corresponds to the term's exponent.
230 // The least significant term/bit is hard-wired internally to
231 // 1, and bit number 0 of the register content is ignored by
232 // the hardware. The following example is for an 8 bit CRC
233 // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 .
234 w.set_crcpoly(crc_poly & 0xFFFFFF)
235 });
236 }
237
238 /// Set the CRC init value
239 /// It only uses the 24 least significant bits
240 /// The CRC initial value varies depending of the PDU type
241 ///
242 /// The radio must be disabled before calling this function
243 pub fn set_crc_init(&mut self, crc_init: u32) {
244 assert!(self.state() == RadioState::DISABLED);
245
246 let r = T::regs();
247
248 r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF));
249 }
250
251 /// Set the radio tx power
252 ///
253 /// The radio must be disabled before calling this function
254 pub fn set_tx_power(&mut self, tx_power: TxPower) {
255 assert!(self.state() == RadioState::DISABLED);
256
257 let r = T::regs();
258
259 r.txpower().write(|w| w.set_txpower(tx_power));
260 }
261
262 /// Set buffer to read/write
263 ///
264 /// This method is unsound. You should guarantee that the buffer will live
265 /// for the life time of the transmission or if the buffer will be modified.
266 /// Also if the buffer is smaller than the packet length, the radio will
267 /// read/write memory out of the buffer bounds.
268 fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
269 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
270
271 let r = T::regs();
272
273 // Here it consider that the length of the packet is
274 // correctly set in the buffer, otherwise it will send
275 // unowned regions of memory
276 let ptr = buffer.as_ptr();
277
278 // Configure the payload
279 r.packetptr().write_value(ptr as u32);
280
281 Ok(())
282 }
283
284 /// Send packet
285 /// If the length byte in the package is greater than the buffer length
286 /// the radio will read memory out of the buffer bounds
287 pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> {
288 self.set_buffer(buffer)?;
289
290 let r = T::regs();
291 self.trigger_and_wait_end(move || {
292 // Initialize the transmission
293 // trace!("txen");
294
295 r.tasks_txen().write_value(1);
296 })
297 .await;
298
299 Ok(())
300 }
301
302 /// Receive packet
303 /// If the length byte in the received package is greater than the buffer length
304 /// the radio will write memory out of the buffer bounds
305 pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
306 self.set_buffer(buffer)?;
307
308 let r = T::regs();
309 self.trigger_and_wait_end(move || {
310 // Initialize the transmission
311 // trace!("rxen");
312 r.tasks_rxen().write_value(1);
313 })
314 .await;
315
316 Ok(())
317 }
318
319 async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) {
320 let r = T::regs();
321 let s = T::state();
322
323 // If the Future is dropped before the end of the transmission
324 // it disable the interrupt and stop the transmission
325 // to keep the state consistent
326 let drop = OnDrop::new(|| {
327 trace!("radio drop: stopping");
328
329 r.intenclr().write(|w| w.set_end(true));
330
331 r.tasks_stop().write_value(1);
332
333 r.events_end().write_value(0);
334
335 trace!("radio drop: stopped");
336 });
337
338 // trace!("radio:enable interrupt");
339 // Clear some remnant side-effects (TODO: check if this is necessary)
340 r.events_end().write_value(0);
341
342 // Enable interrupt
343 r.intenset().write(|w| w.set_end(true));
344
345 compiler_fence(Ordering::SeqCst);
346
347 // Trigger the transmission
348 trigger();
349
350 // On poll check if interrupt happen
351 poll_fn(|cx| {
352 s.event_waker.register(cx.waker());
353 if r.events_end().read() == 1 {
354 // trace!("radio:end");
355 return core::task::Poll::Ready(());
356 }
357 Poll::Pending
358 })
359 .await;
360
361 compiler_fence(Ordering::SeqCst);
362 r.events_end().write_value(0); // ACK
363
364 // Everthing ends fine, so it disable the drop
365 drop.defuse();
366 }
367
368 /// Disable the radio
369 fn disable(&mut self) {
370 let r = T::regs();
371
372 compiler_fence(Ordering::SeqCst);
373 // If it is already disabled, do nothing
374 if self.state() != RadioState::DISABLED {
375 trace!("radio:disable");
376 // Trigger the disable task
377 r.tasks_disable().write_value(1);
378
379 // Wait until the radio is disabled
380 while r.events_disabled().read() == 0 {}
381
382 compiler_fence(Ordering::SeqCst);
383
384 // Acknowledge it
385 r.events_disabled().write_value(0);
386 }
387 }
388}
389
390impl<'d, T: Instance> Drop for Radio<'d, T> {
391 fn drop(&mut self) {
392 self.disable();
393 }
394}
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
index 2f0bcbe04..7f4f8f462 100644
--- a/embassy-nrf/src/radio/ieee802154.rs
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -5,10 +5,11 @@ use core::task::Poll;
5 5
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7 7
8use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; 8use super::{Error, Instance, InterruptHandler, TxPower};
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::interrupt::{self}; 10use crate::interrupt::{self};
11use crate::pac::radio::vals; 11use crate::pac::radio::vals;
12pub use crate::pac::radio::vals::State as RadioState;
12use crate::Peri; 13use crate::Peri;
13 14
14/// Default (IEEE compliant) Start of Frame Delimiter 15/// Default (IEEE compliant) Start of Frame Delimiter
@@ -200,7 +201,7 @@ impl<'d, T: Instance> Radio<'d, T> {
200 201
201 /// Get the current radio state 202 /// Get the current radio state
202 fn state(&self) -> RadioState { 203 fn state(&self) -> RadioState {
203 state(T::regs()) 204 T::regs().state().read().state()
204 } 205 }
205 206
206 /// Moves the radio from any state to the DISABLED state 207 /// Moves the radio from any state to the DISABLED state
@@ -293,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> {
293 r.shorts().write(|_| {}); 294 r.shorts().write(|_| {});
294 r.tasks_stop().write_value(1); 295 r.tasks_stop().write_value(1);
295 loop { 296 loop {
296 match state(r) { 297 match r.state().read().state() {
297 RadioState::DISABLED | RadioState::RX_IDLE => break, 298 RadioState::DISABLED | RadioState::RX_IDLE => break,
298 _ => (), 299 _ => (),
299 } 300 }
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
index 982436266..608ef9024 100644
--- a/embassy-nrf/src/radio/mod.rs
+++ b/embassy-nrf/src/radio/mod.rs
@@ -6,7 +6,6 @@
6#![macro_use] 6#![macro_use]
7 7
8/// Bluetooth Low Energy Radio driver. 8/// Bluetooth Low Energy Radio driver.
9pub mod ble;
10#[cfg(any( 9#[cfg(any(
11 feature = "nrf52811", 10 feature = "nrf52811",
12 feature = "nrf52820", 11 feature = "nrf52820",
@@ -21,7 +20,6 @@ use core::marker::PhantomData;
21 20
22use embassy_hal_internal::PeripheralType; 21use embassy_hal_internal::PeripheralType;
23use embassy_sync::waitqueue::AtomicWaker; 22use embassy_sync::waitqueue::AtomicWaker;
24use pac::radio::vals::State as RadioState;
25pub use pac::radio::vals::Txpower as TxPower; 23pub use pac::radio::vals::Txpower as TxPower;
26 24
27use crate::{interrupt, pac}; 25use crate::{interrupt, pac};
@@ -82,6 +80,7 @@ macro_rules! impl_radio {
82 pac::$pac_type 80 pac::$pac_type
83 } 81 }
84 82
83 #[allow(unused)]
85 fn state() -> &'static crate::radio::State { 84 fn state() -> &'static crate::radio::State {
86 static STATE: crate::radio::State = crate::radio::State::new(); 85 static STATE: crate::radio::State = crate::radio::State::new();
87 &STATE 86 &STATE
@@ -99,8 +98,3 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
99 /// Interrupt for this peripheral. 98 /// Interrupt for this peripheral.
100 type Interrupt: interrupt::typelevel::Interrupt; 99 type Interrupt: interrupt::typelevel::Interrupt;
101} 100}
102
103/// Get the state of the radio
104pub(crate) fn state(radio: pac::radio::Radio) -> RadioState {
105 radio.state().read().state()
106}
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index 08dba04fe..9c42217f0 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -223,7 +223,7 @@ impl<'d, T: Instance> Spdifrx<'d, T> {
223 }; 223 };
224 224
225 for sample in data.as_mut() { 225 for sample in data.as_mut() {
226 if (*sample & (0x0002_u32)) == 0x0001 { 226 if (*sample & (0x0002_u32)) != 0 {
227 // Discard invalid samples, setting them to mute level. 227 // Discard invalid samples, setting them to mute level.
228 *sample = 0; 228 *sample = 0;
229 } else { 229 } else {
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index a0f4b5a74..e7095401e 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker};
6use crate::blocking_mutex::raw::RawMutex; 6use crate::blocking_mutex::raw::RawMutex;
7use crate::blocking_mutex::Mutex; 7use crate::blocking_mutex::Mutex;
8 8
9/// Single-slot signaling primitive. 9/// Single-slot signaling primitive for a _single_ consumer.
10/// 10///
11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except 11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
12/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead 12/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead
@@ -17,6 +17,7 @@ use crate::blocking_mutex::Mutex;
17/// updates. 17/// updates.
18/// 18///
19/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead. 19/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead.
20/// For multiple consumers, use [`Watch`](crate::watch::Watch) instead.
20/// 21///
21/// Signals are generally declared as `static`s and then borrowed as required. 22/// Signals are generally declared as `static`s and then borrowed as required.
22/// 23///
@@ -106,7 +107,7 @@ where
106 }) 107 })
107 } 108 }
108 109
109 /// Future that completes when this Signal has been signaled. 110 /// Future that completes when this Signal has been signaled, taking the value out of the signal.
110 pub fn wait(&self) -> impl Future<Output = T> + '_ { 111 pub fn wait(&self) -> impl Future<Output = T> + '_ {
111 poll_fn(move |cx| self.poll_wait(cx)) 112 poll_fn(move |cx| self.poll_wait(cx))
112 } 113 }
diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs
index e76646c0b..08d6a833d 100644
--- a/embassy-sync/src/watch.rs
+++ b/embassy-sync/src/watch.rs
@@ -10,7 +10,7 @@ use crate::blocking_mutex::raw::RawMutex;
10use crate::blocking_mutex::Mutex; 10use crate::blocking_mutex::Mutex;
11use crate::waitqueue::MultiWakerRegistration; 11use crate::waitqueue::MultiWakerRegistration;
12 12
13/// The `Watch` is a single-slot signaling primitive that allows multiple receivers to concurrently await 13/// The `Watch` is a single-slot signaling primitive that allows _multiple_ (`N`) receivers to concurrently await
14/// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers, 14/// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers,
15/// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous 15/// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous
16/// value when a new one is sent, without waiting for all receivers to read the previous value. 16/// value when a new one is sent, without waiting for all receivers to read the previous value.
@@ -298,7 +298,7 @@ impl<M: RawMutex, T: Clone, const N: usize> WatchBehavior<T> for Watch<M, T, N>
298} 298}
299 299
300impl<M: RawMutex, T: Clone, const N: usize> Watch<M, T, N> { 300impl<M: RawMutex, T: Clone, const N: usize> Watch<M, T, N> {
301 /// Create a new `Watch` channel. 301 /// Create a new `Watch` channel for `N` receivers.
302 pub const fn new() -> Self { 302 pub const fn new() -> Self {
303 Self { 303 Self {
304 mutex: Mutex::new(RefCell::new(WatchState { 304 mutex: Mutex::new(RefCell::new(WatchState {