Skip to main content

ch57x_hal/
lib.rs

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