aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-14 14:39:23 +0100
committerJames Munns <[email protected]>2025-11-14 14:39:23 +0100
commit4979747286af4cd7bab43f8048b0ce6f00cc5ab6 (patch)
tree188116a3254e45e70acdecc6cd4e3f05a9efd888 /src
parent0f8e7650b937aa5d4accef3fdf01047afe099df3 (diff)
Plumb clocks changes to lpuart
Diffstat (limited to 'src')
-rw-r--r--src/clocks/mod.rs301
-rw-r--r--src/clocks/periph_helpers.rs3
-rw-r--r--src/lib.rs14
-rw-r--r--src/lpuart/buffered.rs11
-rw-r--r--src/lpuart/mod.rs136
5 files changed, 291 insertions, 174 deletions
diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs
index ad48a9cf2..63a8fb64d 100644
--- a/src/clocks/mod.rs
+++ b/src/clocks/mod.rs
@@ -1,66 +1,157 @@
1//! Clock control helpers (no magic numbers, PAC field access only). 1//! Clock control helpers (no magic numbers, PAC field access only).
2//! Provides reusable gate abstractions for peripherals used by the examples. 2//! Provides reusable gate abstractions for peripherals used by the examples.
3use core::cell::RefCell;
4
3use mcxa_pac::scg0::{ 5use mcxa_pac::scg0::{
4 firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten}, 6 firccsr::{FircFclkPeriphEn, FircSclkPeriphEn, Fircsten},
5 sirccsr::{SircClkPeriphEn, Sircsten}, 7 sirccsr::{SircClkPeriphEn, Sircsten},
6}; 8};
9use periph_helpers::SPConfHelper;
7 10
8use crate::pac; 11use crate::pac;
9pub mod periph_helpers; 12pub mod periph_helpers;
10 13
11// /// Trait describing an AHB clock gate that can be toggled through MRCC. 14/// Trait describing an AHB clock gate that can be toggled through MRCC.
12// pub trait Gate { 15pub trait Gate {
13// /// Enable the clock gate. 16 type MrccPeriphConfig: SPConfHelper;
14// unsafe fn enable(mrcc: &pac::mrcc0::RegisterBlock);
15 17
16// /// Return whether the clock gate is currently enabled. 18 /// Enable the clock gate.
17// fn is_enabled(mrcc: &pac::mrcc0::RegisterBlock) -> bool; 19 unsafe fn enable_clock();
18// }
19 20
20// /// Enable a clock gate for the given peripheral set. 21 /// Disable the clock gate.
21// #[inline] 22 unsafe fn disable_clock();
22// pub unsafe fn enable<G: Gate>(peripherals: &pac::Peripherals) {
23// let mrcc = &peripherals.mrcc0;
24// G::enable(mrcc);
25// while !G::is_enabled(mrcc) {}
26// core::arch::asm!("dsb sy; isb sy", options(nomem, nostack, preserves_flags));
27// }
28 23
29// /// Check whether a gate is currently enabled. 24 /// Drive the peripheral into reset.
30// #[inline] 25 unsafe fn assert_reset();
31// pub fn is_enabled<G: Gate>(peripherals: &pac::Peripherals) -> bool {
32// G::is_enabled(&peripherals.mrcc0)
33// }
34 26
35// macro_rules! impl_cc_gate { 27 /// Drive the peripheral out of reset.
36// ($name:ident, $reg:ident, $field:ident) => { 28 unsafe fn release_reset();
37// pub struct $name;
38
39// impl Gate for $name {
40// #[inline]
41// unsafe fn enable(mrcc: &pac::mrcc0::RegisterBlock) {
42// mrcc.$reg().modify(|_, w| w.$field().enabled());
43// }
44
45// #[inline]
46// fn is_enabled(mrcc: &pac::mrcc0::RegisterBlock) -> bool {
47// mrcc.$reg().read().$field().is_enabled()
48// }
49// }
50// };
51// }
52 29
53// pub mod gate { 30 /// Return whether the clock gate is currently enabled.
54// use super::*; 31 fn is_clock_enabled() -> bool;
55 32
56// impl_cc_gate!(Port2, mrcc_glb_cc1, port2); 33 /// .
57// impl_cc_gate!(Port3, mrcc_glb_cc1, port3); 34 fn is_reset_released() -> bool;
58// impl_cc_gate!(Ostimer0, mrcc_glb_cc1, ostimer0); 35}
59// impl_cc_gate!(Lpuart2, mrcc_glb_cc0, lpuart2); 36
60// impl_cc_gate!(Gpio3, mrcc_glb_cc2, gpio3); 37#[inline]
61// impl_cc_gate!(Port1, mrcc_glb_cc1, port1); 38pub unsafe fn enable_and_reset<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> {
62// impl_cc_gate!(Adc1, mrcc_glb_cc1, adc1); 39 let freq = enable::<G>(cfg)?;
63// } 40 pulse_reset::<G>();
41 Ok(freq)
42}
43
44/// Enable a clock gate for the given peripheral set.
45#[inline]
46pub unsafe fn enable<G: Gate>(cfg: &G::MrccPeriphConfig) -> Result<u32, ClockError> {
47 G::enable_clock();
48 while !G::is_clock_enabled() {}
49 core::arch::asm!("dsb sy; isb sy", options(nomem, nostack, preserves_flags));
50
51 let freq = critical_section::with(|cs| {
52 let clocks = CLOCKS.borrow_ref(cs);
53 let clocks = clocks.as_ref().ok_or(ClockError::NeverInitialized)?;
54 cfg.post_enable_config(clocks)
55 });
56
57 freq.inspect_err(|_e| {
58 G::disable_clock();
59 })
60}
61
62pub unsafe fn disable<G: Gate>() {
63 G::disable_clock();
64}
65
66/// Check whether a gate is currently enabled.
67#[inline]
68pub fn is_clock_enabled<G: Gate>() -> bool {
69 G::is_clock_enabled()
70}
71
72/// Release a reset line for the given peripheral set.
73#[inline]
74pub unsafe fn release_reset<G: Gate>() {
75 G::release_reset();
76}
77
78/// Assert a reset line for the given peripheral set.
79#[inline]
80pub unsafe fn assert_reset<G: Gate>() {
81 G::assert_reset();
82}
83
84/// Pulse a reset line (assert then release) with a short delay.
85#[inline]
86pub unsafe fn pulse_reset<G: Gate>() {
87 G::assert_reset();
88 cortex_m::asm::nop();
89 cortex_m::asm::nop();
90 G::release_reset();
91}
92
93macro_rules! impl_cc_gate {
94 ($name:ident, $reg:ident, $field:ident, $config:ty) => {
95 impl Gate for crate::peripherals::$name {
96 type MrccPeriphConfig = $config;
97
98 #[inline]
99 unsafe fn enable_clock() {
100 let mrcc = unsafe { pac::Mrcc0::steal() };
101 mrcc.$reg().modify(|_, w| w.$field().enabled());
102 }
103
104 #[inline]
105 unsafe fn disable_clock() {
106 let mrcc = unsafe { pac::Mrcc0::steal() };
107 mrcc.$reg().modify(|_r, w| w.$field().disabled());
108 }
109
110 #[inline]
111 fn is_clock_enabled() -> bool {
112 let mrcc = unsafe { pac::Mrcc0::steal() };
113 mrcc.$reg().read().$field().is_enabled()
114 }
115
116 #[inline]
117 unsafe fn release_reset() {
118 let mrcc = unsafe { pac::Mrcc0::steal() };
119 mrcc.$reg().modify(|_, w| w.$field().enabled());
120 }
121
122 #[inline]
123 unsafe fn assert_reset() {
124 let mrcc = unsafe { pac::Mrcc0::steal() };
125 mrcc.$reg().modify(|_, w| w.$field().disabled());
126 }
127
128 #[inline]
129 fn is_reset_released() -> bool {
130 let mrcc = unsafe { pac::Mrcc0::steal() };
131 mrcc.$reg().read().$field().is_enabled()
132 }
133 }
134 };
135}
136
137pub struct UnimplementedConfig;
138impl SPConfHelper for UnimplementedConfig {
139 fn post_enable_config(&self, _clocks: &Clocks) -> Result<u32, ClockError> {
140 Err(ClockError::UnimplementedConfig)
141 }
142}
143
144pub mod gate {
145 use super::{periph_helpers::LpuartConfig, *};
146
147 impl_cc_gate!(PORT1, mrcc_glb_cc1, port1, UnimplementedConfig);
148 impl_cc_gate!(PORT2, mrcc_glb_cc1, port2, UnimplementedConfig);
149 impl_cc_gate!(PORT3, mrcc_glb_cc1, port3, UnimplementedConfig);
150 impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, ostimer0, UnimplementedConfig);
151 impl_cc_gate!(LPUART2, mrcc_glb_cc0, lpuart2, LpuartConfig);
152 impl_cc_gate!(GPIO3, mrcc_glb_cc2, gpio3, UnimplementedConfig);
153 impl_cc_gate!(ADC1, mrcc_glb_cc1, adc1, UnimplementedConfig);
154}
64 155
65// /// Convenience helper enabling the PORT2 and LPUART2 gates required for the debug UART. 156// /// Convenience helper enabling the PORT2 and LPUART2 gates required for the debug UART.
66// pub unsafe fn enable_uart2_port2(peripherals: &pac::Peripherals) { 157// pub unsafe fn enable_uart2_port2(peripherals: &pac::Peripherals) {
@@ -113,20 +204,6 @@ pub mod periph_helpers;
113// mrcc.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m()); 204// mrcc.mrcc_ostimer0_clksel().write(|w| w.mux().clkroot_1m());
114// } 205// }
115 206
116// pub unsafe fn init_fro16k(peripherals: &pac::Peripherals) {
117// let vbat = &peripherals.vbat0;
118// // Enable FRO16K oscillator
119// vbat.froctla().modify(|_, w| w.fro_en().set_bit());
120
121// // Lock the control register
122// vbat.frolcka().modify(|_, w| w.lock().set_bit());
123
124// // Enable clock outputs to both VSYS and VDD_CORE domains
125// // Bit 0: clk_16k0 to VSYS domain
126// // Bit 1: clk_16k1 to VDD_CORE domain
127// vbat.froclke().modify(|_, w| unsafe { w.clke().bits(0x3) });
128// }
129
130// pub unsafe fn enable_adc(peripherals: &pac::Peripherals) { 207// pub unsafe fn enable_adc(peripherals: &pac::Peripherals) {
131// enable::<gate::Port1>(peripherals); 208// enable::<gate::Port1>(peripherals);
132// enable::<gate::Adc1>(peripherals); 209// enable::<gate::Adc1>(peripherals);
@@ -271,6 +348,7 @@ pub struct ClocksConfig {
271 pub firc: Option<FircConfig>, 348 pub firc: Option<FircConfig>,
272 // NOTE: I don't think we *can* disable the SIRC? 349 // NOTE: I don't think we *can* disable the SIRC?
273 pub sirc: SircConfig, 350 pub sirc: SircConfig,
351 pub fro16k: Option<Fro16KConfig>,
274} 352}
275 353
276// FIRC/FRO180M 354// FIRC/FRO180M
@@ -340,17 +418,30 @@ pub struct Clocks {
340 pub fro_lf_div: Option<Clock>, 418 pub fro_lf_div: Option<Clock>,
341 // 419 //
342 // End FRO12M stuff 420 // End FRO12M stuff
421
422 pub clk_16k_vsys: Option<Clock>,
423 pub clk_16k_vdd_core: Option<Clock>,
343 pub main_clk: Option<Clock>, 424 pub main_clk: Option<Clock>,
344 pub pll1_clk: Option<Clock>, 425 pub pll1_clk: Option<Clock>,
345} 426}
346 427
347static CLOCKS: critical_section::Mutex<Option<Clocks>> = critical_section::Mutex::new(None); 428#[non_exhaustive]
429pub struct Fro16KConfig {
430 pub vsys_domain_active: bool,
431 pub vdd_core_domain_active: bool,
432}
433
434static CLOCKS: critical_section::Mutex<RefCell<Option<Clocks>>> = critical_section::Mutex::new(RefCell::new(None));
348 435
436#[derive(Debug, Copy, Clone, Eq, PartialEq)]
437#[cfg_attr(feature = "defmt", derive(defmt::Format))]
349#[non_exhaustive] 438#[non_exhaustive]
350pub enum ClockError { 439pub enum ClockError {
440 NeverInitialized,
351 AlreadyInitialized, 441 AlreadyInitialized,
352 BadConfig { clock: &'static str, reason: &'static str }, 442 BadConfig { clock: &'static str, reason: &'static str },
353 NotImplemented { clock: &'static str }, 443 NotImplemented { clock: &'static str },
444 UnimplementedConfig,
354} 445}
355 446
356struct ClockOperator<'a> { 447struct ClockOperator<'a> {
@@ -360,6 +451,7 @@ struct ClockOperator<'a> {
360 _mrcc0: pac::Mrcc0, 451 _mrcc0: pac::Mrcc0,
361 scg0: pac::Scg0, 452 scg0: pac::Scg0,
362 syscon: pac::Syscon, 453 syscon: pac::Syscon,
454 vbat0: pac::Vbat0,
363} 455}
364 456
365impl ClockOperator<'_> { 457impl ClockOperator<'_> {
@@ -586,13 +678,52 @@ impl ClockOperator<'_> {
586 }); 678 });
587 } 679 }
588 680
589 todo!() 681 Ok(())
682 }
683
684 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> {
685 let Some(fro16k) = self.config.fro16k.as_ref() else {
686 return Ok(());
687 };
688 // Enable FRO16K oscillator
689 self.vbat0.froctla().modify(|_, w| w.fro_en().set_bit());
690
691 // Lock the control register
692 self.vbat0.frolcka().modify(|_, w| w.lock().set_bit());
693
694 let Fro16KConfig { vsys_domain_active, vdd_core_domain_active } = fro16k;
695
696 // Enable clock outputs to both VSYS and VDD_CORE domains
697 // Bit 0: clk_16k0 to VSYS domain
698 // Bit 1: clk_16k1 to VDD_CORE domain
699 //
700 // TODO: Define sub-fields for this register with a PAC patch?
701 let mut bits = 0;
702 if *vsys_domain_active {
703 bits |= 0b01;
704 self.clocks.clk_16k_vsys = Some(Clock {
705 frequency: 16_384,
706 power: PoweredClock::AlwaysEnabled,
707 });
708 }
709 if *vdd_core_domain_active {
710 bits |= 0b10;
711 self.clocks.clk_16k_vdd_core = Some(Clock {
712 frequency: 16_384,
713 power: PoweredClock::AlwaysEnabled,
714 });
715 }
716 self.vbat0.froclke().modify(|_r, w| {
717 unsafe { w.clke().bits(bits) }
718 });
719
720 Ok(())
590 } 721 }
591} 722}
592 723
593pub fn init(settings: ClocksConfig) -> Result<(), ClockError> { 724pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
594 critical_section::with(|cs| { 725 critical_section::with(|cs| {
595 if CLOCKS.borrow(cs).is_some() { 726 if CLOCKS.borrow_ref(cs).is_some() {
596 Err(ClockError::AlreadyInitialized) 727 Err(ClockError::AlreadyInitialized)
597 } else { 728 } else {
598 Ok(()) 729 Ok(())
@@ -607,12 +738,20 @@ pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
607 _mrcc0: unsafe { pac::Mrcc0::steal() }, 738 _mrcc0: unsafe { pac::Mrcc0::steal() },
608 scg0: unsafe { pac::Scg0::steal() }, 739 scg0: unsafe { pac::Scg0::steal() },
609 syscon: unsafe { pac::Syscon::steal() }, 740 syscon: unsafe { pac::Syscon::steal() },
741 vbat0: unsafe { pac::Vbat0::steal() },
610 }; 742 };
611 743
612 operator.configure_firc_clocks()?; 744 operator.configure_firc_clocks()?;
613 operator.configure_sirc_clocks()?; 745 operator.configure_sirc_clocks()?;
746 operator.configure_fro16k_clocks()?;
614 // TODO, everything downstream 747 // TODO, everything downstream
615 748
749 critical_section::with(|cs| {
750 let mut clks = CLOCKS.borrow_ref_mut(cs);
751 assert!(clks.is_none(), "Clock setup race!");
752 *clks = Some(clocks);
753 });
754
616 Ok(()) 755 Ok(())
617} 756}
618 757
@@ -621,7 +760,8 @@ pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
621/// NOTE: Clocks implements `Clone`, 760/// NOTE: Clocks implements `Clone`,
622pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> { 761pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> {
623 critical_section::with(|cs| { 762 critical_section::with(|cs| {
624 let c = CLOCKS.borrow(cs).as_ref()?; 763 let c = CLOCKS.borrow_ref(cs);
764 let c = c.as_ref()?;
625 Some(f(c)) 765 Some(f(c))
626 }) 766 })
627} 767}
@@ -629,20 +769,32 @@ pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> {
629impl Clocks { 769impl Clocks {
630 pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 770 pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
631 let Some(clk) = self.fro_lf_div.as_ref() else { 771 let Some(clk) = self.fro_lf_div.as_ref() else {
632 return Err(ClockError::BadConfig { clock: "fro_lf_div", reason: "required but not active" }); 772 return Err(ClockError::BadConfig {
773 clock: "fro_lf_div",
774 reason: "required but not active",
775 });
633 }; 776 };
634 if !clk.power.meets_requirement_of(at_level) { 777 if !clk.power.meets_requirement_of(at_level) {
635 return Err(ClockError::BadConfig { clock: "fro_lf_div", reason: "not low power active" }); 778 return Err(ClockError::BadConfig {
779 clock: "fro_lf_div",
780 reason: "not low power active",
781 });
636 } 782 }
637 Ok(clk.frequency) 783 Ok(clk.frequency)
638 } 784 }
639 785
640 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 786 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
641 let Some(clk) = self.fro_hf_div.as_ref() else { 787 let Some(clk) = self.fro_hf_div.as_ref() else {
642 return Err(ClockError::BadConfig { clock: "fro_hf_div", reason: "required but not active" }); 788 return Err(ClockError::BadConfig {
789 clock: "fro_hf_div",
790 reason: "required but not active",
791 });
643 }; 792 };
644 if !clk.power.meets_requirement_of(at_level) { 793 if !clk.power.meets_requirement_of(at_level) {
645 return Err(ClockError::BadConfig { clock: "fro_hf_div", reason: "not low power active" }); 794 return Err(ClockError::BadConfig {
795 clock: "fro_hf_div",
796 reason: "not low power active",
797 });
646 } 798 }
647 Ok(clk.frequency) 799 Ok(clk.frequency)
648 } 800 }
@@ -657,10 +809,16 @@ impl Clocks {
657 809
658 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 810 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
659 let Some(clk) = self.clk_1m.as_ref() else { 811 let Some(clk) = self.clk_1m.as_ref() else {
660 return Err(ClockError::BadConfig { clock: "clk_1m", reason: "required but not active" }); 812 return Err(ClockError::BadConfig {
813 clock: "clk_1m",
814 reason: "required but not active",
815 });
661 }; 816 };
662 if !clk.power.meets_requirement_of(at_level) { 817 if !clk.power.meets_requirement_of(at_level) {
663 return Err(ClockError::BadConfig { clock: "clk_1m", reason: "not low power active" }); 818 return Err(ClockError::BadConfig {
819 clock: "clk_1m",
820 reason: "not low power active",
821 });
664 } 822 }
665 Ok(clk.frequency) 823 Ok(clk.frequency)
666 } 824 }
@@ -668,5 +826,4 @@ impl Clocks {
668 pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { 826 pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> {
669 Err(ClockError::NotImplemented { clock: "pll1_clk_div" }) 827 Err(ClockError::NotImplemented { clock: "pll1_clk_div" })
670 } 828 }
671
672} 829}
diff --git a/src/clocks/periph_helpers.rs b/src/clocks/periph_helpers.rs
index c4d4e9e3b..4d186acf8 100644
--- a/src/clocks/periph_helpers.rs
+++ b/src/clocks/periph_helpers.rs
@@ -7,6 +7,7 @@ pub trait SPConfHelper {
7 7
8// config types 8// config types
9 9
10#[derive(Debug, Clone, Copy)]
10pub enum LpuartClockSel { 11pub enum LpuartClockSel {
11 /// FRO12M/FRO_LF/SIRC clock source, passed through divider 12 /// FRO12M/FRO_LF/SIRC clock source, passed through divider
12 /// "fro_lf_div" 13 /// "fro_lf_div"
@@ -45,7 +46,7 @@ pub struct LpuartConfig {
45 pub div: Div8, 46 pub div: Div8,
46 /// Which instance is this? 47 /// Which instance is this?
47 // NOTE: should not be user settable 48 // NOTE: should not be user settable
48 instance: LpuartInstance, 49 pub(crate) instance: LpuartInstance,
49} 50}
50 51
51// impls 52// impls
diff --git a/src/lib.rs b/src/lib.rs
index 9899564d8..e3e603ef2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,7 +16,19 @@ pub mod ostimer;
16pub mod rtc; 16pub mod rtc;
17pub mod uart; 17pub mod uart;
18 18
19embassy_hal_internal::peripherals!(LPUART2, OSTIMER0, GPIO, RTC0, ADC1,); 19embassy_hal_internal::peripherals!(
20 PORT1,
21 PORT2,
22 PORT3,
23 LPUART2,
24 OSTIMER0,
25 GPIO,
26 PIO2_2,
27 PIO2_3,
28 GPIO3,
29 RTC0,
30 ADC1,
31);
20 32
21/// Get access to the PAC Peripherals for low-level register access. 33/// Get access to the PAC Peripherals for low-level register access.
22/// This is a lazy-initialized singleton that can be called after init(). 34/// This is a lazy-initialized singleton that can be called after init().
diff --git a/src/lpuart/buffered.rs b/src/lpuart/buffered.rs
index a617c10a5..7b575c086 100644
--- a/src/lpuart/buffered.rs
+++ b/src/lpuart/buffered.rs
@@ -212,10 +212,19 @@ impl<'a> BufferedLpuart<'a> {
212 config.enable_tx = true; 212 config.enable_tx = true;
213 config.enable_rx = true; 213 config.enable_rx = true;
214 214
215 // Enable clocks
216 let conf = LpuartConfig {
217 power: config.power,
218 source: config.source,
219 div: config.div,
220 instance: T::CLOCK_INSTANCE,
221 };
222 let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? };
223
215 // Perform standard initialization 224 // Perform standard initialization
216 perform_software_reset(regs); 225 perform_software_reset(regs);
217 disable_transceiver(regs); 226 disable_transceiver(regs);
218 configure_baudrate(regs, config.baudrate_bps, config.clock)?; 227 configure_baudrate(regs, config.baudrate_bps, clock_freq)?;
219 configure_frame_format(regs, &config); 228 configure_frame_format(regs, &config);
220 configure_control_settings(regs, &config); 229 configure_control_settings(regs, &config);
221 configure_fifo(regs, &config); 230 configure_fifo(regs, &config);
diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs
index 35b531421..41ec951ec 100644
--- a/src/lpuart/mod.rs
+++ b/src/lpuart/mod.rs
@@ -3,6 +3,8 @@ use core::marker::PhantomData;
3use embassy_hal_internal::{Peri, PeripheralType}; 3use embassy_hal_internal::{Peri, PeripheralType};
4use paste::paste; 4use paste::paste;
5 5
6use crate::clocks::periph_helpers::{LpuartClockSel, LpuartConfig};
7use crate::clocks::{enable_and_reset, ClockError, Div8, Gate, PoweredClock};
6use crate::pac::lpuart0::baud::Sbns as StopBits; 8use crate::pac::lpuart0::baud::Sbns as StopBits;
7use 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};
8use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; 10use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
@@ -18,70 +20,7 @@ pub mod buffered;
18// 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
19// Pin and Clock initialization is currently done at the examples level. 21// Pin and Clock initialization is currently done at the examples level.
20 22
21// --- START LIB ---
22
23// Use our own instance of Peripherals, until we align `lib.rs` with the EMBASSY-IMXRT approach
24// Inlined peripherals_definition! to bypass the `Peripherals::take_with_cs()` check
25// SHOULD NOT BE USED IN THE FINAL VERSION
26pub mod lib {
27 // embassy_hal_internal::peripherals!(LPUART2, PIO2_2, PIO2_3)
28
29 embassy_hal_internal::peripherals_definition!(LPUART2, PIO2_2, PIO2_3,);
30 #[doc = r" Struct containing all the peripheral singletons."]
31 #[doc = r""]
32 #[doc = r" To obtain the peripherals, you must initialize the HAL, by calling [`crate::init`]."]
33 #[allow(non_snake_case)]
34 pub struct Peripherals {
35 #[doc = concat!(stringify!(LPUART2)," peripheral")]
36 pub LPUART2: embassy_hal_internal::Peri<'static, peripherals::LPUART2>,
37 #[doc = concat!(stringify!(PIO2_2)," peripheral")]
38 pub PIO2_2: embassy_hal_internal::Peri<'static, peripherals::PIO2_2>,
39 #[doc = concat!(stringify!(PIO2_3)," peripheral")]
40 pub PIO2_3: embassy_hal_internal::Peri<'static, peripherals::PIO2_3>,
41 }
42 impl Peripherals {
43 #[doc = r"Returns all the peripherals *once*"]
44 #[inline]
45 pub(crate) fn take() -> Self {
46 critical_section::with(Self::take_with_cs)
47 }
48 #[doc = r"Returns all the peripherals *once*"]
49 #[inline]
50 pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self {
51 #[no_mangle]
52 static mut _EMBASSY_DEVICE_PERIPHERALS2: bool = false; // ALIGN: Temporary fix to use stub Peripherals
53 unsafe {
54 if _EMBASSY_DEVICE_PERIPHERALS2 {
55 panic!("init called more than once!")
56 }
57 _EMBASSY_DEVICE_PERIPHERALS2 = true;
58 Self::steal()
59 }
60 }
61 }
62 impl Peripherals {
63 #[doc = r" Unsafely create an instance of this peripheral out of thin air."]
64 #[doc = r""]
65 #[doc = r" # Safety"]
66 #[doc = r""]
67 #[doc = r" You must ensure that you're only using one instance of this type at a time."]
68 #[inline]
69 pub unsafe fn steal() -> Self {
70 Self {
71 LPUART2: peripherals::LPUART2::steal(),
72 PIO2_2: peripherals::PIO2_2::steal(),
73 PIO2_3: peripherals::PIO2_3::steal(),
74 }
75 }
76 }
77
78 /// Initialize HAL
79 pub fn init() -> Peripherals {
80 Peripherals::take()
81 }
82}
83 23
84// --- END LIB ---
85 24
86// --- START GPIO --- 25// --- START GPIO ---
87 26
@@ -101,13 +40,13 @@ mod gpio {
101 macro_rules! impl_gpio_pin { 40 macro_rules! impl_gpio_pin {
102 ($($pin:ident),*) => { 41 ($($pin:ident),*) => {
103 $( 42 $(
104 impl SealedPin for super::lib::peripherals::$pin {} 43 impl SealedPin for crate::peripherals::$pin {}
105 44
106 impl GpioPin for super::lib::peripherals::$pin {} 45 impl GpioPin for crate::peripherals::$pin {}
107 46
108 impl From<super::lib::peripherals::$pin> for AnyPin { 47 impl From<crate::peripherals::$pin> for AnyPin {
109 // TODO: AJM: any reason we aren't using $pin? 48 // TODO: AJM: any reason we aren't using $pin?
110 fn from(_val: super::lib::peripherals::$pin) -> Self { 49 fn from(_val: crate::peripherals::$pin) -> Self {
111 AnyPin 50 AnyPin
112 } 51 }
113 } 52 }
@@ -143,18 +82,6 @@ use dma::Channel;
143 82
144// --- END DMA --- 83// --- END DMA ---
145 84
146// --- START CLOCK ---
147mod clock {
148 #[derive(Debug, Clone, Copy)]
149 pub enum Clock {
150 FroLf, // Low-Frequency Free-Running Oscillator
151 }
152}
153
154use clock::Clock;
155
156// --- END CLOCK ---
157
158// ============================================================================ 85// ============================================================================
159// MISC 86// MISC
160// ============================================================================ 87// ============================================================================
@@ -182,7 +109,8 @@ pub struct Info {
182 109
183/// Trait for LPUART peripheral instances 110/// Trait for LPUART peripheral instances
184#[allow(private_bounds)] 111#[allow(private_bounds)]
185pub trait Instance: SealedInstance + PeripheralType + 'static + Send { 112pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = LpuartConfig> {
113 const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance;
186 type Interrupt: interrupt::typelevel::Interrupt; 114 type Interrupt: interrupt::typelevel::Interrupt;
187} 115}
188 116
@@ -190,7 +118,7 @@ macro_rules! impl_instance {
190 ($($n:expr),*) => { 118 ($($n:expr),*) => {
191 $( 119 $(
192 paste!{ 120 paste!{
193 impl SealedInstance for lib::peripherals::[<LPUART $n>] { 121 impl SealedInstance for crate::peripherals::[<LPUART $n>] {
194 fn info() -> Info { 122 fn info() -> Info {
195 Info { 123 Info {
196 regs: unsafe { &*pac::[<Lpuart $n>]::ptr() }, 124 regs: unsafe { &*pac::[<Lpuart $n>]::ptr() },
@@ -208,7 +136,9 @@ macro_rules! impl_instance {
208 } 136 }
209 } 137 }
210 138
211 impl Instance for lib::peripherals::[<LPUART $n>] { 139 impl Instance for crate::peripherals::[<LPUART $n>] {
140 const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance
141 = crate::clocks::periph_helpers::LpuartInstance::[<Lpuart $n>];
212 type Interrupt = crate::interrupt::typelevel::[<LPUART $n>]; 142 type Interrupt = crate::interrupt::typelevel::[<LPUART $n>];
213 } 143 }
214 } 144 }
@@ -236,8 +166,7 @@ pub fn disable_transceiver(regs: Regs) {
236} 166}
237 167
238/// Calculate and configure baudrate settings 168/// Calculate and configure baudrate settings
239pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock: Clock) -> Result<()> { 169pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock_freq: u32) -> Result<()> {
240 let clock_freq = get_fc_freq(clock)?;
241 let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?; 170 let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?;
242 171
243 // Configure BAUD register 172 // Configure BAUD register
@@ -408,16 +337,6 @@ pub fn calculate_baudrate(baudrate: u32, src_clock_hz: u32) -> Result<(u8, u16)>
408 Ok((osr, sbr)) 337 Ok((osr, sbr))
409} 338}
410 339
411pub fn get_fc_freq(clock: Clock) -> Result<u32> {
412 // This is a placeholder - actual implementation would query the clock system
413 // In real implementation, this would get the LPUART clock frequency
414 match clock {
415 Clock::FroLf => Ok(12_000_000), // Low frequency oscillator
416 #[allow(unreachable_patterns)]
417 _ => Err(Error::InvalidArgument),
418 }
419}
420
421/// Wait for all transmit operations to complete 340/// Wait for all transmit operations to complete
422pub fn wait_for_tx_complete(regs: Regs) { 341pub fn wait_for_tx_complete(regs: Regs) {
423 // Wait for TX FIFO to empty 342 // Wait for TX FIFO to empty
@@ -504,7 +423,7 @@ macro_rules! impl_pin_trait {
504 ($fcn:ident, $mode:ident, $($pin:ident, $alt:ident),*) => { 423 ($fcn:ident, $mode:ident, $($pin:ident, $alt:ident),*) => {
505 paste! { 424 paste! {
506 $( 425 $(
507 impl [<$mode:camel Pin>]<lib::peripherals::$fcn> for lib::peripherals::$pin { 426 impl [<$mode:camel Pin>]<crate::peripherals::$fcn> for crate::peripherals::$pin {
508 fn [<as_ $mode>](&self) { 427 fn [<as_ $mode>](&self) {
509 let _alt = gpio::Alt::$alt; 428 let _alt = gpio::Alt::$alt;
510 // todo!("Configure pin for LPUART function") 429 // todo!("Configure pin for LPUART function")
@@ -553,6 +472,8 @@ pub enum Error {
553 TxFifoFull, 472 TxFifoFull,
554 /// TX Busy 473 /// TX Busy
555 TxBusy, 474 TxBusy,
475 /// Clock Error
476 ClockSetup(ClockError),
556} 477}
557 478
558/// A specialized Result type for LPUART operations 479/// A specialized Result type for LPUART operations
@@ -565,10 +486,14 @@ pub type Result<T> = core::result::Result<T, Error>;
565/// Lpuart config 486/// Lpuart config
566#[derive(Debug, Clone, Copy)] 487#[derive(Debug, Clone, Copy)]
567pub struct Config { 488pub struct Config {
489 /// Power state required for this peripheral
490 pub power: PoweredClock,
491 /// Clock source
492 pub source: LpuartClockSel,
493 /// Clock divisor
494 pub div: Div8,
568 /// Baud rate in bits per second 495 /// Baud rate in bits per second
569 pub baudrate_bps: u32, 496 pub baudrate_bps: u32,
570 /// Clock
571 pub clock: Clock,
572 /// Parity configuration 497 /// Parity configuration
573 pub parity_mode: Option<Parity>, 498 pub parity_mode: Option<Parity>,
574 /// Number of data bits 499 /// Number of data bits
@@ -605,7 +530,6 @@ impl Default for Config {
605 fn default() -> Self { 530 fn default() -> Self {
606 Self { 531 Self {
607 baudrate_bps: 115_200u32, 532 baudrate_bps: 115_200u32,
608 clock: Clock::FroLf,
609 parity_mode: None, 533 parity_mode: None,
610 data_bits_count: DataBits::Data8, 534 data_bits_count: DataBits::Data8,
611 msb_firs: MsbFirst::LsbFirst, 535 msb_firs: MsbFirst::LsbFirst,
@@ -621,6 +545,9 @@ impl Default for Config {
621 enable_tx: false, 545 enable_tx: false,
622 enable_rx: false, 546 enable_rx: false,
623 swap_txd_rxd: false, 547 swap_txd_rxd: false,
548 power: PoweredClock::NormalEnabledDeepSleepDisabled,
549 source: LpuartClockSel::FroLfDiv,
550 div: const { Div8::from_divisor(1).unwrap() },
624 } 551 }
625 } 552 }
626} 553}
@@ -706,10 +633,21 @@ impl<'a, M: Mode> Lpuart<'a, M> {
706 ) -> Result<()> { 633 ) -> Result<()> {
707 let regs = T::info().regs; 634 let regs = T::info().regs;
708 635
636 // Enable clocks
637 let conf = LpuartConfig {
638 power: config.power,
639 source: config.source,
640 div: config.div,
641 instance: T::CLOCK_INSTANCE,
642 };
643 let clock_freq = unsafe {
644 enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)?
645 };
646
709 // Perform initialization sequence 647 // Perform initialization sequence
710 perform_software_reset(regs); 648 perform_software_reset(regs);
711 disable_transceiver(regs); 649 disable_transceiver(regs);
712 configure_baudrate(regs, config.baudrate_bps, config.clock)?; 650 configure_baudrate(regs, config.baudrate_bps, clock_freq)?;
713 configure_frame_format(regs, &config); 651 configure_frame_format(regs, &config);
714 configure_control_settings(regs, &config); 652 configure_control_settings(regs, &config);
715 configure_fifo(regs, &config); 653 configure_fifo(regs, &config);