Skip to content

Commit e2a2bd3

Browse files
authored
Merge pull request #4741 from 0e4ef622/nrf-trimcnf
nrf: apply FICR.TRIMCNF values
2 parents b73f8f1 + c0fd86d commit e2a2bd3

File tree

5 files changed

+100
-13
lines changed

5 files changed

+100
-13
lines changed

embassy-nrf/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

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

1112
## 0.8.0 - 2025-09-30
1213

embassy-nrf/src/chips/nrf54l15_app.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub mod pac {
9494
#[cfg(feature = "_s")]
9595
#[doc(no_inline)]
9696
pub use nrf_pac::{
97+
FICR_NS as FICR,
9798
SICR_S as SICR,
9899
ICACHEDATA_S as ICACHEDATA,
99100
ICACHEINFO_S as ICACHEINFO,

embassy-nrf/src/lib.rs

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -406,16 +406,19 @@ pub mod config {
406406
/// Settings for the internal capacitors.
407407
#[cfg(feature = "nrf5340-app-s")]
408408
pub struct InternalCapacitors {
409-
/// Config for the internal capacitors on pins XC1 and XC2.
409+
/// Config for the internal capacitors on pins XC1 and XC2. Pass `None` to not touch it.
410410
pub hfxo: Option<HfxoCapacitance>,
411-
/// Config for the internal capacitors between pins XL1 and XL2.
411+
/// Config for the internal capacitors between pins XL1 and XL2. Pass `None` to not touch
412+
/// it.
412413
pub lfxo: Option<LfxoCapacitance>,
413414
}
414415

415416
/// Internal capacitance value for the HFXO.
416417
#[cfg(feature = "nrf5340-app-s")]
417418
#[derive(Copy, Clone)]
418419
pub enum HfxoCapacitance {
420+
/// Use external capacitors
421+
External,
419422
/// 7.0 pF
420423
_7_0pF,
421424
/// 7.5 pF
@@ -475,8 +478,9 @@ pub mod config {
475478
#[cfg(feature = "nrf5340-app-s")]
476479
impl HfxoCapacitance {
477480
/// The capacitance value times two.
478-
pub(crate) const fn value2(self) -> i32 {
481+
pub(crate) fn value2(self) -> i32 {
479482
match self {
483+
HfxoCapacitance::External => unreachable!(),
480484
HfxoCapacitance::_7_0pF => 14,
481485
HfxoCapacitance::_7_5pF => 15,
482486
HfxoCapacitance::_8_0pF => 16,
@@ -506,11 +510,17 @@ pub mod config {
506510
HfxoCapacitance::_20_0pF => 40,
507511
}
508512
}
513+
514+
pub(crate) fn external(self) -> bool {
515+
matches!(self, Self::External)
516+
}
509517
}
510518

511519
/// Internal capacitance value for the LFXO.
512520
#[cfg(feature = "nrf5340-app-s")]
513521
pub enum LfxoCapacitance {
522+
/// Use external capacitors
523+
External = 0,
514524
/// 6 pF
515525
_6pF = 1,
516526
/// 7 pF
@@ -523,6 +533,7 @@ pub mod config {
523533
impl From<LfxoCapacitance> for super::pac::oscillators::vals::Intcap {
524534
fn from(t: LfxoCapacitance) -> Self {
525535
match t {
536+
LfxoCapacitance::External => Self::EXTERNAL,
526537
LfxoCapacitance::_6pF => Self::C6PF,
527538
LfxoCapacitance::_7pF => Self::C7PF,
528539
LfxoCapacitance::_9pF => Self::C9PF,
@@ -720,6 +731,29 @@ pub fn init(config: config::Config) -> Peripherals {
720731
}
721732
}
722733

734+
// Apply trimming values from the FICR.
735+
#[cfg(any(
736+
all(feature = "_nrf5340-app", feature = "_s"),
737+
all(feature = "_nrf54l", feature = "_s"),
738+
feature = "_nrf5340-net",
739+
))]
740+
{
741+
#[cfg(feature = "_nrf5340")]
742+
let n = 32;
743+
#[cfg(feature = "_nrf54l")]
744+
let n = 64;
745+
for i in 0..n {
746+
let info = pac::FICR.trimcnf(i);
747+
let addr = info.addr().read();
748+
if addr == 0 || addr == 0xFFFF_FFFF {
749+
break;
750+
}
751+
unsafe {
752+
(addr as *mut u32).write_volatile(info.data().read());
753+
}
754+
}
755+
}
756+
723757
// GLITCHDET is only accessible for secure code
724758
#[cfg(all(feature = "_nrf54l", feature = "_s"))]
725759
{
@@ -953,17 +987,21 @@ pub fn init(config: config::Config) -> Peripherals {
953987
#[cfg(feature = "nrf5340-app-s")]
954988
{
955989
if let Some(cap) = config.internal_capacitors.hfxo {
956-
let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32;
957-
let offset = pac::FICR.xosc32mtrim().read().offset() as i32;
958-
// slope is a signed 5-bit integer
959-
if slope >= 16 {
960-
slope -= 32;
990+
if cap.external() {
991+
pac::OSCILLATORS.xosc32mcaps().write(|w| w.set_enable(false));
992+
} else {
993+
let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32;
994+
let offset = pac::FICR.xosc32mtrim().read().offset() as i32;
995+
// slope is a signed 5-bit integer
996+
if slope >= 16 {
997+
slope -= 32;
998+
}
999+
let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6;
1000+
pac::OSCILLATORS.xosc32mcaps().write(|w| {
1001+
w.set_capvalue(capvalue as u8);
1002+
w.set_enable(true);
1003+
});
9611004
}
962-
let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6;
963-
pac::OSCILLATORS.xosc32mcaps().write(|w| {
964-
w.set_capvalue(capvalue as u8);
965-
w.set_enable(true);
966-
});
9671005
}
9681006
if let Some(cap) = config.internal_capacitors.lfxo {
9691007
pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into()));

embassy-nrf/src/radio/ieee802154.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ impl<'d> Radio<'d> {
5252
// Disable and enable to reset peripheral
5353
r.power().write(|w| w.set_power(false));
5454
r.power().write(|w| w.set_power(true));
55+
errata::post_power();
5556

5657
// Enable 802.15.4 mode
5758
r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT));
@@ -541,3 +542,19 @@ fn dma_start_fence() {
541542
fn dma_end_fence() {
542543
compiler_fence(Ordering::Acquire);
543544
}
545+
546+
mod errata {
547+
pub fn post_power() {
548+
// Workaround for anomaly 158
549+
#[cfg(feature = "_nrf5340-net")]
550+
for i in 0..32 {
551+
let info = crate::pac::FICR.trimcnf(i);
552+
let addr = info.addr().read();
553+
if addr & 0xFFFF_F000 == crate::pac::RADIO.as_ptr() as u32 {
554+
unsafe {
555+
(addr as *mut u32).write_volatile(info.data().read());
556+
}
557+
}
558+
}
559+
}
560+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use defmt::info;
5+
use embassy_executor::Spawner;
6+
use embassy_nrf::config::{Config, HfclkSource, LfclkSource, LfxoCapacitance};
7+
use embassy_nrf::pac;
8+
use {defmt_rtt as _, panic_probe as _};
9+
10+
fn print_xosc32mcaps() {
11+
let value = pac::OSCILLATORS.xosc32mcaps().read();
12+
info!("XOSC32MCAPS.ENABLE = {}", value.enable());
13+
info!("XOSC32MCAPS.CAPVALUE = {}", value.capvalue());
14+
}
15+
16+
#[embassy_executor::main]
17+
async fn main(_spawner: Spawner) {
18+
info!("Before init:");
19+
print_xosc32mcaps();
20+
21+
let mut config = Config::default();
22+
config.hfclk_source = HfclkSource::Internal;
23+
config.lfclk_source = LfclkSource::ExternalXtal;
24+
config.internal_capacitors.hfxo = None; // keep the value from the FICR
25+
config.internal_capacitors.lfxo = Some(LfxoCapacitance::_7pF);
26+
let _p = embassy_nrf::init(config);
27+
28+
info!("After init:");
29+
print_xosc32mcaps();
30+
}

0 commit comments

Comments
 (0)