ch58x_hal/
sysctl.rs

1use fugit::HertzU32 as Hertz;
2use qingke::riscv;
3
4use crate::pac::SYS;
5use crate::with_safe_access;
6
7// No HSI
8const 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    // Power on default
13    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/// 32K clock source
27#[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    // CK32K
38    Clock32K,
39    // CK32M from HSE, then div, 2 <= div <= 32
40    HSE(u8),
41    // CK32M from PLL, then div, 2 <= div <= 32
42    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        // LClk32K_Select, config CK32K
109        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(|| unsafe {
118                //    sys.xt32k_tune().modify(|_, w| w.xt32k_i_tune().bits(0b01));
119                //});
120                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                    // HSE power on
143                    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                    // HSE power on
169                    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                    // 80MHz
184                    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                // directly from CK32
196                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() {}