1use fugit::HertzU32 as Hertz;
2use qingke::riscv;
3
4use crate::pac::SYS;
5use crate::with_safe_access;
6
7const HSE_FREQUENCY: Hertz = Hertz::from_raw(32_000_000);
9const PLL_FREQUENCY: Hertz = Hertz::from_raw(480_000_000);
10
11static mut CLOCK: Clocks = Clocks {
12 hclk: Hertz::from_raw(6_400_000),
14};
15
16#[derive(Copy, Clone, Eq, PartialEq, Debug)]
17pub struct Clocks {
18 pub hclk: Hertz,
19}
20
21#[inline]
22pub fn clocks() -> &'static Clocks {
23 unsafe { &CLOCK }
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Default)]
28pub enum Clock32KSrc {
29 #[default]
30 LSI,
31 LSE,
32}
33
34#[derive(Clone, Copy, Debug, PartialEq)]
35#[repr(u8)]
36pub enum ClockSrc {
37 Clock32K,
39 HSE(u8),
41 PLL(u8),
43}
44
45impl Default for ClockSrc {
46 fn default() -> Self {
47 Self::PLL(8)
48 }
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Default)]
52pub struct Config {
53 pub clock32ksrc: Clock32KSrc,
54 pub mux: ClockSrc,
55}
56
57impl Config {
58 pub fn use_lsi_32k(&mut self) -> &mut Self {
59 self.clock32ksrc = Clock32KSrc::LSI;
60 self.mux = ClockSrc::Clock32K;
61 self
62 }
63
64 pub fn use_lse_32k(&mut self) -> &mut Self {
65 self.clock32ksrc = Clock32KSrc::LSE;
66 self.mux = ClockSrc::Clock32K;
67 self
68 }
69
70 pub fn use_pll_60mhz(&mut self) -> &mut Self {
71 self.mux = ClockSrc::PLL(8);
72 self
73 }
74
75 pub fn use_pll_80mhz(&mut self) -> &mut Self {
76 self.mux = ClockSrc::PLL(6);
77 self
78 }
79
80 pub fn use_pll_48mhz(&mut self) -> &mut Self {
81 self.mux = ClockSrc::PLL(10);
82 self
83 }
84
85 pub fn use_pll_32mhz(&mut self) -> &mut Self {
86 self.mux = ClockSrc::PLL(15);
87 self
88 }
89
90 pub fn use_pll_24mhz(&mut self) -> &mut Self {
91 self.mux = ClockSrc::PLL(20);
92 self
93 }
94
95 pub fn use_pll_20mhz(&mut self) -> &mut Self {
96 self.mux = ClockSrc::PLL(24);
97 self
98 }
99
100 pub fn enable_lse(&mut self) -> &mut Self {
101 self.clock32ksrc = Clock32KSrc::LSE;
102 self
103 }
104
105 pub fn freeze(self) {
106 let sys = unsafe { &*SYS::PTR };
107
108 match self.clock32ksrc {
110 Clock32KSrc::LSE => {
111 with_safe_access(|| {
112 sys.ck32k_config().modify(|_, w| w.clk_xt32k_pon().set_bit());
113 });
114 unsafe {
115 riscv::asm::delay(clocks().hclk.to_Hz() / 10 / 4);
116 }
117 with_safe_access(|| {
121 sys.ck32k_config().modify(|_, w| w.clk_osc32k_xt().set_bit());
122 });
123 unsafe {
124 riscv::asm::delay(clocks().hclk.to_Hz() / 1000);
125 }
126 }
127 Clock32KSrc::LSI => {
128 with_safe_access(|| {
129 sys.ck32k_config()
130 .modify(|_, w| w.clk_osc32k_xt().clear_bit().clk_int32k_pon().set_bit());
131 });
132 }
133 }
134
135 with_safe_access(|| unsafe {
136 sys.pll_config().modify(|r, w| w.bits(r.bits() & !(1 << 5)));
137 });
138 let hclk = match self.mux {
139 ClockSrc::HSE(div) => {
140 assert!(div != 1, "1 means close HCLK");
141 if sys.hfck_pwr_ctrl().read().clk_xt32m_pon().bit_is_clear() {
142 with_safe_access(|| sys.hfck_pwr_ctrl().modify(|_, w| w.clk_xt32m_pon().set_bit()));
144 unsafe {
145 riscv::asm::delay(2400);
146 }
147 }
148 with_safe_access(|| unsafe {
149 sys.clk_sys_cfg()
150 .write(|w| w.clk_sys_mod().variant(0b00).clk_pll_div().variant(div & 0x1f));
151 riscv::asm::nop();
152 riscv::asm::nop();
153 riscv::asm::nop();
154 riscv::asm::nop();
155 });
156 unsafe {
157 riscv::asm::nop();
158 riscv::asm::nop();
159 }
160 with_safe_access(|| unsafe {
161 sys.flash_cfg().write(|w| w.bits(0x51));
162 });
163 Hertz::from_raw(HSE_FREQUENCY.to_Hz() / (div as u32))
164 }
165 ClockSrc::PLL(div) => {
166 assert!(div != 1, "1 means close HCLK");
167 if sys.hfck_pwr_ctrl().read().clk_pll_pon().bit_is_clear() {
168 with_safe_access(|| sys.hfck_pwr_ctrl().modify(|_, w| w.clk_pll_pon().set_bit()));
170 unsafe {
171 riscv::asm::delay(4000);
172 }
173 }
174 with_safe_access(|| unsafe {
175 sys.clk_sys_cfg()
176 .write(|w| w.clk_sys_mod().bits(0b01).clk_pll_div().bits(div & 0x1f));
177 riscv::asm::nop();
178 riscv::asm::nop();
179 riscv::asm::nop();
180 riscv::asm::nop();
181 });
182 if div == 6 {
183 with_safe_access(|| unsafe {
185 sys.flash_cfg().modify(|_, w| w.bits(0x02));
186 });
187 } else {
188 with_safe_access(|| unsafe {
189 sys.flash_cfg().modify(|_, w| w.bits(0x52));
190 });
191 }
192 Hertz::from_raw(PLL_FREQUENCY.to_Hz() / (div as u32))
193 }
194 _ => {
195 with_safe_access(|| unsafe {
197 sys.clk_sys_cfg().modify(|r, w| w.bits(r.bits() | 0xC0));
198 });
199 Hertz::from_raw(32_768)
200 }
201 };
202 with_safe_access(|| unsafe {
203 sys.pll_config().modify(|r, w| w.bits(r.bits() | (1 << 7)));
204 });
205
206 unsafe {
207 CLOCK = Clocks { hclk };
208 }
209 }
210}
211
212pub unsafe fn calibrate_lsi() {}