Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c0d3507
bump cortex-ar to v0.3
robamu Oct 2, 2025
e4e06ab
Merge pull request #4730 from robamu/bump-allowed-cortex-ar-range
Dirbaio Oct 2, 2025
99ec241
Add Air Quality Monitor project to Embassy in the Wild page
1-rafael-1 Oct 4, 2025
b73f8f1
Merge pull request #4739 from 1-rafael-1/embassy-in-the-wild-air-qual…
lulf Oct 5, 2025
c0fd86d
nrf: apply FICR.TRIMCNF values
0e4ef622 Oct 5, 2025
e2a2bd3
Merge pull request #4741 from 0e4ef622/nrf-trimcnf
Dirbaio Oct 5, 2025
ac2628b
Add some logging to the USB interrupt handler
bschwind Sep 8, 2025
cd69344
WIP: implement USB OUT bulk transfers using OTG-FS's DMA
goodhoko Sep 5, 2025
9649960
Add a separate read_with_dma function for EndpointOut
bschwind Sep 8, 2025
147d9df
Make some progress on control setup DMA stuff
bschwind Sep 9, 2025
9e2f856
WIP for USB DMA continues
bschwind Sep 9, 2025
ef1687d
Format the file with vscode
goodhoko Sep 10, 2025
0e59be2
Make the EndpointOut::read() work with DMA
goodhoko Sep 10, 2025
64d12c9
Cleanup
goodhoko Sep 10, 2025
dec0069
Always configure at least one packet for the OUT transfer
goodhoko Sep 10, 2025
2851469
Comment out code that is not used anyway
goodhoko Sep 10, 2025
69ee83b
Fix couple bugs, add logs, etc.
goodhoko Sep 10, 2025
ab9b16f
Make it work maybe?
goodhoko Sep 10, 2025
f3751e2
Make the OTG_HS go brrrr
bschwind Sep 11, 2025
e1d3c4c
Compute the correct number of packets to receive
goodhoko Sep 11, 2025
a69e6bd
Removed unused field and a const
goodhoko Sep 12, 2025
b8f84bd
Remove unused out_buffer
goodhoko Sep 12, 2025
b3102fd
Remove more unused code and TODO that is done
goodhoko Sep 12, 2025
55e37a4
Remove code that's commented out
goodhoko Sep 12, 2025
9bb53b9
Remove needless atomic buffer for handing over SETUP packet data
goodhoko Sep 12, 2025
e126c4a
Fix typo
goodhoko Sep 12, 2025
43d2a39
Improve comments, remove needless logging, document a TODO
goodhoko Sep 12, 2025
c8e7a72
Remove unused code (fix cargo check warning)
goodhoko Sep 18, 2025
a50e7e1
Remove excessive usb logging
goodhoko Sep 24, 2025
21d4ea1
Remove the check for a 'divisible-by-4' buffer size, it was incorrect
bschwind Sep 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/pages/embassy_in_the_wild.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ Here are known examples of real-world projects which make use of Embassy. Feel f

_newer entries at the top_

* link:https://github.com/1-rafael-1/air-quality-monitor[Air Quality Monitor]
** Air Quality Monitor based on rp2350 board, ens160 and aht21 sensors and ssd1306 display. Code and 3D printable enclosure included.
* link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation]
** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details.
* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2]
** A hobbyist project building a tracked robot with basic autonomous and manual drive mode.
* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files.
* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
** Targets STM32, RP2040, nRF52 and ESP32 MCUs
* link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware]
** Targets some STM32 MCUs
Expand All @@ -21,10 +23,9 @@ _newer entries at the top_
* link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system]
** Targets nRF52 and uses nrf-softdevice

* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop
* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop
firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are:
** biopotentials (analog ports)
** motion capture (6-axis accelerometers)
** air quality (CO2, Temp, Humidity)
** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]]

1 change: 1 addition & 0 deletions embassy-executor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upgraded rtos-trace
- Added optional "highest priority" scheduling
- Added optional "earliest deadline first" EDF scheduling
- Bump `cortex-ar` to v0.3

## 0.9.1 - 2025-08-31

Expand Down
2 changes: 1 addition & 1 deletion embassy-executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ portable-atomic = { version = "1.5", optional = true }
cortex-m = { version = "0.7.6", optional = true }

# arch-cortex-ar dependencies
cortex-ar = { version = "0.2", optional = true }
cortex-ar = { version = "0.3", optional = true }

# arch-wasm dependencies
wasm-bindgen = { version = "0.2.82", optional = true }
Expand Down
1 change: 1 addition & 0 deletions embassy-nrf/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- next-header -->
## Unreleased - ReleaseDate
- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l

## 0.8.0 - 2025-09-30

Expand Down
1 change: 1 addition & 0 deletions embassy-nrf/src/chips/nrf54l15_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub mod pac {
#[cfg(feature = "_s")]
#[doc(no_inline)]
pub use nrf_pac::{
FICR_NS as FICR,
SICR_S as SICR,
ICACHEDATA_S as ICACHEDATA,
ICACHEINFO_S as ICACHEINFO,
Expand Down
64 changes: 51 additions & 13 deletions embassy-nrf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,16 +406,19 @@ pub mod config {
/// Settings for the internal capacitors.
#[cfg(feature = "nrf5340-app-s")]
pub struct InternalCapacitors {
/// Config for the internal capacitors on pins XC1 and XC2.
/// Config for the internal capacitors on pins XC1 and XC2. Pass `None` to not touch it.
pub hfxo: Option<HfxoCapacitance>,
/// Config for the internal capacitors between pins XL1 and XL2.
/// Config for the internal capacitors between pins XL1 and XL2. Pass `None` to not touch
/// it.
pub lfxo: Option<LfxoCapacitance>,
}

/// Internal capacitance value for the HFXO.
#[cfg(feature = "nrf5340-app-s")]
#[derive(Copy, Clone)]
pub enum HfxoCapacitance {
/// Use external capacitors
External,
/// 7.0 pF
_7_0pF,
/// 7.5 pF
Expand Down Expand Up @@ -475,8 +478,9 @@ pub mod config {
#[cfg(feature = "nrf5340-app-s")]
impl HfxoCapacitance {
/// The capacitance value times two.
pub(crate) const fn value2(self) -> i32 {
pub(crate) fn value2(self) -> i32 {
match self {
HfxoCapacitance::External => unreachable!(),
HfxoCapacitance::_7_0pF => 14,
HfxoCapacitance::_7_5pF => 15,
HfxoCapacitance::_8_0pF => 16,
Expand Down Expand Up @@ -506,11 +510,17 @@ pub mod config {
HfxoCapacitance::_20_0pF => 40,
}
}

pub(crate) fn external(self) -> bool {
matches!(self, Self::External)
}
}

/// Internal capacitance value for the LFXO.
#[cfg(feature = "nrf5340-app-s")]
pub enum LfxoCapacitance {
/// Use external capacitors
External = 0,
/// 6 pF
_6pF = 1,
/// 7 pF
Expand All @@ -523,6 +533,7 @@ pub mod config {
impl From<LfxoCapacitance> for super::pac::oscillators::vals::Intcap {
fn from(t: LfxoCapacitance) -> Self {
match t {
LfxoCapacitance::External => Self::EXTERNAL,
LfxoCapacitance::_6pF => Self::C6PF,
LfxoCapacitance::_7pF => Self::C7PF,
LfxoCapacitance::_9pF => Self::C9PF,
Expand Down Expand Up @@ -720,6 +731,29 @@ pub fn init(config: config::Config) -> Peripherals {
}
}

// Apply trimming values from the FICR.
#[cfg(any(
all(feature = "_nrf5340-app", feature = "_s"),
all(feature = "_nrf54l", feature = "_s"),
feature = "_nrf5340-net",
))]
{
#[cfg(feature = "_nrf5340")]
let n = 32;
#[cfg(feature = "_nrf54l")]
let n = 64;
for i in 0..n {
let info = pac::FICR.trimcnf(i);
let addr = info.addr().read();
if addr == 0 || addr == 0xFFFF_FFFF {
break;
}
unsafe {
(addr as *mut u32).write_volatile(info.data().read());
}
}
}

// GLITCHDET is only accessible for secure code
#[cfg(all(feature = "_nrf54l", feature = "_s"))]
{
Expand Down Expand Up @@ -953,17 +987,21 @@ pub fn init(config: config::Config) -> Peripherals {
#[cfg(feature = "nrf5340-app-s")]
{
if let Some(cap) = config.internal_capacitors.hfxo {
let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32;
let offset = pac::FICR.xosc32mtrim().read().offset() as i32;
// slope is a signed 5-bit integer
if slope >= 16 {
slope -= 32;
if cap.external() {
pac::OSCILLATORS.xosc32mcaps().write(|w| w.set_enable(false));
} else {
let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32;
let offset = pac::FICR.xosc32mtrim().read().offset() as i32;
// slope is a signed 5-bit integer
if slope >= 16 {
slope -= 32;
}
let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6;
pac::OSCILLATORS.xosc32mcaps().write(|w| {
w.set_capvalue(capvalue as u8);
w.set_enable(true);
});
}
let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6;
pac::OSCILLATORS.xosc32mcaps().write(|w| {
w.set_capvalue(capvalue as u8);
w.set_enable(true);
});
}
if let Some(cap) = config.internal_capacitors.lfxo {
pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into()));
Expand Down
17 changes: 17 additions & 0 deletions embassy-nrf/src/radio/ieee802154.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ impl<'d> Radio<'d> {
// Disable and enable to reset peripheral
r.power().write(|w| w.set_power(false));
r.power().write(|w| w.set_power(true));
errata::post_power();

// Enable 802.15.4 mode
r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT));
Expand Down Expand Up @@ -541,3 +542,19 @@ fn dma_start_fence() {
fn dma_end_fence() {
compiler_fence(Ordering::Acquire);
}

mod errata {
pub fn post_power() {
// Workaround for anomaly 158
#[cfg(feature = "_nrf5340-net")]
for i in 0..32 {
let info = crate::pac::FICR.trimcnf(i);
let addr = info.addr().read();
if addr & 0xFFFF_F000 == crate::pac::RADIO.as_ptr() as u32 {
unsafe {
(addr as *mut u32).write_volatile(info.data().read());
}
}
}
}
}
40 changes: 6 additions & 34 deletions embassy-stm32/src/usb/otg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
unsafe fn on_interrupt() {
let r = T::regs();
let state = T::state();
on_interrupt_impl(r, state, T::ENDPOINT_COUNT);
on_interrupt_impl(r, state);
}
}

Expand All @@ -44,7 +44,7 @@ macro_rules! config_ulpi_pins {
// This calculation doesn't correspond to one in a Reference Manual.
// In fact, the required number of words is higher than indicated in RM.
// The following numbers are pessimistic and were figured out empirically.
const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 30;
const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 256;

/// USB driver.
pub struct Driver<'d, T: Instance> {
Expand All @@ -54,18 +54,11 @@ pub struct Driver<'d, T: Instance> {

impl<'d, T: Instance> Driver<'d, T> {
/// Initializes USB OTG peripheral with internal Full-Speed PHY.
///
/// # Arguments
///
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_fs(
_peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dp: Peri<'d, impl DpPin<T>>,
dm: Peri<'d, impl DmPin<T>>,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
set_as_af!(dp, AfType::output(OutputType::PushPull, Speed::VeryHigh));
Expand All @@ -84,24 +77,17 @@ impl<'d, T: Instance> Driver<'d, T> {
};

Self {
inner: OtgDriver::new(ep_out_buffer, instance, config),
inner: OtgDriver::new(instance, config),
phantom: PhantomData,
}
}

/// Initializes USB OTG peripheral with internal High-Speed PHY.
///
/// # Arguments
///
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_hs(
_peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_dp: Peri<'d, impl DpPin<T>>,
_dm: Peri<'d, impl DmPin<T>>,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
// For STM32U5 High speed pins need to be left in analog mode
Expand All @@ -122,18 +108,12 @@ impl<'d, T: Instance> Driver<'d, T> {
};

Self {
inner: OtgDriver::new(ep_out_buffer, instance, config),
inner: OtgDriver::new(instance, config),
phantom: PhantomData,
}
}

/// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
///
/// # Arguments
///
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_fs_ulpi(
_peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
Expand All @@ -149,7 +129,6 @@ impl<'d, T: Instance> Driver<'d, T> {
ulpi_d5: Peri<'d, impl UlpiD5Pin<T>>,
ulpi_d6: Peri<'d, impl UlpiD6Pin<T>>,
ulpi_d7: Peri<'d, impl UlpiD7Pin<T>>,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
config_ulpi_pins!(
Expand All @@ -168,18 +147,12 @@ impl<'d, T: Instance> Driver<'d, T> {
};

Self {
inner: OtgDriver::new(ep_out_buffer, instance, config),
inner: OtgDriver::new(instance, config),
phantom: PhantomData,
}
}

/// Initializes USB OTG peripheral with external High-Speed PHY.
///
/// # Arguments
///
/// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_hs_ulpi(
_peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
Expand All @@ -195,7 +168,6 @@ impl<'d, T: Instance> Driver<'d, T> {
ulpi_d5: Peri<'d, impl UlpiD5Pin<T>>,
ulpi_d6: Peri<'d, impl UlpiD6Pin<T>>,
ulpi_d7: Peri<'d, impl UlpiD7Pin<T>>,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
Expand All @@ -216,7 +188,7 @@ impl<'d, T: Instance> Driver<'d, T> {
};

Self {
inner: OtgDriver::new(ep_out_buffer, instance, config),
inner: OtgDriver::new(instance, config),
phantom: PhantomData,
}
}
Expand Down
Loading