diff options
| author | Matthew Tran <[email protected]> | 2025-10-05 03:16:18 -0500 |
|---|---|---|
| committer | Matthew Tran <[email protected]> | 2025-10-05 08:15:10 -0500 |
| commit | c0fd86d6c68ec5f66a4cd5a5ef36bcda7b9e1c0e (patch) | |
| tree | f795496b927ffa15823782e4934e62e56a008587 | |
| parent | e4e06ab5b136a21c98d42491ef1e31b6dc25e08e (diff) | |
nrf: apply FICR.TRIMCNF values
| -rw-r--r-- | embassy-nrf/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf54l15_app.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 64 | ||||
| -rw-r--r-- | embassy-nrf/src/radio/ieee802154.rs | 17 | ||||
| -rw-r--r-- | examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs | 30 |
5 files changed, 100 insertions, 13 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b3d4045fa..0244dedab 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l | ||
| 10 | 11 | ||
| 11 | ## 0.8.0 - 2025-09-30 | 12 | ## 0.8.0 - 2025-09-30 |
| 12 | 13 | ||
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index ff05bbec0..82d30104f 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs | |||
| @@ -94,6 +94,7 @@ pub mod pac { | |||
| 94 | #[cfg(feature = "_s")] | 94 | #[cfg(feature = "_s")] |
| 95 | #[doc(no_inline)] | 95 | #[doc(no_inline)] |
| 96 | pub use nrf_pac::{ | 96 | pub use nrf_pac::{ |
| 97 | FICR_NS as FICR, | ||
| 97 | SICR_S as SICR, | 98 | SICR_S as SICR, |
| 98 | ICACHEDATA_S as ICACHEDATA, | 99 | ICACHEDATA_S as ICACHEDATA, |
| 99 | ICACHEINFO_S as ICACHEINFO, | 100 | ICACHEINFO_S as ICACHEINFO, |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7c26a6184..716eec961 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -406,9 +406,10 @@ pub mod config { | |||
| 406 | /// Settings for the internal capacitors. | 406 | /// Settings for the internal capacitors. |
| 407 | #[cfg(feature = "nrf5340-app-s")] | 407 | #[cfg(feature = "nrf5340-app-s")] |
| 408 | pub struct InternalCapacitors { | 408 | 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. |
| 410 | pub hfxo: Option<HfxoCapacitance>, | 410 | 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. | ||
| 412 | pub lfxo: Option<LfxoCapacitance>, | 413 | pub lfxo: Option<LfxoCapacitance>, |
| 413 | } | 414 | } |
| 414 | 415 | ||
| @@ -416,6 +417,8 @@ pub mod config { | |||
| 416 | #[cfg(feature = "nrf5340-app-s")] | 417 | #[cfg(feature = "nrf5340-app-s")] |
| 417 | #[derive(Copy, Clone)] | 418 | #[derive(Copy, Clone)] |
| 418 | pub enum HfxoCapacitance { | 419 | pub enum HfxoCapacitance { |
| 420 | /// Use external capacitors | ||
| 421 | External, | ||
| 419 | /// 7.0 pF | 422 | /// 7.0 pF |
| 420 | _7_0pF, | 423 | _7_0pF, |
| 421 | /// 7.5 pF | 424 | /// 7.5 pF |
| @@ -475,8 +478,9 @@ pub mod config { | |||
| 475 | #[cfg(feature = "nrf5340-app-s")] | 478 | #[cfg(feature = "nrf5340-app-s")] |
| 476 | impl HfxoCapacitance { | 479 | impl HfxoCapacitance { |
| 477 | /// The capacitance value times two. | 480 | /// The capacitance value times two. |
| 478 | pub(crate) const fn value2(self) -> i32 { | 481 | pub(crate) fn value2(self) -> i32 { |
| 479 | match self { | 482 | match self { |
| 483 | HfxoCapacitance::External => unreachable!(), | ||
| 480 | HfxoCapacitance::_7_0pF => 14, | 484 | HfxoCapacitance::_7_0pF => 14, |
| 481 | HfxoCapacitance::_7_5pF => 15, | 485 | HfxoCapacitance::_7_5pF => 15, |
| 482 | HfxoCapacitance::_8_0pF => 16, | 486 | HfxoCapacitance::_8_0pF => 16, |
| @@ -506,11 +510,17 @@ pub mod config { | |||
| 506 | HfxoCapacitance::_20_0pF => 40, | 510 | HfxoCapacitance::_20_0pF => 40, |
| 507 | } | 511 | } |
| 508 | } | 512 | } |
| 513 | |||
| 514 | pub(crate) fn external(self) -> bool { | ||
| 515 | matches!(self, Self::External) | ||
| 516 | } | ||
| 509 | } | 517 | } |
| 510 | 518 | ||
| 511 | /// Internal capacitance value for the LFXO. | 519 | /// Internal capacitance value for the LFXO. |
| 512 | #[cfg(feature = "nrf5340-app-s")] | 520 | #[cfg(feature = "nrf5340-app-s")] |
| 513 | pub enum LfxoCapacitance { | 521 | pub enum LfxoCapacitance { |
| 522 | /// Use external capacitors | ||
| 523 | External = 0, | ||
| 514 | /// 6 pF | 524 | /// 6 pF |
| 515 | _6pF = 1, | 525 | _6pF = 1, |
| 516 | /// 7 pF | 526 | /// 7 pF |
| @@ -523,6 +533,7 @@ pub mod config { | |||
| 523 | impl From<LfxoCapacitance> for super::pac::oscillators::vals::Intcap { | 533 | impl From<LfxoCapacitance> for super::pac::oscillators::vals::Intcap { |
| 524 | fn from(t: LfxoCapacitance) -> Self { | 534 | fn from(t: LfxoCapacitance) -> Self { |
| 525 | match t { | 535 | match t { |
| 536 | LfxoCapacitance::External => Self::EXTERNAL, | ||
| 526 | LfxoCapacitance::_6pF => Self::C6PF, | 537 | LfxoCapacitance::_6pF => Self::C6PF, |
| 527 | LfxoCapacitance::_7pF => Self::C7PF, | 538 | LfxoCapacitance::_7pF => Self::C7PF, |
| 528 | LfxoCapacitance::_9pF => Self::C9PF, | 539 | LfxoCapacitance::_9pF => Self::C9PF, |
| @@ -720,6 +731,29 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 720 | } | 731 | } |
| 721 | } | 732 | } |
| 722 | 733 | ||
| 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 | |||
| 723 | // GLITCHDET is only accessible for secure code | 757 | // GLITCHDET is only accessible for secure code |
| 724 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | 758 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] |
| 725 | { | 759 | { |
| @@ -953,17 +987,21 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 953 | #[cfg(feature = "nrf5340-app-s")] | 987 | #[cfg(feature = "nrf5340-app-s")] |
| 954 | { | 988 | { |
| 955 | if let Some(cap) = config.internal_capacitors.hfxo { | 989 | if let Some(cap) = config.internal_capacitors.hfxo { |
| 956 | let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; | 990 | if cap.external() { |
| 957 | let offset = pac::FICR.xosc32mtrim().read().offset() as i32; | 991 | pac::OSCILLATORS.xosc32mcaps().write(|w| w.set_enable(false)); |
| 958 | // slope is a signed 5-bit integer | 992 | } else { |
| 959 | if slope >= 16 { | 993 | let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; |
| 960 | slope -= 32; | 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 | }); | ||
| 961 | } | 1004 | } |
| 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 | }); | ||
| 967 | } | 1005 | } |
| 968 | if let Some(cap) = config.internal_capacitors.lfxo { | 1006 | if let Some(cap) = config.internal_capacitors.lfxo { |
| 969 | pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into())); | 1007 | pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into())); |
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 62af03a5a..844d3551e 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs | |||
| @@ -52,6 +52,7 @@ impl<'d> Radio<'d> { | |||
| 52 | // Disable and enable to reset peripheral | 52 | // Disable and enable to reset peripheral |
| 53 | r.power().write(|w| w.set_power(false)); | 53 | r.power().write(|w| w.set_power(false)); |
| 54 | r.power().write(|w| w.set_power(true)); | 54 | r.power().write(|w| w.set_power(true)); |
| 55 | errata::post_power(); | ||
| 55 | 56 | ||
| 56 | // Enable 802.15.4 mode | 57 | // Enable 802.15.4 mode |
| 57 | r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); | 58 | r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); |
| @@ -541,3 +542,19 @@ fn dma_start_fence() { | |||
| 541 | fn dma_end_fence() { | 542 | fn dma_end_fence() { |
| 542 | compiler_fence(Ordering::Acquire); | 543 | compiler_fence(Ordering::Acquire); |
| 543 | } | 544 | } |
| 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 | } | ||
diff --git a/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs new file mode 100644 index 000000000..0b1fb852e --- /dev/null +++ b/examples/nrf5340/src/bin/nrf5340dk_internal_caps.rs | |||
| @@ -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 | } | ||
