Skip to main content

ch57x_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.r8_ck32k_config().modify(|_, w| w.rb_clk_xt32k_pon().set_bit());
113                });
114                riscv::asm::delay(clocks().hclk.to_Hz() / 10 / 4);
115                //with_safe_access(|| unsafe {
116                //    sys.xt32k_tune().modify(|_, w| w.xt32k_i_tune().bits(0b01));
117                //});
118                with_safe_access(|| {
119                    sys.r8_ck32k_config().modify(|_, w| w.rb_clk_osc32k_xt().set_bit());
120                });
121                riscv::asm::delay(clocks().hclk.to_Hz() / 1000);
122            }
123            Clock32KSrc::LSI => {
124                with_safe_access(|| {
125                    sys.r8_ck32k_config()
126                        .modify(|_, w| w.rb_clk_osc32k_xt().clear_bit().rb_clk_int32k_pon().set_bit());
127                });
128            }
129        }
130
131        with_safe_access(|| unsafe {
132            sys.r8_pll_config().modify(|r, w| w.bits(r.bits() & !(1 << 5)));
133        });
134        let hclk = match self.mux {
135            ClockSrc::HSE(div) => {
136                assert!(div != 1, "1 means close HCLK");
137                if sys.r8_hfck_pwr_ctrl().read().rb_clk_xt32m_pon().bit_is_clear() {
138                    // HSE power on
139                    with_safe_access(|| sys.r8_hfck_pwr_ctrl().modify(|_, w| w.rb_clk_xt32m_pon().set_bit()));
140                    unsafe {
141                        riscv::asm::delay(2400);
142                    }
143                }
144                with_safe_access(|| {
145                    sys.r16_clk_sys_cfg()
146                        .write(|w| unsafe { w.rb_clk_sys_mod().bits(0b00).rb_clk_pll_div().bits(div & 0x1f) });
147                    riscv::asm::nop();
148                    riscv::asm::nop();
149                    riscv::asm::nop();
150                    riscv::asm::nop();
151                });
152                riscv::asm::nop();
153                riscv::asm::nop();
154                with_safe_access(|| {
155                    sys.r8_adc_cfg().write(|w| unsafe { w.bits(0x51) });
156                });
157                Hertz::from_raw(HSE_FREQUENCY.to_Hz() / (div as u32))
158            }
159            ClockSrc::PLL(div) => {
160                assert!(div != 1, "1 means close HCLK");
161                if sys.r8_hfck_pwr_ctrl().read().rb_clk_pll_pon().bit_is_clear() {
162                    // HSE power on
163                    with_safe_access(|| sys.r8_hfck_pwr_ctrl().modify(|_, w| w.rb_clk_pll_pon().set_bit()));
164                    riscv::asm::delay(4000);
165                }
166                with_safe_access(|| {
167                    sys.r16_clk_sys_cfg()
168                        .write(|w| unsafe { w.rb_clk_sys_mod().bits(0b01).rb_clk_pll_div().bits(div & 0x1f) });
169                    riscv::asm::nop();
170                    riscv::asm::nop();
171                    riscv::asm::nop();
172                    riscv::asm::nop();
173                });
174                if div == 6 {
175                    // 80MHz
176                    with_safe_access(|| unsafe {
177                        sys.r8_adc_cfg().modify(|_, w| w.bits(0x02));
178                    });
179                } else {
180                    with_safe_access(|| unsafe {
181                        sys.r8_adc_cfg().modify(|_, w| w.bits(0x52));
182                    });
183                }
184                Hertz::from_raw(PLL_FREQUENCY.to_Hz() / (div as u32))
185            }
186            _ => {
187                // directly from CK32
188                with_safe_access(|| unsafe {
189                    sys.r16_clk_sys_cfg().modify(|r, w| w.bits(r.bits() | 0xC0));
190                });
191                Hertz::from_raw(32_768)
192            }
193        };
194        with_safe_access(|| unsafe {
195            sys.r8_pll_config().modify(|r, w| w.bits(r.bits() | (1 << 7)));
196        });
197
198        unsafe {
199            CLOCK = Clocks { hclk };
200        }
201    }
202}
203
204pub unsafe fn calibrate_lsi() {}