diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 23888b390..f2cf0d77e 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -360,6 +360,133 @@ pub mod config { pub regmain: bool, } + /// Settings for the internal capacitors. + #[cfg(feature = "nrf5340-app-s")] + pub struct InternalCapacitors { + /// Config for the internal capacitors on pins XC1 and XC2. + pub hfxo: Option, + /// Config for the internal capacitors between pins XL1 and XL2. + pub lfxo: Option, + } + + /// Internal capacitance value for the HFXO. + #[cfg(feature = "nrf5340-app-s")] + #[derive(Copy, Clone)] + pub enum HfxoCapacitance { + /// 7.0 pF + _7_0pF, + /// 7.5 pF + _7_5pF, + /// 8.0 pF + _8_0pF, + /// 8.5 pF + _8_5pF, + /// 9.0 pF + _9_0pF, + /// 9.5 pF + _9_5pF, + /// 10.0 pF + _10_0pF, + /// 10.5 pF + _10_5pF, + /// 11.0 pF + _11_0pF, + /// 11.5 pF + _11_5pF, + /// 12.0 pF + _12_0pF, + /// 12.5 pF + _12_5pF, + /// 13.0 pF + _13_0pF, + /// 13.5 pF + _13_5pF, + /// 14.0 pF + _14_0pF, + /// 14.5 pF + _14_5pF, + /// 15.0 pF + _15_0pF, + /// 15.5 pF + _15_5pF, + /// 16.0 pF + _16_0pF, + /// 16.5 pF + _16_5pF, + /// 17.0 pF + _17_0pF, + /// 17.5 pF + _17_5pF, + /// 18.0 pF + _18_0pF, + /// 18.5 pF + _18_5pF, + /// 19.0 pF + _19_0pF, + /// 19.5 pF + _19_5pF, + /// 20.0 pF + _20_0pF, + } + + #[cfg(feature = "nrf5340-app-s")] + impl HfxoCapacitance { + /// The capacitance value times two. + pub(crate) const fn value2(self) -> i32 { + match self { + HfxoCapacitance::_7_0pF => 14, + HfxoCapacitance::_7_5pF => 15, + HfxoCapacitance::_8_0pF => 16, + HfxoCapacitance::_8_5pF => 17, + HfxoCapacitance::_9_0pF => 18, + HfxoCapacitance::_9_5pF => 19, + HfxoCapacitance::_10_0pF => 20, + HfxoCapacitance::_10_5pF => 21, + HfxoCapacitance::_11_0pF => 22, + HfxoCapacitance::_11_5pF => 23, + HfxoCapacitance::_12_0pF => 24, + HfxoCapacitance::_12_5pF => 25, + HfxoCapacitance::_13_0pF => 26, + HfxoCapacitance::_13_5pF => 27, + HfxoCapacitance::_14_0pF => 28, + HfxoCapacitance::_14_5pF => 29, + HfxoCapacitance::_15_0pF => 30, + HfxoCapacitance::_15_5pF => 31, + HfxoCapacitance::_16_0pF => 32, + HfxoCapacitance::_16_5pF => 33, + HfxoCapacitance::_17_0pF => 34, + HfxoCapacitance::_17_5pF => 35, + HfxoCapacitance::_18_0pF => 36, + HfxoCapacitance::_18_5pF => 37, + HfxoCapacitance::_19_0pF => 38, + HfxoCapacitance::_19_5pF => 39, + HfxoCapacitance::_20_0pF => 40, + } + } + } + + /// Internal capacitance value for the LFXO. + #[cfg(feature = "nrf5340-app-s")] + pub enum LfxoCapacitance { + /// 6 pF + _6pF = 1, + /// 7 pF + _7pF = 2, + /// 9 pF + _9pF = 3, + } + + #[cfg(feature = "nrf5340-app-s")] + impl From for super::pac::oscillators::vals::Intcap { + fn from(t: LfxoCapacitance) -> Self { + match t { + LfxoCapacitance::_6pF => Self::C6PF, + LfxoCapacitance::_7pF => Self::C7PF, + LfxoCapacitance::_9pF => Self::C9PF, + } + } + } + /// Configuration for peripherals. Default configuration should work on any nRF chip. #[non_exhaustive] pub struct Config { @@ -367,6 +494,10 @@ pub mod config { pub hfclk_source: HfclkSource, /// Low frequency clock source. pub lfclk_source: LfclkSource, + #[cfg(feature = "nrf5340-app-s")] + /// Internal capacitor configuration, for use with the `ExternalXtal` clock source. See + /// nrf5340-PS ยง4.12. + pub internal_capacitors: InternalCapacitors, #[cfg(not(any(feature = "_nrf5340-net", feature = "_nrf54l")))] /// DCDC configuration. pub dcdc: DcdcConfig, @@ -388,6 +519,8 @@ pub mod config { // xtals if they know they have them. hfclk_source: HfclkSource::Internal, lfclk_source: LfclkSource::InternalRC, + #[cfg(feature = "nrf5340-app-s")] + internal_capacitors: InternalCapacitors { hfxo: None, lfxo: None }, #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] dcdc: DcdcConfig { #[cfg(feature = "nrf52840")] @@ -687,6 +820,27 @@ pub fn init(config: config::Config) -> Peripherals { cortex_m::peripheral::SCB::sys_reset(); } + // Configure internal capacitors + #[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; + } + 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())); + } + } + let r = pac::CLOCK; // Start HFCLK. @@ -753,7 +907,7 @@ pub fn init(config: config::Config) -> Peripherals { config::LfclkSource::ExternalLowSwing => lfxo = true, #[cfg(not(feature = "lfxo-pins-as-gpio"))] config::LfclkSource::ExternalFullSwing => { - #[cfg(all(feature = "_nrf5340-app"))] + #[cfg(feature = "_nrf5340-app")] pac::OSCILLATORS.xosc32ki().bypass().write(|w| w.set_bypass(true)); lfxo = true; }