ch58x_hal/
lib.rs

1#![no_std]
2#![recursion_limit = "1024"]
3use core::ptr;
4
5pub use ch58x::ch58x as pac;
6use qingke::riscv;
7
8pub use self::peripheral::{Peripheral, PeripheralRef};
9pub use self::peripherals::Peripherals;
10
11pub mod adc;
12pub mod dma;
13pub mod gpio;
14pub mod i2c;
15// pub mod lcd;
16#[cfg(feature = "ble")]
17pub mod ble;
18pub mod delay;
19pub mod rtc;
20pub mod signature;
21pub mod spi;
22pub mod sysctl;
23#[cfg(not(feature = "embassy"))]
24pub mod systick;
25pub mod timer;
26pub mod uart;
27
28pub mod interrupt;
29pub mod isp;
30// pub mod rt;
31
32pub mod peripherals;
33
34mod peripheral;
35pub mod prelude;
36
37#[cfg(feature = "embassy")]
38pub mod embassy;
39
40/// Bits per second
41pub type BitsPerSecond = fugit::HertzU32;
42
43/// Extension trait that adds convenience methods to the `u32` type
44pub trait U32Ext {
45    /// Wrap in `Bps`
46    fn bps(self) -> BitsPerSecond;
47}
48
49impl U32Ext for u32 {
50    fn bps(self) -> BitsPerSecond {
51        BitsPerSecond::from_raw(self)
52    }
53}
54
55static mut IRQ_STA: usize = 0;
56
57pub fn with_safe_access<F, R>(f: F) -> R
58where
59    F: FnOnce() -> R,
60{
61    use qingke::register::gintenr;
62
63    const REG_SAFE_ACCESS_SIG: *mut u8 = 0x40001040 as *mut u8;
64    const SAFE_ACCESS_SIG1: u8 = 0x57;
65    const SAFE_ACCESS_SIG2: u8 = 0xA8;
66
67    unsafe {
68        if gintenr::read() & 0x08 != 0 {
69            IRQ_STA = gintenr::read();
70            gintenr::write(IRQ_STA & (!0x08));
71        }
72        riscv::asm::nop();
73        riscv::asm::nop();
74
75        ptr::write_volatile(REG_SAFE_ACCESS_SIG, SAFE_ACCESS_SIG1);
76        ptr::write_volatile(REG_SAFE_ACCESS_SIG, SAFE_ACCESS_SIG2);
77
78        riscv::asm::nop();
79        riscv::asm::nop();
80    }
81    let ret = f();
82    unsafe {
83        ptr::write_volatile(REG_SAFE_ACCESS_SIG, 0);
84        gintenr::write(gintenr::read() | (IRQ_STA & 0x08));
85        IRQ_STA = 0;
86        riscv::asm::nop();
87        riscv::asm::nop();
88    }
89    ret
90}
91
92pub fn delay_us(t: u16) {
93    let t = t as u32;
94    let mut i = match sysctl::clocks().hclk.to_Hz() {
95        60000000 => t * 15,
96        80000000 => t * 20,
97        48000000 => t * 12,
98        32000000 => t * 8,
99        24000000 => t * 6,
100        16000000 => t * 4,
101        8000000 => t * 2,
102        4000000 => t,
103        2000000 => t / 2,
104        1000000 => t / 4,
105        _ => t << 1, // default 2us
106    };
107    i = i / 8;
108    unsafe {
109        core::arch::asm!(
110        "1:",
111        "nop",
112        "addi {0}, {0}, -1",
113        "bne {0}, zero, 1b",
114        inout(reg) i => _,
115        options(nomem, nostack),
116        );
117    }
118}
119
120pub fn delay_ms(t: u16) {
121    for _ in 0..t {
122        delay_us(1000);
123    }
124}
125
126#[derive(Debug, Clone, Default)]
127pub struct Config {
128    pub clock: sysctl::Config,
129    /// All GPIO Input Pull Up, aka. HAL_SLEEP
130    pub low_power: bool,
131    /// Enable DCDC, aka. DCDC_ENABLE
132    pub enable_dcdc: bool,
133}
134
135pub fn init(config: Config) -> Peripherals {
136    let sys = unsafe { &*pac::SYS::PTR };
137    if config.enable_dcdc {
138        with_safe_access(|| {
139            sys.aux_power_adj().modify(|_, w| w.dcdc_charge().set_bit());
140            sys.power_plan().modify(|_, w| w.pwr_dcdc_pre().set_bit());
141        });
142        delay_us(10);
143        with_safe_access(|| {
144            sys.power_plan().modify(|_, w| w.pwr_dcdc_en().set_bit());
145        });
146    } else {
147        with_safe_access(|| {
148            sys.aux_power_adj().modify(|_, w| w.dcdc_charge().clear_bit());
149            sys.power_plan()
150                .modify(|_, w| w.pwr_dcdc_pre().clear_bit().pwr_dcdc_pre().clear_bit());
151        });
152    }
153
154    config.clock.freeze();
155
156    if config.low_power {
157        unsafe {
158            for rb in [&*pac::GPIOA::PTR, &*pac::GPIOB::PTR] {
159                // in pu
160                rb.pd_drv().write(|w| w.bits(0));
161                rb.pu().write(|w| w.bits(0xffff));
162                rb.dir().write(|w| w.bits(0));
163            }
164        }
165    }
166
167    Peripherals::take()
168}
169
170/// System reset
171pub unsafe fn reset() -> ! {
172    const KEY3: u16 = 0xBEEF;
173    let pfic = unsafe { &*pac::PFIC::PTR };
174    pfic.cfgr().write(|w| w.keycode().variant(KEY3).resetsys().set_bit());
175    loop {}
176}
177
178/// Software reset
179pub unsafe fn soft_reset() -> ! {
180    isp::flash_rom_reset();
181
182    let rb = unsafe { &*pac::SYS::PTR };
183    with_safe_access(|| {
184        rb.rst_wdog_ctrl().modify(|_, w| w.software_reset().set_bit());
185    });
186    loop {}
187}
188
189pub static mut SERIAL: Option<uart::UartTx<peripherals::UART1>> = None;
190
191#[macro_export]
192macro_rules! println {
193    ($($arg:tt)*) => {
194        unsafe {
195            use core::fmt::Write;
196            use core::writeln;
197
198            if let Some(uart) = $crate::SERIAL.as_mut() {
199                writeln!(uart, $($arg)*).unwrap();
200            }
201        }
202    }
203}
204
205pub unsafe fn set_default_serial(serial: uart::UartTx<'static, peripherals::UART1>) {
206    SERIAL.replace(serial);
207}
208
209pub fn stack_free() -> usize {
210    extern "C" {
211        static mut _ebss: u32;
212        static mut _stack_top: u32;
213    }
214    unsafe { &mut _stack_top as *mut u32 as usize - &mut _ebss as *mut u32 as usize }
215}