aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-14 15:35:20 +0100
committerJames Munns <[email protected]>2025-11-14 15:36:31 +0100
commit9f889d015ef5d373343ad6c769824e28be780e53 (patch)
tree837276d87fbe10123f0cd37ff87679087442d355
parent4979747286af4cd7bab43f8048b0ce6f00cc5ab6 (diff)
Implement SPConfHelper for OSTimer and ADC
-rw-r--r--src/board.rs14
-rw-r--r--src/clocks/mod.rs71
-rw-r--r--src/clocks/periph_helpers.rs171
-rw-r--r--src/lpuart/mod.rs12
4 files changed, 229 insertions, 39 deletions
diff --git a/src/board.rs b/src/board.rs
deleted file mode 100644
index fa679e82c..000000000
--- a/src/board.rs
+++ /dev/null
@@ -1,14 +0,0 @@
1use crate::{clocks, pac, pins};
2
3/// Initialize clocks and pin muxing for UART2 debug console.
4pub unsafe fn init_uart2(p: &pac::Peripherals) {
5 clocks::ensure_frolf_running(p);
6 clocks::enable_uart2_port2(p);
7 pins::configure_uart2_pins_port2();
8 clocks::select_uart2_clock(p);
9}
10
11/// Initialize clocks for the LED GPIO/PORT used by the blink example.
12pub unsafe fn init_led(p: &pac::Peripherals) {
13 clocks::enable_led_port(p);
14}
diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs
index 63a8fb64d..db41db628 100644
--- a/src/clocks/mod.rs
+++ b/src/clocks/mod.rs
@@ -141,16 +141,23 @@ impl SPConfHelper for UnimplementedConfig {
141 } 141 }
142} 142}
143 143
144pub struct NoConfig;
145impl SPConfHelper for NoConfig {
146 fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> {
147 Ok(0)
148 }
149}
150
144pub mod gate { 151pub mod gate {
145 use super::{periph_helpers::LpuartConfig, *}; 152 use super::{periph_helpers::{AdcConfig, LpuartConfig, OsTimerConfig}, *};
146 153
147 impl_cc_gate!(PORT1, mrcc_glb_cc1, port1, UnimplementedConfig); 154 impl_cc_gate!(PORT1, mrcc_glb_cc1, port1, NoConfig);
148 impl_cc_gate!(PORT2, mrcc_glb_cc1, port2, UnimplementedConfig); 155 impl_cc_gate!(PORT2, mrcc_glb_cc1, port2, NoConfig);
149 impl_cc_gate!(PORT3, mrcc_glb_cc1, port3, UnimplementedConfig); 156 impl_cc_gate!(PORT3, mrcc_glb_cc1, port3, NoConfig);
150 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, ostimer0, UnimplementedConfig); 157 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, ostimer0, OsTimerConfig);
151 impl_cc_gate!(LPUART2, mrcc_glb_cc0, lpuart2, LpuartConfig); 158 impl_cc_gate!(LPUART2, mrcc_glb_cc0, lpuart2, LpuartConfig);
152 impl_cc_gate!(GPIO3, mrcc_glb_cc2, gpio3, UnimplementedConfig); 159 impl_cc_gate!(GPIO3, mrcc_glb_cc2, gpio3, NoConfig);
153 impl_cc_gate!(ADC1, mrcc_glb_cc1, adc1, UnimplementedConfig); 160 impl_cc_gate!(ADC1, mrcc_glb_cc1, adc1, AdcConfig);
154} 161}
155 162
156// /// Convenience helper enabling the PORT2 and LPUART2 gates required for the debug UART. 163// /// Convenience helper enabling the PORT2 and LPUART2 gates required for the debug UART.
@@ -418,7 +425,6 @@ pub struct Clocks {
418 pub fro_lf_div: Option<Clock>, 425 pub fro_lf_div: Option<Clock>,
419 // 426 //
420 // End FRO12M stuff 427 // End FRO12M stuff
421
422 pub clk_16k_vsys: Option<Clock>, 428 pub clk_16k_vsys: Option<Clock>,
423 pub clk_16k_vdd_core: Option<Clock>, 429 pub clk_16k_vdd_core: Option<Clock>,
424 pub main_clk: Option<Clock>, 430 pub main_clk: Option<Clock>,
@@ -691,7 +697,10 @@ impl ClockOperator<'_> {
691 // Lock the control register 697 // Lock the control register
692 self.vbat0.frolcka().modify(|_, w| w.lock().set_bit()); 698 self.vbat0.frolcka().modify(|_, w| w.lock().set_bit());
693 699
694 let Fro16KConfig { vsys_domain_active, vdd_core_domain_active } = fro16k; 700 let Fro16KConfig {
701 vsys_domain_active,
702 vdd_core_domain_active,
703 } = fro16k;
695 704
696 // Enable clock outputs to both VSYS and VDD_CORE domains 705 // Enable clock outputs to both VSYS and VDD_CORE domains
697 // Bit 0: clk_16k0 to VSYS domain 706 // Bit 0: clk_16k0 to VSYS domain
@@ -713,9 +722,7 @@ impl ClockOperator<'_> {
713 power: PoweredClock::AlwaysEnabled, 722 power: PoweredClock::AlwaysEnabled,
714 }); 723 });
715 } 724 }
716 self.vbat0.froclke().modify(|_r, w| { 725 self.vbat0.froclke().modify(|_r, w| unsafe { w.clke().bits(bits) });
717 unsafe { w.clke().bits(bits) }
718 });
719 726
720 Ok(()) 727 Ok(())
721 } 728 }
@@ -783,6 +790,22 @@ impl Clocks {
783 Ok(clk.frequency) 790 Ok(clk.frequency)
784 } 791 }
785 792
793 pub fn ensure_fro_hf_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
794 let Some(clk) = self.fro_hf.as_ref() else {
795 return Err(ClockError::BadConfig {
796 clock: "fro_hf",
797 reason: "required but not active",
798 });
799 };
800 if !clk.power.meets_requirement_of(at_level) {
801 return Err(ClockError::BadConfig {
802 clock: "fro_hf",
803 reason: "not low power active",
804 });
805 }
806 Ok(clk.frequency)
807 }
808
786 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 809 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
787 let Some(clk) = self.fro_hf_div.as_ref() else { 810 let Some(clk) = self.fro_hf_div.as_ref() else {
788 return Err(ClockError::BadConfig { 811 return Err(ClockError::BadConfig {
@@ -803,8 +826,28 @@ impl Clocks {
803 Err(ClockError::NotImplemented { clock: "clk_in" }) 826 Err(ClockError::NotImplemented { clock: "clk_in" })
804 } 827 }
805 828
806 pub fn ensure_clk_16k_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { 829 pub fn ensure_clk_16k_vsys_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
807 Err(ClockError::NotImplemented { clock: "clk_16k" }) 830 // NOTE: clk_16k is always active in low power mode
831 Ok(self
832 .clk_16k_vsys
833 .as_ref()
834 .ok_or(ClockError::BadConfig {
835 clock: "clk_16k_vsys",
836 reason: "required but not active",
837 })?
838 .frequency)
839 }
840
841 pub fn ensure_clk_16k_vdd_core_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
842 // NOTE: clk_16k is always active in low power mode
843 Ok(self
844 .clk_16k_vdd_core
845 .as_ref()
846 .ok_or(ClockError::BadConfig {
847 clock: "clk_16k_vdd_core",
848 reason: "required but not active",
849 })?
850 .frequency)
808 } 851 }
809 852
810 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 853 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
diff --git a/src/clocks/periph_helpers.rs b/src/clocks/periph_helpers.rs
index 4d186acf8..de767ef87 100644
--- a/src/clocks/periph_helpers.rs
+++ b/src/clocks/periph_helpers.rs
@@ -1,4 +1,4 @@
1use super::{ClockError, Clocks, Div8, PoweredClock}; 1use super::{ClockError, Clocks, PoweredClock};
2use crate::pac; 2use crate::pac;
3 3
4pub trait SPConfHelper { 4pub trait SPConfHelper {
@@ -7,6 +7,59 @@ pub trait SPConfHelper {
7 7
8// config types 8// config types
9 9
10/// This type represents a divider in the range 1..=16.
11///
12/// At a hardware level, this is an 8-bit register from 0..=15,
13/// which adds one.
14///
15/// While the *clock* domain seems to use 8-bit dividers, the *peripheral* domain
16/// seems to use 4 bit dividers!
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub struct Div4(pub(super) u8);
19
20impl Div4 {
21 /// Store a "raw" divisor value that will divide the source by
22 /// `(n + 1)`, e.g. `Div4::from_raw(0)` will divide the source
23 /// by 1, and `Div4::from_raw(15)` will divide the source by
24 /// 16.
25 pub const fn from_raw(n: u8) -> Option<Self> {
26 if n > 0b1111 {
27 None
28 } else {
29 Some(Self(n))
30 }
31 }
32
33 /// Store a specific divisor value that will divide the source
34 /// by `n`. e.g. `Div4::from_divisor(1)` will divide the source
35 /// by 1, and `Div4::from_divisor(16)` will divide the source
36 /// by 16.
37 ///
38 /// Will return `None` if `n` is not in the range `1..=16`.
39 /// Consider [`Self::from_raw`] for an infallible version.
40 pub const fn from_divisor(n: u8) -> Option<Self> {
41 let Some(n) = n.checked_sub(1) else {
42 return None;
43 };
44 if n > 0b1111 {
45 return None;
46 }
47 Some(Self(n))
48 }
49
50 /// Convert into "raw" bits form
51 #[inline(always)]
52 pub const fn into_bits(self) -> u8 {
53 self.0
54 }
55
56 /// Convert into "divisor" form, as a u32 for convenient frequency math
57 #[inline(always)]
58 pub const fn into_divisor(self) -> u32 {
59 self.0 as u32 + 1
60 }
61}
62
10#[derive(Debug, Clone, Copy)] 63#[derive(Debug, Clone, Copy)]
11pub enum LpuartClockSel { 64pub enum LpuartClockSel {
12 /// FRO12M/FRO_LF/SIRC clock source, passed through divider 65 /// FRO12M/FRO_LF/SIRC clock source, passed through divider
@@ -43,12 +96,41 @@ pub struct LpuartConfig {
43 /// Clock source 96 /// Clock source
44 pub source: LpuartClockSel, 97 pub source: LpuartClockSel,
45 /// Clock divisor 98 /// Clock divisor
46 pub div: Div8, 99 pub div: Div4,
47 /// Which instance is this? 100 /// Which instance is this?
48 // NOTE: should not be user settable 101 // NOTE: should not be user settable
49 pub(crate) instance: LpuartInstance, 102 pub(crate) instance: LpuartInstance,
50} 103}
51 104
105pub enum OstimerClockSel {
106 /// 16k clock, sourced from FRO16K (Vdd Core)
107 Clk16kVddCore,
108 /// 1 MHz Clock sourced from FRO12M
109 Clk1M,
110 /// Disabled
111 None,
112}
113
114pub struct OsTimerConfig {
115 pub power: PoweredClock,
116 pub source: OstimerClockSel,
117}
118
119pub enum AdcClockSel {
120 FroLfDiv,
121 FroHf,
122 ClkIn,
123 Clk1M,
124 Pll1ClkDiv,
125 None,
126}
127
128pub struct AdcConfig {
129 pub power: PoweredClock,
130 pub source: AdcClockSel,
131 pub div: Div4,
132}
133
52// impls 134// impls
53 135
54impl SPConfHelper for LpuartConfig { 136impl SPConfHelper for LpuartConfig {
@@ -80,7 +162,7 @@ impl SPConfHelper for LpuartConfig {
80 (freq, Mux::ClkrootFunc3) 162 (freq, Mux::ClkrootFunc3)
81 } 163 }
82 LpuartClockSel::Clk16K => { 164 LpuartClockSel::Clk16K => {
83 let freq = clocks.ensure_clk_16k_active(&self.power)?; 165 let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?;
84 (freq, Mux::ClkrootFunc4) 166 (freq, Mux::ClkrootFunc4)
85 } 167 }
86 LpuartClockSel::Clk1M => { 168 LpuartClockSel::Clk1M => {
@@ -124,3 +206,86 @@ impl SPConfHelper for LpuartConfig {
124 Ok(freq / self.div.into_divisor()) 206 Ok(freq / self.div.into_divisor())
125 } 207 }
126} 208}
209
210impl SPConfHelper for OsTimerConfig {
211 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
212 let mrcc0 = unsafe { pac::Mrcc0::steal() };
213 Ok(match self.source {
214 OstimerClockSel::Clk16kVddCore => {
215 let freq = clocks.ensure_clk_16k_vdd_core_active(&self.power)?;
216 mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_16k());
217 freq
218 }
219 OstimerClockSel::Clk1M => {
220 let freq = clocks.ensure_clk_1m_active(&self.power)?;
221 mrcc0.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m());
222 freq
223 }
224 OstimerClockSel::None => {
225 mrcc0.mrcc_ostimer0_clksel().write(|w| unsafe { w.mux().bits(0b11) });
226 0
227 }
228 })
229 }
230}
231
232impl SPConfHelper for AdcConfig {
233 fn post_enable_config(&self, clocks: &Clocks) -> Result<u32, ClockError> {
234 use mcxa_pac::mrcc0::mrcc_adc_clksel::Mux;
235 let mrcc0 = unsafe { pac::Mrcc0::steal() };
236 let (freq, variant) = match self.source {
237 AdcClockSel::FroLfDiv => {
238 let freq = clocks.ensure_fro_lf_div_active(&self.power)?;
239 (freq, Mux::ClkrootFunc0)
240 }
241 AdcClockSel::FroHf => {
242 let freq = clocks.ensure_fro_hf_active(&self.power)?;
243 (freq, Mux::ClkrootFunc1)
244 }
245 AdcClockSel::ClkIn => {
246 let freq = clocks.ensure_clk_in_active(&self.power)?;
247 (freq, Mux::ClkrootFunc3)
248 }
249 AdcClockSel::Clk1M => {
250 let freq = clocks.ensure_clk_1m_active(&self.power)?;
251 (freq, Mux::ClkrootFunc5)
252 }
253 AdcClockSel::Pll1ClkDiv => {
254 let freq = clocks.ensure_pll1_clk_div_active(&self.power)?;
255 (freq, Mux::ClkrootFunc6)
256 }
257 AdcClockSel::None => {
258 mrcc0.mrcc_adc_clksel().write(|w| unsafe {
259 // no ClkrootFunc7, just write manually for now
260 w.mux().bits(0b111)
261 });
262 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
263 w.reset().on();
264 w.halt().on();
265 w
266 });
267 return Ok(0);
268 }
269 };
270
271 // set clksel
272 mrcc0.mrcc_adc_clksel().modify(|_r, w| w.mux().variant(variant));
273
274 // Set up clkdiv
275 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
276 w.halt().on();
277 w.reset().on();
278 w
279 });
280 mrcc0.mrcc_adc_clkdiv().modify(|_r, w| {
281 w.halt().off();
282 w.reset().off();
283 unsafe { w.div().bits(self.div.into_bits()) };
284 w
285 });
286
287 while mrcc0.mrcc_adc_clkdiv().read().unstab().is_on() {}
288
289 Ok(freq / self.div.into_divisor())
290 }
291}
diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs
index 41ec951ec..35b4db24c 100644
--- a/src/lpuart/mod.rs
+++ b/src/lpuart/mod.rs
@@ -4,7 +4,7 @@ use embassy_hal_internal::{Peri, PeripheralType};
4use paste::paste; 4use paste::paste;
5 5
6use crate::clocks::periph_helpers::{LpuartClockSel, LpuartConfig}; 6use crate::clocks::periph_helpers::{LpuartClockSel, LpuartConfig};
7use crate::clocks::{enable_and_reset, ClockError, Div8, Gate, PoweredClock}; 7use crate::clocks::{enable_and_reset, ClockError, periph_helpers::Div4, Gate, PoweredClock};
8use crate::pac::lpuart0::baud::Sbns as StopBits; 8use crate::pac::lpuart0::baud::Sbns as StopBits;
9use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits}; 9use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits};
10use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; 10use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
@@ -20,8 +20,6 @@ pub mod buffered;
20// Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API 20// Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API
21// Pin and Clock initialization is currently done at the examples level. 21// Pin and Clock initialization is currently done at the examples level.
22 22
23
24
25// --- START GPIO --- 23// --- START GPIO ---
26 24
27mod gpio { 25mod gpio {
@@ -491,7 +489,7 @@ pub struct Config {
491 /// Clock source 489 /// Clock source
492 pub source: LpuartClockSel, 490 pub source: LpuartClockSel,
493 /// Clock divisor 491 /// Clock divisor
494 pub div: Div8, 492 pub div: Div4,
495 /// Baud rate in bits per second 493 /// Baud rate in bits per second
496 pub baudrate_bps: u32, 494 pub baudrate_bps: u32,
497 /// Parity configuration 495 /// Parity configuration
@@ -547,7 +545,7 @@ impl Default for Config {
547 swap_txd_rxd: false, 545 swap_txd_rxd: false,
548 power: PoweredClock::NormalEnabledDeepSleepDisabled, 546 power: PoweredClock::NormalEnabledDeepSleepDisabled,
549 source: LpuartClockSel::FroLfDiv, 547 source: LpuartClockSel::FroLfDiv,
550 div: const { Div8::from_divisor(1).unwrap() }, 548 div: const { Div4::from_divisor(1).unwrap() },
551 } 549 }
552 } 550 }
553} 551}
@@ -640,9 +638,7 @@ impl<'a, M: Mode> Lpuart<'a, M> {
640 div: config.div, 638 div: config.div,
641 instance: T::CLOCK_INSTANCE, 639 instance: T::CLOCK_INSTANCE,
642 }; 640 };
643 let clock_freq = unsafe { 641 let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? };
644 enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)?
645 };
646 642
647 // Perform initialization sequence 643 // Perform initialization sequence
648 perform_software_reset(regs); 644 perform_software_reset(regs);