stm32_rust_template/arch/cortex_m4/
systick.rs

1// SysTick (System Timer) register definitions
2// Based on CMSIS Cortex-M4 core_cm4.h
3
4use super::super::super::mcu::stm32f407::PeripheralAccess;
5use core::sync::atomic::{AtomicU32, Ordering};
6
7// SysTick Base Address
8pub const SYSTICK_BASE: u32 = 0xE000E010;
9
10// SysTick Register Block
11#[repr(C)]
12pub struct SysTick {
13    pub ctrl: u32,  // SysTick Control and Status Register
14    pub load: u32,  // SysTick Reload Value Register
15    pub val: u32,   // SysTick Current Value Register
16    pub calib: u32, // SysTick Calibration Register
17}
18
19// SysTick Peripheral Instance
20pub struct SYSTICK;
21
22impl PeripheralAccess for SYSTICK {
23    const BASE_ADDRESS: u32 = SYSTICK_BASE;
24    type RegisterBlock = SysTick;
25}
26
27// Global tick counter
28static TICK_COUNT: AtomicU32 = AtomicU32::new(0);
29
30// Get current tick count
31pub fn get_ticks() -> u32 {
32    TICK_COUNT.load(Ordering::Relaxed)
33}
34
35// Increment tick count (called from interrupt handler)
36pub fn increment_ticks() {
37    TICK_COUNT.fetch_add(1, Ordering::Relaxed);
38}
39
40// SysTick Control / Status Register Definitions
41pub const SYSTICK_CTRL_COUNTFLAG_POS: u32 = 16;
42pub const SYSTICK_CTRL_COUNTFLAG_MSK: u32 = 1 << SYSTICK_CTRL_COUNTFLAG_POS;
43
44pub const SYSTICK_CTRL_CLKSOURCE_POS: u32 = 2;
45pub const SYSTICK_CTRL_CLKSOURCE_MSK: u32 = 1 << SYSTICK_CTRL_CLKSOURCE_POS;
46
47pub const SYSTICK_CTRL_TICKINT_POS: u32 = 1;
48pub const SYSTICK_CTRL_TICKINT_MSK: u32 = 1 << SYSTICK_CTRL_TICKINT_POS;
49
50pub const SYSTICK_CTRL_ENABLE_POS: u32 = 0;
51pub const SYSTICK_CTRL_ENABLE_MSK: u32 = 1;
52
53// SysTick Reload Register Definitions
54pub const SYSTICK_LOAD_RELOAD_POS: u32 = 0;
55pub const SYSTICK_LOAD_RELOAD_MSK: u32 = 0xFFFFFF;
56
57// SysTick Current Register Definitions
58pub const SYSTICK_VAL_CURRENT_POS: u32 = 0;
59pub const SYSTICK_VAL_CURRENT_MSK: u32 = 0xFFFFFF;
60
61// SysTick Calibration Register Definitions
62pub const SYSTICK_CALIB_NOREF_POS: u32 = 31;
63pub const SYSTICK_CALIB_NOREF_MSK: u32 = 1 << SYSTICK_CALIB_NOREF_POS;
64
65pub const SYSTICK_CALIB_SKEW_POS: u32 = 30;
66pub const SYSTICK_CALIB_SKEW_MSK: u32 = 1 << SYSTICK_CALIB_SKEW_POS;
67
68pub const SYSTICK_CALIB_TENMS_POS: u32 = 0;
69pub const SYSTICK_CALIB_TENMS_MSK: u32 = 0xFFFFFF;
70
71// Helper functions for SysTick
72impl SysTick {
73    /// Enable SysTick
74    pub fn enable(&mut self) {
75        self.ctrl |= SYSTICK_CTRL_ENABLE_MSK;
76    }
77
78    /// Disable SysTick
79    pub fn disable(&mut self) {
80        self.ctrl &= !SYSTICK_CTRL_ENABLE_MSK;
81    }
82
83    /// Enable SysTick interrupt
84    pub fn enable_interrupt(&mut self) {
85        self.ctrl |= SYSTICK_CTRL_TICKINT_MSK;
86    }
87
88    /// Disable SysTick interrupt
89    pub fn disable_interrupt(&mut self) {
90        self.ctrl &= !SYSTICK_CTRL_TICKINT_MSK;
91    }
92
93    /// Set clock source to processor clock
94    pub fn set_clock_source_processor(&mut self) {
95        self.ctrl |= SYSTICK_CTRL_CLKSOURCE_MSK;
96    }
97
98    /// Set clock source to external clock
99    pub fn set_clock_source_external(&mut self) {
100        self.ctrl &= !SYSTICK_CTRL_CLKSOURCE_MSK;
101    }
102
103    /// Set reload value
104    pub fn set_reload(&mut self, value: u32) {
105        self.load = value & SYSTICK_LOAD_RELOAD_MSK;
106    }
107
108    /// Get current value
109    pub fn get_current(&self) -> u32 {
110        self.val & SYSTICK_VAL_CURRENT_MSK
111    }
112
113    /// Clear current value (write any value to clear)
114    pub fn clear_current(&mut self) {
115        self.val = 0;
116    }
117
118    /// Check if count flag is set
119    pub fn is_count_flag_set(&self) -> bool {
120        (self.ctrl & SYSTICK_CTRL_COUNTFLAG_MSK) != 0
121    }
122
123    /// Get calibration value for 10ms
124    pub fn get_tenms(&self) -> u32 {
125        self.calib & SYSTICK_CALIB_TENMS_MSK
126    }
127
128    /// Check if calibration has no reference clock
129    pub fn has_no_reference(&self) -> bool {
130        (self.calib & SYSTICK_CALIB_NOREF_MSK) != 0
131    }
132
133    /// Check if calibration is skewed
134    pub fn is_skewed(&self) -> bool {
135        (self.calib & SYSTICK_CALIB_SKEW_MSK) != 0
136    }
137}
138
139/// SysTick Configuration
140/// Initializes the System Timer and its interrupt, and starts the System Tick Timer.
141/// Counter is in free running mode to generate periodic interrupts.
142/// Returns 0 on success, 1 on failure.
143pub fn systick_config(ticks: u32) -> u32 {
144    if (ticks - 1) > SYSTICK_LOAD_RELOAD_MSK {
145        return 1; // Reload value impossible
146    }
147
148    unsafe {
149        let systick = &mut *(SYSTICK_BASE as *mut SysTick);
150        systick.set_reload(ticks - 1);
151        systick.clear_current();
152        systick.set_clock_source_processor();
153        systick.enable_interrupt();
154        systick.enable();
155    }
156
157    0
158}
159
160/// Configure SysTick for 1ms interrupts based on system clock frequency
161/// freq_hz: System clock frequency in Hz (e.g., 168000000 for 168MHz)
162pub fn systick_init_1ms(freq_hz: u32) -> u32 {
163    let ticks = freq_hz / 1000; // 1ms ticks
164    systick_config(ticks)
165}