From 0988f2ce50c8aed6b062c8ed23dc0847b7c824a1 Mon Sep 17 00:00:00 2001 From: Gabriel <69007475+Friendly-Banana@users.noreply.github.com> Date: Sun, 3 May 2026 20:07:55 +0000 Subject: [PATCH 1/7] add RTC --- machine/api/src/lib.rs | 2 + machine/cortex-m/src/native.rs | 8 + machine/cortex-m/src/stub.rs | 7 + machine/cortex-m/st/stm32l4/interface/clock.c | 144 ++++++++++++++++++ .../cortex-m/st/stm32l4/interface/export.h | 2 + src/lib.rs | 5 +- src/time.rs | 125 +++++++++++++++ 7 files changed, 292 insertions(+), 1 deletion(-) diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index f54884a3..097d7552 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -32,6 +32,8 @@ pub trait Machinelike { fn monotonic_now() -> u64; fn monotonic_freq() -> u64; + fn get_rtc_raw() -> u64; + fn set_rtc_raw(time: u64); // Returns the frequency of the machine's systick timer in Hz. fn systick_freq() -> u64; diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index 4e51b59f..2d2af9e2 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -110,6 +110,14 @@ impl hal_api::Machinelike for ArmMachine { unsafe { bindings::monotonic_freq() } } + fn get_rtc_raw() -> u64 { + unsafe { bindings::get_rtc_raw() } + } + + fn set_rtc_raw(time: u64) { + unsafe { bindings::set_rtc_raw(time) } + } + fn systick_freq() -> u64 { unsafe { bindings::systick_freq() } } diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index f89334b6..69486fd8 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -47,6 +47,13 @@ impl hal_api::Machinelike for StubMachine { 0 } + fn get_rtc_raw() -> u64 { + 0 + } + + fn set_rtc_raw(_time: u64) { + } + fn systick_freq() -> u64 { 0 } diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index 980e8357..c75d6719 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -1,11 +1,102 @@ #include "lib.h" #include +#include #include +#include "stm32l4xx_hal_rcc.h" +#include #include static volatile uint64_t monotonic_hi = 0; static volatile uint32_t tick = 0; +#define RTC_BKP_MAGIC 0x4F534952U +#define LSE_READY_TIMEOUT_LOOPS 2000000U +#define LSI_READY_TIMEOUT_LOOPS 200000U + +static RTC_HandleTypeDef rtc_handle; + +static int wait_rcc_ready_flag(uint32_t flag, uint32_t timeout_loops) +{ + while (timeout_loops > 0U) { + if (__HAL_RCC_GET_FLAG(flag) != RESET) { + return 1; + } + + timeout_loops--; + } + + return 0; +} + +static HAL_StatusTypeDef select_rtc_clock_source(uint32_t source) +{ + RCC_PeriphCLKInitTypeDef periph = {0}; + + periph.PeriphClockSelection = RCC_PERIPHCLK_RTC; + periph.RTCClockSelection = source; + + return HAL_RCCEx_PeriphCLKConfig(&periph); +} + +static void init_rtc_clock_source(void) +{ + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH); + __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); + + if (wait_rcc_ready_flag(RCC_FLAG_LSERDY, LSE_READY_TIMEOUT_LOOPS)) { + if (select_rtc_clock_source(RCC_RTCCLKSOURCE_LSE) != HAL_OK) { + while (1) { + } + } + } else { + __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); + __HAL_RCC_LSI_ENABLE(); + + if (!wait_rcc_ready_flag(RCC_FLAG_LSIRDY, LSI_READY_TIMEOUT_LOOPS) || + select_rtc_clock_source(RCC_RTCCLKSOURCE_LSI) != HAL_OK) { + while (1) { + } + } + } + + __HAL_RCC_RTC_ENABLE(); +} + +void set_rtc_raw(unsigned long long raw); +void init_rtc(void) +{ + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWR_EnableBkUpAccess(); + + init_rtc_clock_source(); + + rtc_handle.Instance = RTC; + rtc_handle.Init.HourFormat = RTC_HOURFORMAT_24; + rtc_handle.Init.AsynchPrediv = 0x7FU; + rtc_handle.Init.SynchPrediv = 0x00FFU; + rtc_handle.Init.OutPut = RTC_OUTPUT_DISABLE; + rtc_handle.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; + rtc_handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + rtc_handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + + if (HAL_RTC_Init(&rtc_handle) != HAL_OK) { + while (1) { + } + } + + if (HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0) != RTC_BKP_MAGIC) { + // Sat 01.01.2000 + unsigned long long time = ((uint64_t)0) | + ((uint64_t)0 << 8U) | + ((uint64_t)0 << 16U) | + ((uint64_t)RTC_WEEKDAY_SATURDAY << 32U) | + ((uint64_t)RTC_MONTH_JANUARY << 40U) | + ((uint64_t)0 << 48U) | + ((uint64_t)0 << 56U); + set_rtc_raw(time); + } +} + static void init_monotonic_timer(void) { const uint32_t target_hz = 1000000U; @@ -102,6 +193,7 @@ void init_clock_cfg(void) SystemCoreClockUpdate(); init_monotonic_timer(); + init_rtc(); } unsigned long long monotonic_now(void) @@ -165,3 +257,55 @@ void do_tick(void) { tick++; } + +} + +unsigned long long get_rtc_raw(void) +{ + RTC_TimeTypeDef time = {0}; + RTC_DateTypeDef date = {0}; + + if (HAL_RTC_GetTime(&rtc_handle, &time, RTC_FORMAT_BCD) != HAL_OK) { + return 0U; + } + + if (HAL_RTC_GetDate(&rtc_handle, &date, RTC_FORMAT_BCD) != HAL_OK) { + return 0U; + } + + return ((uint64_t)time.Hours) | + ((uint64_t)time.Minutes << 8U) | + ((uint64_t)time.Seconds << 16U) | + ((uint64_t)date.WeekDay << 32U) | + ((uint64_t)date.Month << 40U) | + ((uint64_t)date.Date << 48U) | + ((uint64_t)date.Year << 56U); +} + +void set_rtc_raw(unsigned long long raw) +{ + RTC_TimeTypeDef rtc_time = {0}; + RTC_DateTypeDef rtc_date = {0}; + + rtc_time.Hours = (uint8_t)(raw & 0xFFU); + rtc_time.Minutes = (uint8_t)((raw >> 8U) & 0xFFU); + rtc_time.Seconds = (uint8_t)((raw >> 16U) & 0xFFU); + rtc_time.TimeFormat = RTC_HOURFORMAT_24; + + rtc_date.WeekDay = (uint8_t)((raw >> 32U) & 0xFFU); + rtc_date.Month = (uint8_t)((raw >> 40U) & 0xFFU); + rtc_date.Date = (uint8_t)((raw >> 48U) & 0xFFU); + rtc_date.Year = (uint8_t)((raw >> 56U) & 0xFFU); + + if (HAL_RTC_SetTime(&rtc_handle, &rtc_time, RTC_FORMAT_BCD) != HAL_OK) { + while (1) { + } + } + + if (HAL_RTC_SetDate(&rtc_handle, &rtc_date, RTC_FORMAT_BCD) != HAL_OK) { + while (1) { + } + } + + HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0, RTC_BKP_MAGIC); +} \ No newline at end of file diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index f8c41029..bdbb5632 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -253,3 +253,5 @@ unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); void do_tick(void); void tim2_hndlr(void); +unsigned long long get_rtc_raw(void); +void set_rtc_raw(unsigned long long time); diff --git a/src/lib.rs b/src/lib.rs index 2e195e57..f8e758db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,10 @@ pub unsafe extern "C" fn kernel_init() -> ! { kprint!("Scheduler initialized.\n"); idle::init(); - kprint!("Idle thread initialized.\n"); + kprintln!("Idle thread initialized.\n"); + + time::init(); + kprintln!("Time thread initialized.\n"); let (cyc, _ns) = hal::Machine::bench_end(); kprint!("Kernel init took {} cycles.\n", cyc); diff --git a/src/time.rs b/src/time.rs index e5379b20..1b0d8619 100644 --- a/src/time.rs +++ b/src/time.rs @@ -4,6 +4,131 @@ use crate::{sched, sync}; static TICKS: sync::atomic::AtomicU64 = sync::atomic::AtomicU64::new(0); +extern "C" fn update_time() { + let interval: u64 = mono_freq() / 10; // ~100 seconds in ticks + kprintln!( + "Time thread started with tick interval {} at {}", + interval, + get_actual_time() + ); + loop { + let tick = tick(); + + sched::with(|sched| { + kprintln!("time is now {}", get_actual_time()); + let _ = sched.sleep_until(tick + interval, tick); + }); + } +} + +pub fn init() { + let attrs = sched::thread::Attributes { + entry: update_time, + fin: None, + attrs: None, + }; + + sched::with(|sched| { + if let Ok(uid) = sched.create_thread(Some(sched::task::KERNEL_TASK), &attrs) { + if sched.enqueue(tick(), uid).is_err() { + panic!("failed to enqueue time thread."); + } + } else { + panic!("failed to create time task."); + } + }) +} + +pub fn get_actual_time() -> u64 { + let raw = sync::atomic::irq_free(|| hal::Machine::get_rtc_raw()); + rtc_raw_to_unix(raw) +} + +pub fn set_actual_time(time: u64) { + let raw = unix_to_rtc_raw(time); + sync::atomic::irq_free(|| hal::Machine::set_rtc_raw(raw)) +} + +const fn bcd_to_bin(value: u8) -> u8 { + ((value >> 4) * 10) + (value & 0x0f) +} + +const fn bin_to_bcd(value: u8) -> u8 { + ((value / 10) << 4) | (value % 10) +} + +const fn is_leap_year(year: u32) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} + +const fn days_in_month(year: u32, month: u32) -> u32 { + match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 if is_leap_year(year) => 29, + 2 => 28, + _ => 0, + } +} + +fn days_since_unix_epoch(year: u32, month: u32, day: u32) -> u64 { + let mut days = 0u64; + for y in 1970..year { + days += if is_leap_year(y) { 366 } else { 365 }; + } + for m in 1..month { + days += days_in_month(year, m) as u64; + } + days + u64::from(day.saturating_sub(1)) +} + +fn rtc_raw_to_unix(raw: u64) -> u64 { + let hours = bcd_to_bin((raw & 0xff) as u8) as u64; + let minutes = bcd_to_bin(((raw >> 8) & 0xff) as u8) as u64; + let seconds = bcd_to_bin(((raw >> 16) & 0xff) as u8) as u64; + let weekday = ((raw >> 32) & 0xff) as u8; + let year = 2000 + u32::from(bcd_to_bin(((raw >> 56) & 0xff) as u8)); + let month = u32::from(bcd_to_bin(((raw >> 40) & 0xff) as u8)); + let day = u32::from(bcd_to_bin(((raw >> 48) & 0xff) as u8)); + + days_since_unix_epoch(year, month, day) * 86_400 + hours * 3_600 + minutes * 60 + seconds +} + +fn unix_to_rtc_raw(unix: u64) -> u64 { + let epoch_2000 = 946_684_800u64; + let mut seconds = unix.saturating_sub(epoch_2000); + let mut days = seconds / 86_400; + seconds %= 86_400; + + let mut year = 2000u32; + while days >= if is_leap_year(year) { 366 } else { 365 } { + days -= if is_leap_year(year) { 366 } else { 365 }; + year += 1; + } + + let mut month = 1u32; + while days >= u64::from(days_in_month(year, month)) { + days -= u64::from(days_in_month(year, month)); + month += 1; + } + + let day = (days + 1) as u32; + let weekday = (((days_since_unix_epoch(year, month, day) + 4) % 7) + 1) as u8; + + let hours = (seconds / 3_600) as u8; + seconds %= 3_600; + let minutes = (seconds / 60) as u8; + let seconds = (seconds % 60) as u8; + + (u64::from(bin_to_bcd(hours))) + | (u64::from(bin_to_bcd(minutes)) << 8) + | (u64::from(bin_to_bcd(seconds)) << 16) + | (u64::from(weekday) << 32) + | (u64::from(bin_to_bcd(month as u8)) << 40) + | (u64::from(bin_to_bcd(day as u8)) << 48) + | (u64::from(bin_to_bcd((year - 2000) as u8)) << 56) +} + pub fn tick() -> u64 { TICKS.load(sync::atomic::Ordering::Acquire) } From 39bd9355742eb3beb9cceb764c5a221e428c6cf7 Mon Sep 17 00:00:00 2001 From: Gabriel <69007475+Friendly-Banana@users.noreply.github.com> Date: Sun, 3 May 2026 20:09:47 +0000 Subject: [PATCH 2/7] expose RTC backup registers --- machine/api/src/lib.rs | 4 ++++ machine/cortex-m/src/native.rs | 8 ++++++++ machine/cortex-m/src/stub.rs | 7 +++++++ machine/cortex-m/st/stm32l4/interface/clock.c | 10 ++++++++++ machine/cortex-m/st/stm32l4/interface/export.h | 3 +++ src/time.rs | 12 ++++++++++++ 6 files changed, 44 insertions(+) diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index 097d7552..7cc35099 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -34,6 +34,10 @@ pub trait Machinelike { fn monotonic_freq() -> u64; fn get_rtc_raw() -> u64; fn set_rtc_raw(time: u64); + // index 0..32, 0 is used by the RTC + fn get_rtc_backup_register(index: u8) -> u32; + // index 0..32, 0 is used by the RTC + fn set_rtc_backup_register(index: u8, value: u32); // Returns the frequency of the machine's systick timer in Hz. fn systick_freq() -> u64; diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index 2d2af9e2..20234e58 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -118,6 +118,14 @@ impl hal_api::Machinelike for ArmMachine { unsafe { bindings::set_rtc_raw(time) } } + fn get_rtc_backup_register(index: u8) -> u32 { + unsafe { bindings::get_rtc_backup_register(index) } + } + + fn set_rtc_backup_register(index: u8, value: u32) { + unsafe { bindings::set_rtc_backup_register(index, value) } + } + fn systick_freq() -> u64 { unsafe { bindings::systick_freq() } } diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index 69486fd8..9aac6eac 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -54,6 +54,13 @@ impl hal_api::Machinelike for StubMachine { fn set_rtc_raw(_time: u64) { } + fn get_rtc_backup_register(index: u8) -> u32 { + 0 + } + + fn set_rtc_backup_register(index: u8, value: u32) { + } + fn systick_freq() -> u64 { 0 } diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index c75d6719..6f7e71ea 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -258,6 +258,16 @@ void do_tick(void) tick++; } + +long get_rtc_backup_register(unsigned index) +{ + return HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0 + index); +} + +void set_rtc_backup_register(unsigned index, long value) +{ + assert(index != 0 && "Register 0 is reserved for RTC init"); + HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0 + index, value); } unsigned long long get_rtc_raw(void) diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index bdbb5632..9ac07796 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -255,3 +255,6 @@ void do_tick(void); void tim2_hndlr(void); unsigned long long get_rtc_raw(void); void set_rtc_raw(unsigned long long time); + +unsigned long get_rtc_backup_register(unsigned char index); +void set_rtc_backup_register(unsigned char index, unsigned long value); diff --git a/src/time.rs b/src/time.rs index 1b0d8619..a1a30f08 100644 --- a/src/time.rs +++ b/src/time.rs @@ -39,6 +39,18 @@ pub fn init() { }) } +pub fn get_rtc_backup_register(index: u8) -> u32 { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index == 0, "RTC uses this register for restart continuity"); + hal::Machine::get_rtc_backup_register(index) +} + +pub fn set_rtc_backup_register(index: u8, value: u32) { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index == 0, "RTC uses this register for restart continuity"); + hal::Machine::set_rtc_backup_register(index, value) +} + pub fn get_actual_time() -> u64 { let raw = sync::atomic::irq_free(|| hal::Machine::get_rtc_raw()); rtc_raw_to_unix(raw) From 431251edd0ba9d90c862168da6965f9bfe0b66c4 Mon Sep 17 00:00:00 2001 From: Gabriel Kuznik Date: Wed, 13 May 2026 15:17:52 +0200 Subject: [PATCH 3/7] add error handling rename functions --- machine/api/src/lib.rs | 6 +- machine/cortex-m/src/native.rs | 15 ++-- machine/cortex-m/src/stub.rs | 7 +- machine/cortex-m/st/stm32l4/interface/clock.c | 82 ++++++++++--------- .../cortex-m/st/stm32l4/interface/export.h | 8 +- machine/cortex-m/st/stm32l4/interface/lib.c | 21 +++-- machine/cortex-m/st/stm32l4/interface/lib.h | 2 +- src/lib.rs | 2 +- src/time.rs | 37 ++++++--- 9 files changed, 106 insertions(+), 74 deletions(-) diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index 7cc35099..6144a68a 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -32,10 +32,10 @@ pub trait Machinelike { fn monotonic_now() -> u64; fn monotonic_freq() -> u64; - fn get_rtc_raw() -> u64; - fn set_rtc_raw(time: u64); + fn rtc_raw() -> u64; + fn set_rtc_raw(time: u64) -> i32; // index 0..32, 0 is used by the RTC - fn get_rtc_backup_register(index: u8) -> u32; + fn rtc_backup_register(index: u8) -> u32; // index 0..32, 0 is used by the RTC fn set_rtc_backup_register(index: u8, value: u32); // Returns the frequency of the machine's systick timer in Hz. diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index 20234e58..e1542230 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -45,7 +45,10 @@ fn monotonic_overflow_irq(_ctx: *mut u8, _vector: usize, _userdata: Option u64 { - unsafe { bindings::get_rtc_raw() } + fn rtc_raw() -> u64 { + unsafe { bindings::rtc_raw() } } - fn set_rtc_raw(time: u64) { + fn set_rtc_raw(time: u64) -> i32 { unsafe { bindings::set_rtc_raw(time) } } - fn get_rtc_backup_register(index: u8) -> u32 { - unsafe { bindings::get_rtc_backup_register(index) } + fn rtc_backup_register(index: u8) -> u32 { + unsafe { bindings::rtc_backup_register(index) } } fn set_rtc_backup_register(index: u8, value: u32) { diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index 9aac6eac..c714e78a 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -47,14 +47,15 @@ impl hal_api::Machinelike for StubMachine { 0 } - fn get_rtc_raw() -> u64 { + fn rtc_raw() -> u64 { 0 } - fn set_rtc_raw(_time: u64) { + fn set_rtc_raw(_time: u64) -> i32 { + 0 } - fn get_rtc_backup_register(index: u8) -> u32 { + fn rtc_backup_register(index: u8) -> u32 { 0 } diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index 6f7e71ea..bbee93dd 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -13,13 +13,19 @@ static volatile uint32_t tick = 0; #define LSE_READY_TIMEOUT_LOOPS 2000000U #define LSI_READY_TIMEOUT_LOOPS 200000U +#define ERROR_CONTROL_VOLTAGE_SCALING -1 +#define ERROR_RCC_OSC_CONFIG -2 +#define ERROR_RCC_CLOCK_CONFIG -3 +#define ERROR_RTC_INIT_CLOCK_SOURCE -4 +#define ERROR_RTC_INIT -5 + static RTC_HandleTypeDef rtc_handle; static int wait_rcc_ready_flag(uint32_t flag, uint32_t timeout_loops) { while (timeout_loops > 0U) { if (__HAL_RCC_GET_FLAG(flag) != RESET) { - return 1; + return -1; } timeout_loops--; @@ -38,37 +44,38 @@ static HAL_StatusTypeDef select_rtc_clock_source(uint32_t source) return HAL_RCCEx_PeriphCLKConfig(&periph); } -static void init_rtc_clock_source(void) +static int init_rtc_clock_source(void) { __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH); __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); - if (wait_rcc_ready_flag(RCC_FLAG_LSERDY, LSE_READY_TIMEOUT_LOOPS)) { - if (select_rtc_clock_source(RCC_RTCCLKSOURCE_LSE) != HAL_OK) { - while (1) { - } - } - } else { - __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); - __HAL_RCC_LSI_ENABLE(); - - if (!wait_rcc_ready_flag(RCC_FLAG_LSIRDY, LSI_READY_TIMEOUT_LOOPS) || - select_rtc_clock_source(RCC_RTCCLKSOURCE_LSI) != HAL_OK) { - while (1) { - } - } + if (!wait_rcc_ready_flag(RCC_FLAG_LSERDY, LSE_READY_TIMEOUT_LOOPS) && + select_rtc_clock_source(RCC_RTCCLKSOURCE_LSE) == HAL_OK) { + __HAL_RCC_RTC_ENABLE(); + return 0; } - - __HAL_RCC_RTC_ENABLE(); + + __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); + __HAL_RCC_LSI_ENABLE(); + + if (!wait_rcc_ready_flag(RCC_FLAG_LSIRDY, LSI_READY_TIMEOUT_LOOPS) && + select_rtc_clock_source(RCC_RTCCLKSOURCE_LSI) == HAL_OK) { + __HAL_RCC_RTC_ENABLE(); + return 0; + } + return -1; } -void set_rtc_raw(unsigned long long raw); -void init_rtc(void) +int set_rtc_raw(unsigned long long raw); +int init_rtc(void) { __HAL_RCC_PWR_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); - init_rtc_clock_source(); + // TODO: setup Clock Security System + if (init_rtc_clock_source()) { + return ERROR_RTC_INIT_CLOCK_SOURCE; + } rtc_handle.Instance = RTC; rtc_handle.Init.HourFormat = RTC_HOURFORMAT_24; @@ -80,8 +87,7 @@ void init_rtc(void) rtc_handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&rtc_handle) != HAL_OK) { - while (1) { - } + return ERROR_RTC_INIT; } if (HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0) != RTC_BKP_MAGIC) { @@ -91,10 +97,11 @@ void init_rtc(void) ((uint64_t)0 << 16U) | ((uint64_t)RTC_WEEKDAY_SATURDAY << 32U) | ((uint64_t)RTC_MONTH_JANUARY << 40U) | - ((uint64_t)0 << 48U) | + ((uint64_t)1 << 48U) | ((uint64_t)0 << 56U); - set_rtc_raw(time); + return set_rtc_raw(time); } + return 0; } static void init_monotonic_timer(void) @@ -147,7 +154,7 @@ void tim2_hndlr(void) } } -void init_clock_cfg(void) +int init_clock_cfg(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; @@ -156,7 +163,7 @@ void init_clock_cfg(void) __HAL_RCC_PWR_CLK_ENABLE(); if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { - while (1) {} + return ERROR_CONTROL_VOLTAGE_SCALING; } /* HSI16 -> PLL -> 80 MHz SYSCLK */ @@ -173,7 +180,7 @@ void init_clock_cfg(void) RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // arbitrary unless you use PLLQ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - while (1) {} + return ERROR_RCC_OSC_CONFIG; } RCC_ClkInitStruct.ClockType = @@ -188,12 +195,12 @@ void init_clock_cfg(void) RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { - while (1) {} + return ERROR_RCC_CLOCK_CONFIG; } SystemCoreClockUpdate(); init_monotonic_timer(); - init_rtc(); + return init_rtc(); } unsigned long long monotonic_now(void) @@ -270,17 +277,17 @@ void set_rtc_backup_register(unsigned index, long value) HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0 + index, value); } -unsigned long long get_rtc_raw(void) +unsigned long long rtc_raw(void) { RTC_TimeTypeDef time = {0}; RTC_DateTypeDef date = {0}; if (HAL_RTC_GetTime(&rtc_handle, &time, RTC_FORMAT_BCD) != HAL_OK) { - return 0U; + return -1U; } if (HAL_RTC_GetDate(&rtc_handle, &date, RTC_FORMAT_BCD) != HAL_OK) { - return 0U; + return -2U; } return ((uint64_t)time.Hours) | @@ -292,7 +299,7 @@ unsigned long long get_rtc_raw(void) ((uint64_t)date.Year << 56U); } -void set_rtc_raw(unsigned long long raw) +int set_rtc_raw(unsigned long long raw) { RTC_TimeTypeDef rtc_time = {0}; RTC_DateTypeDef rtc_date = {0}; @@ -308,14 +315,13 @@ void set_rtc_raw(unsigned long long raw) rtc_date.Year = (uint8_t)((raw >> 56U) & 0xFFU); if (HAL_RTC_SetTime(&rtc_handle, &rtc_time, RTC_FORMAT_BCD) != HAL_OK) { - while (1) { - } + return -1; } if (HAL_RTC_SetDate(&rtc_handle, &rtc_date, RTC_FORMAT_BCD) != HAL_OK) { - while (1) { - } + return -2; } HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0, RTC_BKP_MAGIC); + return 0; } \ No newline at end of file diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index 9ac07796..5ef5c971 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -4,7 +4,7 @@ // lib.c unsigned long long systick_freq(void); -void init_hal(void); +int init_hal(void); __attribute__((noreturn)) void system_reset(void); // uart.c @@ -253,8 +253,8 @@ unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); void do_tick(void); void tim2_hndlr(void); -unsigned long long get_rtc_raw(void); -void set_rtc_raw(unsigned long long time); +unsigned long long rtc_raw(void); +int set_rtc_raw(unsigned long long time); -unsigned long get_rtc_backup_register(unsigned char index); +unsigned long rtc_backup_register(unsigned char index); void set_rtc_backup_register(unsigned char index, unsigned long value); diff --git a/machine/cortex-m/st/stm32l4/interface/lib.c b/machine/cortex-m/st/stm32l4/interface/lib.c index 058c0797..7f3ffeda 100644 --- a/machine/cortex-m/st/stm32l4/interface/lib.c +++ b/machine/cortex-m/st/stm32l4/interface/lib.c @@ -14,16 +14,18 @@ static void enable_faults(void) { __DSB(); } -static void init_systick(void) { - HAL_SYSTICK_Config(SystemCoreClock / 1000); // Configure SysTick to interrupt every 1 ms +static int init_systick(void) { + if (HAL_SYSTICK_Config(SystemCoreClock / 1000)) // Configure SysTick to interrupt every 1 ms + return -1; HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + return 0; } unsigned long long systick_freq(void) { return 1000; } -void init_hal(void) { +int init_hal(void) { #if OSIRIS_TUNING_ENABLEFPU init_fpu(); #endif @@ -31,8 +33,17 @@ void init_hal(void) { enable_faults(); - init_clock_cfg(); - init_systick(); + int ret = init_clock_cfg(); + if (ret != 0) { + return ret; + } + + ret = init_systick(); + if (ret != 0) { + return ret; + } + + return 0; } void HAL_MspInit(void) { diff --git a/machine/cortex-m/st/stm32l4/interface/lib.h b/machine/cortex-m/st/stm32l4/interface/lib.h index 3a4c6f0d..9ddd3d0f 100644 --- a/machine/cortex-m/st/stm32l4/interface/lib.h +++ b/machine/cortex-m/st/stm32l4/interface/lib.h @@ -2,7 +2,7 @@ #include -void init_clock_cfg(void); +int init_clock_cfg(void); unsigned long long monotonic_now(void); unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); diff --git a/src/lib.rs b/src/lib.rs index f8e758db..a6d3780e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub unsafe extern "C" fn kernel_init() -> ! { idle::init(); kprintln!("Idle thread initialized.\n"); - + time::init(); kprintln!("Time thread initialized.\n"); diff --git a/src/time.rs b/src/time.rs index a1a30f08..01396cf9 100644 --- a/src/time.rs +++ b/src/time.rs @@ -5,19 +5,18 @@ use crate::{sched, sync}; static TICKS: sync::atomic::AtomicU64 = sync::atomic::AtomicU64::new(0); extern "C" fn update_time() { - let interval: u64 = mono_freq() / 10; // ~100 seconds in ticks + let interval: u64 = 100_000; // ~100 seconds in ticks kprintln!( "Time thread started with tick interval {} at {}", interval, - get_actual_time() + walltime() ); loop { let tick = tick(); - sched::with(|sched| { - kprintln!("time is now {}", get_actual_time()); let _ = sched.sleep_until(tick + interval, tick); }); + kprintln!("time is now {}", walltime()); } } @@ -39,26 +38,39 @@ pub fn init() { }) } -pub fn get_rtc_backup_register(index: u8) -> u32 { +pub fn rtc_backup_register(index: u8) -> u32 { assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index == 0, "RTC uses this register for restart continuity"); - hal::Machine::get_rtc_backup_register(index) + assert!(index != 0, "RTC uses this register for restart continuity"); + hal::Machine::rtc_backup_register(index) } pub fn set_rtc_backup_register(index: u8, value: u32) { assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index == 0, "RTC uses this register for restart continuity"); + assert!(index != 0, "RTC uses this register for restart continuity"); hal::Machine::set_rtc_backup_register(index, value) } -pub fn get_actual_time() -> u64 { - let raw = sync::atomic::irq_free(|| hal::Machine::get_rtc_raw()); +pub fn walltime() -> u64 { + let raw = hal::Machine::rtc_raw(); + if raw == -1i64 as u64 { + kprintln!("failed to read RTC time"); + return 0; + } + if raw == -2i64 as u64 { + kprintln!("failed to read RTC date"); + return 0; + } rtc_raw_to_unix(raw) } -pub fn set_actual_time(time: u64) { +pub fn set_walltime(time: u64) { let raw = unix_to_rtc_raw(time); - sync::atomic::irq_free(|| hal::Machine::set_rtc_raw(raw)) + match hal::Machine::set_rtc_raw(raw) { + 0 => (), + -1 => kprintln!("failed to set RTC time"), + -2 => kprintln!("failed to set RTC date"), + _ => kprintln!("unknown error setting RTC time"), + } } const fn bcd_to_bin(value: u8) -> u8 { @@ -98,7 +110,6 @@ fn rtc_raw_to_unix(raw: u64) -> u64 { let hours = bcd_to_bin((raw & 0xff) as u8) as u64; let minutes = bcd_to_bin(((raw >> 8) & 0xff) as u8) as u64; let seconds = bcd_to_bin(((raw >> 16) & 0xff) as u8) as u64; - let weekday = ((raw >> 32) & 0xff) as u8; let year = 2000 + u32::from(bcd_to_bin(((raw >> 56) & 0xff) as u8)); let month = u32::from(bcd_to_bin(((raw >> 40) & 0xff) as u8)); let day = u32::from(bcd_to_bin(((raw >> 48) & 0xff) as u8)); From 521cebd376a7f7f88183e349ebf0243c859220eb Mon Sep 17 00:00:00 2001 From: Gabriel Kuznik Date: Sun, 17 May 2026 23:33:33 +0200 Subject: [PATCH 4/7] move rtc into driver use backup register 31 instead of 1 --- machine/api/src/lib.rs | 5 +- machine/cortex-m/src/native.rs | 4 + machine/cortex-m/src/stub.rs | 4 + machine/cortex-m/st/stm32l4/interface/clock.c | 7 +- .../cortex-m/st/stm32l4/interface/export.h | 1 + src/drivers.rs | 2 + src/drivers/clock.rs | 143 ++++++++++++++++++ src/time.rs | 124 +-------------- src/uapi/time.rs | 12 +- 9 files changed, 177 insertions(+), 125 deletions(-) create mode 100644 src/drivers/clock.rs diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index 6144a68a..0c704eba 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -34,9 +34,10 @@ pub trait Machinelike { fn monotonic_freq() -> u64; fn rtc_raw() -> u64; fn set_rtc_raw(time: u64) -> i32; - // index 0..32, 0 is used by the RTC + fn init_rtc() -> i32; + // index 0..32, 31 is used by the RTC fn rtc_backup_register(index: u8) -> u32; - // index 0..32, 0 is used by the RTC + // index 0..32, 31 is used by the RTC fn set_rtc_backup_register(index: u8, value: u32); // Returns the frequency of the machine's systick timer in Hz. fn systick_freq() -> u64; diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index e1542230..b926fadb 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -121,6 +121,10 @@ impl hal_api::Machinelike for ArmMachine { unsafe { bindings::set_rtc_raw(time) } } + fn init_rtc() -> i32 { + unsafe { bindings::init_rtc() } + } + fn rtc_backup_register(index: u8) -> u32 { unsafe { bindings::rtc_backup_register(index) } } diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index c714e78a..4099bef8 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -55,6 +55,10 @@ impl hal_api::Machinelike for StubMachine { 0 } + fn init_rtc() -> i32 { + 0 + } + fn rtc_backup_register(index: u8) -> u32 { 0 } diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index bbee93dd..152f82b9 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -90,7 +90,7 @@ int init_rtc(void) return ERROR_RTC_INIT; } - if (HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0) != RTC_BKP_MAGIC) { + if (HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR31) != RTC_BKP_MAGIC) { // Sat 01.01.2000 unsigned long long time = ((uint64_t)0) | ((uint64_t)0 << 8U) | @@ -200,7 +200,7 @@ int init_clock_cfg(void) SystemCoreClockUpdate(); init_monotonic_timer(); - return init_rtc(); + return 0; } unsigned long long monotonic_now(void) @@ -273,7 +273,6 @@ long get_rtc_backup_register(unsigned index) void set_rtc_backup_register(unsigned index, long value) { - assert(index != 0 && "Register 0 is reserved for RTC init"); HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0 + index, value); } @@ -322,6 +321,6 @@ int set_rtc_raw(unsigned long long raw) return -2; } - HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0, RTC_BKP_MAGIC); + HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR31, RTC_BKP_MAGIC); return 0; } \ No newline at end of file diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index 5ef5c971..246d2a11 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -253,6 +253,7 @@ unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); void do_tick(void); void tim2_hndlr(void); +int init_rtc(void); unsigned long long rtc_raw(void); int set_rtc_raw(unsigned long long time); diff --git a/src/drivers.rs b/src/drivers.rs index 6d15f2cc..4bf07bd5 100644 --- a/src/drivers.rs +++ b/src/drivers.rs @@ -1,10 +1,12 @@ pub mod can; +pub mod clock; pub mod i2c; pub mod key; pub mod led; pub mod spi; pub fn init() { + clock::init(); i2c::init(); spi::init(); can::init(); diff --git a/src/drivers/clock.rs b/src/drivers/clock.rs new file mode 100644 index 00000000..3abd3482 --- /dev/null +++ b/src/drivers/clock.rs @@ -0,0 +1,143 @@ +use hal_api::PosixError; + +use crate::hal; +use crate::hal::Machinelike; + +/// The monotonic clock is brought up by [hal::Machine::init()] +pub fn init() { + match hal::Machine::init_rtc() { + 0 => (), + -4 => { + kprintln!("failed to initialize RTC: init clock source"); + } + -5 => { + kprintln!("failed to initialize RTC: init RTC"); + } + ret => { + kprintln!("failed to initialize RTC: {ret}"); + } + } +} + +pub fn rtc_backup_register(index: u8) -> u32 { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index != 31, "RTC uses this register for restart continuity"); + hal::Machine::rtc_backup_register(index) +} + +pub fn set_rtc_backup_register(index: u8, value: u32) { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index != 31, "RTC uses this register for restart continuity"); + hal::Machine::set_rtc_backup_register(index, value) +} + +pub fn walltime() -> Result { + let raw = hal::Machine::rtc_raw(); + if raw == -1i64 as u64 { + kprintln!("failed to read RTC time"); + return Err(PosixError::EIO); + } + if raw == -2i64 as u64 { + kprintln!("failed to read RTC date"); + return Err(PosixError::EIO); + } + Ok(rtc_raw_to_unix(raw)) +} + +pub fn set_walltime(time: u64) -> Result<(), PosixError> { + let raw = unix_to_rtc_raw(time); + match hal::Machine::set_rtc_raw(raw) { + 0 => Ok(()), + -1 => { + kprintln!("failed to set RTC time"); + return Err(PosixError::EINVAL); + } + -2 => { + kprintln!("failed to set RTC date"); + return Err(PosixError::EINVAL); + } + _ => { + kprintln!("unknown error setting RTC time"); + return Err(PosixError::Unknown); + } + } +} + +const fn bcd_to_bin(value: u8) -> u8 { + ((value >> 4) * 10) + (value & 0x0f) +} + +const fn bin_to_bcd(value: u8) -> u8 { + ((value / 10) << 4) | (value % 10) +} + +const fn is_leap_year(year: u32) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} + +const fn days_in_month(year: u32, month: u32) -> u32 { + match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 if is_leap_year(year) => 29, + 2 => 28, + _ => 0, + } +} + +fn days_since_unix_epoch(year: u32, month: u32, day: u32) -> u64 { + let mut days = 0u64; + for y in 1970..year { + days += if is_leap_year(y) { 366 } else { 365 }; + } + for m in 1..month { + days += days_in_month(year, m) as u64; + } + days + u64::from(day.saturating_sub(1)) +} + +fn rtc_raw_to_unix(raw: u64) -> u64 { + let hours = bcd_to_bin((raw & 0xff) as u8) as u64; + let minutes = bcd_to_bin(((raw >> 8) & 0xff) as u8) as u64; + let seconds = bcd_to_bin(((raw >> 16) & 0xff) as u8) as u64; + let year = 2000 + u32::from(bcd_to_bin(((raw >> 56) & 0xff) as u8)); + let month = u32::from(bcd_to_bin(((raw >> 40) & 0xff) as u8)); + let day = u32::from(bcd_to_bin(((raw >> 48) & 0xff) as u8)); + + days_since_unix_epoch(year, month, day) * 86_400 + hours * 3_600 + minutes * 60 + seconds +} + +fn unix_to_rtc_raw(unix: u64) -> u64 { + let epoch_2000 = 946_684_800u64; + let mut seconds = unix.saturating_sub(epoch_2000); + let mut days = seconds / 86_400; + seconds %= 86_400; + + let mut year = 2000u32; + while days >= if is_leap_year(year) { 366 } else { 365 } { + days -= if is_leap_year(year) { 366 } else { 365 }; + year += 1; + } + + let mut month = 1u32; + while days >= u64::from(days_in_month(year, month)) { + days -= u64::from(days_in_month(year, month)); + month += 1; + } + + let day = (days + 1) as u32; + let weekday = (((days_since_unix_epoch(year, month, day) + 4) % 7) + 1) as u8; + + let hours = (seconds / 3_600) as u8; + seconds %= 3_600; + let minutes = (seconds / 60) as u8; + let seconds = (seconds % 60) as u8; + + (u64::from(bin_to_bcd(hours))) + | (u64::from(bin_to_bcd(minutes)) << 8) + | (u64::from(bin_to_bcd(seconds)) << 16) + | (u64::from(weekday) << 32) + | (u64::from(bin_to_bcd(month as u8)) << 40) + | (u64::from(bin_to_bcd(day as u8)) << 48) + | (u64::from(bin_to_bcd((year - 2000) as u8)) << 56) +} diff --git a/src/time.rs b/src/time.rs index 01396cf9..d3d58fae 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,28 +1,30 @@ +use crate::drivers::clock; use crate::hal::{self, Machinelike}; use crate::{sched, sync}; static TICKS: sync::atomic::AtomicU64 = sync::atomic::AtomicU64::new(0); -extern "C" fn update_time() { +extern "C" fn update_time(_ctx: *mut core::ffi::c_void) { let interval: u64 = 100_000; // ~100 seconds in ticks kprintln!( - "Time thread started with tick interval {} at {}", + "Time thread started with tick interval {} at {:?}", interval, - walltime() + clock::walltime() ); loop { let tick = tick(); sched::with(|sched| { let _ = sched.sleep_until(tick + interval, tick); }); - kprintln!("time is now {}", walltime()); + kprintln!("time is now {:?}", clock::walltime()); } } pub fn init() { let attrs = sched::thread::Attributes { entry: update_time, + ctx: core::ptr::null_mut(), fin: None, attrs: None, }; @@ -38,120 +40,6 @@ pub fn init() { }) } -pub fn rtc_backup_register(index: u8) -> u32 { - assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index != 0, "RTC uses this register for restart continuity"); - hal::Machine::rtc_backup_register(index) -} - -pub fn set_rtc_backup_register(index: u8, value: u32) { - assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index != 0, "RTC uses this register for restart continuity"); - hal::Machine::set_rtc_backup_register(index, value) -} - -pub fn walltime() -> u64 { - let raw = hal::Machine::rtc_raw(); - if raw == -1i64 as u64 { - kprintln!("failed to read RTC time"); - return 0; - } - if raw == -2i64 as u64 { - kprintln!("failed to read RTC date"); - return 0; - } - rtc_raw_to_unix(raw) -} - -pub fn set_walltime(time: u64) { - let raw = unix_to_rtc_raw(time); - match hal::Machine::set_rtc_raw(raw) { - 0 => (), - -1 => kprintln!("failed to set RTC time"), - -2 => kprintln!("failed to set RTC date"), - _ => kprintln!("unknown error setting RTC time"), - } -} - -const fn bcd_to_bin(value: u8) -> u8 { - ((value >> 4) * 10) + (value & 0x0f) -} - -const fn bin_to_bcd(value: u8) -> u8 { - ((value / 10) << 4) | (value % 10) -} - -const fn is_leap_year(year: u32) -> bool { - year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) -} - -const fn days_in_month(year: u32, month: u32) -> u32 { - match month { - 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, - 4 | 6 | 9 | 11 => 30, - 2 if is_leap_year(year) => 29, - 2 => 28, - _ => 0, - } -} - -fn days_since_unix_epoch(year: u32, month: u32, day: u32) -> u64 { - let mut days = 0u64; - for y in 1970..year { - days += if is_leap_year(y) { 366 } else { 365 }; - } - for m in 1..month { - days += days_in_month(year, m) as u64; - } - days + u64::from(day.saturating_sub(1)) -} - -fn rtc_raw_to_unix(raw: u64) -> u64 { - let hours = bcd_to_bin((raw & 0xff) as u8) as u64; - let minutes = bcd_to_bin(((raw >> 8) & 0xff) as u8) as u64; - let seconds = bcd_to_bin(((raw >> 16) & 0xff) as u8) as u64; - let year = 2000 + u32::from(bcd_to_bin(((raw >> 56) & 0xff) as u8)); - let month = u32::from(bcd_to_bin(((raw >> 40) & 0xff) as u8)); - let day = u32::from(bcd_to_bin(((raw >> 48) & 0xff) as u8)); - - days_since_unix_epoch(year, month, day) * 86_400 + hours * 3_600 + minutes * 60 + seconds -} - -fn unix_to_rtc_raw(unix: u64) -> u64 { - let epoch_2000 = 946_684_800u64; - let mut seconds = unix.saturating_sub(epoch_2000); - let mut days = seconds / 86_400; - seconds %= 86_400; - - let mut year = 2000u32; - while days >= if is_leap_year(year) { 366 } else { 365 } { - days -= if is_leap_year(year) { 366 } else { 365 }; - year += 1; - } - - let mut month = 1u32; - while days >= u64::from(days_in_month(year, month)) { - days -= u64::from(days_in_month(year, month)); - month += 1; - } - - let day = (days + 1) as u32; - let weekday = (((days_since_unix_epoch(year, month, day) + 4) % 7) + 1) as u8; - - let hours = (seconds / 3_600) as u8; - seconds %= 3_600; - let minutes = (seconds / 60) as u8; - let seconds = (seconds % 60) as u8; - - (u64::from(bin_to_bcd(hours))) - | (u64::from(bin_to_bcd(minutes)) << 8) - | (u64::from(bin_to_bcd(seconds)) << 16) - | (u64::from(weekday) << 32) - | (u64::from(bin_to_bcd(month as u8)) << 40) - | (u64::from(bin_to_bcd(day as u8)) << 48) - | (u64::from(bin_to_bcd((year - 2000) as u8)) << 56) -} - pub fn tick() -> u64 { TICKS.load(sync::atomic::Ordering::Acquire) } diff --git a/src/uapi/time.rs b/src/uapi/time.rs index c05f72fa..c1b39dd2 100644 --- a/src/uapi/time.rs +++ b/src/uapi/time.rs @@ -1,4 +1,6 @@ -use crate::time; +use hal_api::PosixError; + +use crate::{drivers::clock, time}; pub fn mono_now() -> u64 { time::mono_now() @@ -11,3 +13,11 @@ pub fn mono_freq() -> u64 { pub fn tick() -> u64 { time::tick() } + +pub fn walltime() -> Result { + clock::walltime() +} + +pub fn set_walltime(time: u64) -> Result<(), PosixError> { + clock::set_walltime(time) +} From 3f6ca02ebf3cc0eca1a2b08f55f266fdb12ab67b Mon Sep 17 00:00:00 2001 From: Gabriel Kuznik Date: Thu, 21 May 2026 15:42:55 +0200 Subject: [PATCH 5/7] hal CSS part for LSE --- machine/cortex-m/st/stm32l4/interface/clock.c | 183 +++++++++++------- 1 file changed, 116 insertions(+), 67 deletions(-) diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index 152f82b9..96d5309f 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -3,6 +3,7 @@ #include #include #include "stm32l4xx_hal_rcc.h" +#include "stm32l4xx_hal_rcc_ex.h" #include #include @@ -10,71 +11,109 @@ static volatile uint64_t monotonic_hi = 0; static volatile uint32_t tick = 0; #define RTC_BKP_MAGIC 0x4F534952U -#define LSE_READY_TIMEOUT_LOOPS 2000000U -#define LSI_READY_TIMEOUT_LOOPS 200000U -#define ERROR_CONTROL_VOLTAGE_SCALING -1 -#define ERROR_RCC_OSC_CONFIG -2 -#define ERROR_RCC_CLOCK_CONFIG -3 -#define ERROR_RTC_INIT_CLOCK_SOURCE -4 -#define ERROR_RTC_INIT -5 +// use msb for the error type +// lower byte(s) contain hal status +enum ErrorTypes : uint64_t { + ERROR_CONTROL_VOLTAGE_SCALING = 0x01U << 56U, + ERROR_RCC_OSC_CONFIG = 0x02U << 56U, + ERROR_RCC_CLOCK_CONFIG = 0x03U << 56U, + ERROR_RTC_INIT_CLOCK_SOURCE = 0x04U << 56U, + ERROR_RTC_INIT = 0x05U << 56U, + ERROR_RTC_GET_TIME = 0x06U << 56U, + ERROR_RTC_GET_DATE = 0x07U << 56U, + ERROR_RTC_SET_TIME = 0x08U << 56U, + ERROR_RTC_SET_DATE = 0x09U << 56U +}; static RTC_HandleTypeDef rtc_handle; -static int wait_rcc_ready_flag(uint32_t flag, uint32_t timeout_loops) +/** +* Try to use LSE, fall back to LSI and enable CSS if both are available. +* @retval HAL_StatusTypeDef codes: +* bit 0-1: selecting LSE clock source +* bit 2-3: selecting LSI clock source +* bit 4-5: HAL_TIMEOUT from waiting for LSI ready + */ +static int init_rtc_clock_source(void) { - while (timeout_loops > 0U) { - if (__HAL_RCC_GET_FLAG(flag) != RESET) { - return -1; - } + HAL_PWR_EnableBkUpAccess(); + int error = 0; - timeout_loops--; - } + __HAL_RCC_LSI_ENABLE(); - return 0; -} + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH); + __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); -static HAL_StatusTypeDef select_rtc_clock_source(uint32_t source) -{ RCC_PeriphCLKInitTypeDef periph = {0}; - periph.PeriphClockSelection = RCC_PERIPHCLK_RTC; - periph.RTCClockSelection = source; - return HAL_RCCEx_PeriphCLKConfig(&periph); + periph.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + HAL_StatusTypeDef status = HAL_RCCEx_PeriphCLKConfig(&periph); + + if (status != HAL_OK) { + error = status; + // fallback to LSI + periph.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + status = HAL_RCCEx_PeriphCLKConfig(&periph); + // if LSI selection also fails, return both errors + if (status != HAL_OK) { + error |= status << 2; + return error; + } + } + + // ensure LSI is ready + uint32_t tickstart = HAL_GetTick(); + while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) { + if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) { + error |= HAL_TIMEOUT << 4; + break; + } + } + + __HAL_RCC_RTC_ENABLE(); + + // clock security system requires both LSE and LSI to be enabled. + if (!error) { + HAL_RCCEx_EnableLSECSS(); + __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS); + } + HAL_PWR_DisableBkUpAccess(); + + return error; } -static int init_rtc_clock_source(void) +void handle_css_lse_interrupt() { - __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH); - __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); + HAL_PWR_EnableBkUpAccess(); + __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS); - if (!wait_rcc_ready_flag(RCC_FLAG_LSERDY, LSE_READY_TIMEOUT_LOOPS) && - select_rtc_clock_source(RCC_RTCCLKSOURCE_LSE) == HAL_OK) { - __HAL_RCC_RTC_ENABLE(); - return 0; - } - + // The software MUST then disable the LSECSSON bit + HAL_RCCEx_DisableLSECSS(); + // stop the defective 32 kHz oscillator (disabling LSEON) __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); - __HAL_RCC_LSI_ENABLE(); - if (!wait_rcc_ready_flag(RCC_FLAG_LSIRDY, LSI_READY_TIMEOUT_LOOPS) && - select_rtc_clock_source(RCC_RTCCLKSOURCE_LSI) == HAL_OK) { - __HAL_RCC_RTC_ENABLE(); - return 0; + // and change the RTC clock source (no clock or LSI or HSE, with RTCSEL) + RCC_PeriphCLKInitTypeDef periph = {0}; + periph.PeriphClockSelection = RCC_PERIPHCLK_RTC; + periph.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + HAL_StatusTypeDef status = HAL_RCCEx_PeriphCLKConfig(&periph); + if (status != HAL_OK) { + // internal clock failed, try again later? + __HAL_RCC_RTC_DISABLE(); } - return -1; + HAL_PWR_DisableBkUpAccess(); } -int set_rtc_raw(unsigned long long raw); -int init_rtc(void) +uint64_t set_rtc_raw(uint64_t raw); +uint64_t init_rtc(void) { __HAL_RCC_PWR_CLK_ENABLE(); - HAL_PWR_EnableBkUpAccess(); - // TODO: setup Clock Security System - if (init_rtc_clock_source()) { - return ERROR_RTC_INIT_CLOCK_SOURCE; + int ret = init_rtc_clock_source(); + if (ret) { + return ERROR_RTC_INIT_CLOCK_SOURCE | ret; } rtc_handle.Instance = RTC; @@ -86,8 +125,9 @@ int init_rtc(void) rtc_handle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; rtc_handle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; - if (HAL_RTC_Init(&rtc_handle) != HAL_OK) { - return ERROR_RTC_INIT; + ret = HAL_RTC_Init(&rtc_handle); + if (ret != HAL_OK) { + return ERROR_RTC_INIT | ret; } if (HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR31) != RTC_BKP_MAGIC) { @@ -154,7 +194,7 @@ void tim2_hndlr(void) } } -int init_clock_cfg(void) +uint64_t init_clock_cfg(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; @@ -162,8 +202,9 @@ int init_clock_cfg(void) /* 80 MHz on STM32L4+ => Range 1 normal mode, not boost */ __HAL_RCC_PWR_CLK_ENABLE(); - if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) { - return ERROR_CONTROL_VOLTAGE_SCALING; + int ret = HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); + if (ret != HAL_OK) { + return ERROR_CONTROL_VOLTAGE_SCALING | ret; } /* HSI16 -> PLL -> 80 MHz SYSCLK */ @@ -179,8 +220,9 @@ int init_clock_cfg(void) RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // arbitrary unless you use PLLP RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // arbitrary unless you use PLLQ - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - return ERROR_RCC_OSC_CONFIG; + ret = HAL_RCC_OscConfig(&RCC_OscInitStruct); + if (ret != HAL_OK) { + return ERROR_RCC_OSC_CONFIG | ret; } RCC_ClkInitStruct.ClockType = @@ -194,8 +236,9 @@ int init_clock_cfg(void) RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { - return ERROR_RCC_CLOCK_CONFIG; + ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4); + if (ret != HAL_OK) { + return ERROR_RCC_CLOCK_CONFIG | ret; } SystemCoreClockUpdate(); @@ -266,39 +309,43 @@ void do_tick(void) } -long get_rtc_backup_register(unsigned index) +uint32_t get_rtc_backup_register(uint32_t index) { return HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0 + index); } -void set_rtc_backup_register(unsigned index, long value) +void set_rtc_backup_register(uint32_t index, uint32_t value) { + HAL_PWR_EnableBkUpAccess(); HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0 + index, value); + HAL_PWR_DisableBkUpAccess(); } -unsigned long long rtc_raw(void) +uint64_t rtc_raw(void) { RTC_TimeTypeDef time = {0}; RTC_DateTypeDef date = {0}; - if (HAL_RTC_GetTime(&rtc_handle, &time, RTC_FORMAT_BCD) != HAL_OK) { - return -1U; + int ret = HAL_RTC_GetTime(&rtc_handle, &time, RTC_FORMAT_BCD); + if (ret != HAL_OK) { + return ERROR_RTC_GET_TIME | ret; } - if (HAL_RTC_GetDate(&rtc_handle, &date, RTC_FORMAT_BCD) != HAL_OK) { - return -2U; + ret = HAL_RTC_GetDate(&rtc_handle, &date, RTC_FORMAT_BCD); + if (ret != HAL_OK) { + return ERROR_RTC_GET_DATE | ret; } return ((uint64_t)time.Hours) | ((uint64_t)time.Minutes << 8U) | ((uint64_t)time.Seconds << 16U) | - ((uint64_t)date.WeekDay << 32U) | - ((uint64_t)date.Month << 40U) | - ((uint64_t)date.Date << 48U) | - ((uint64_t)date.Year << 56U); + ((uint64_t)date.WeekDay << 24U) | + ((uint64_t)date.Month << 32U) | + ((uint64_t)date.Date << 40U) | + ((uint64_t)date.Year << 48U); } -int set_rtc_raw(unsigned long long raw) +uint64_t set_rtc_raw(uint64_t raw) { RTC_TimeTypeDef rtc_time = {0}; RTC_DateTypeDef rtc_date = {0}; @@ -313,12 +360,14 @@ int set_rtc_raw(unsigned long long raw) rtc_date.Date = (uint8_t)((raw >> 48U) & 0xFFU); rtc_date.Year = (uint8_t)((raw >> 56U) & 0xFFU); - if (HAL_RTC_SetTime(&rtc_handle, &rtc_time, RTC_FORMAT_BCD) != HAL_OK) { - return -1; + int ret = HAL_RTC_SetTime(&rtc_handle, &rtc_time, RTC_FORMAT_BCD); + if (ret != HAL_OK) { + return ERROR_RTC_SET_TIME | ret; } - if (HAL_RTC_SetDate(&rtc_handle, &rtc_date, RTC_FORMAT_BCD) != HAL_OK) { - return -2; + ret = HAL_RTC_SetDate(&rtc_handle, &rtc_date, RTC_FORMAT_BCD); + if (ret != HAL_OK) { + return ERROR_RTC_SET_DATE | ret; } HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR31, RTC_BKP_MAGIC); From 1f89aeb0e3eaf9ec72cfae49e65a5b6d22ce2343 Mon Sep 17 00:00:00 2001 From: Gabriel Kuznik Date: Fri, 29 May 2026 00:37:08 +0200 Subject: [PATCH 6/7] move error handling into HAL move BCD logic into HAL --- machine/api/src/lib.rs | 12 +- machine/cortex-m/src/native.rs | 27 ++++- .../cortex-m/src/native/rtc.rs | 113 ++++++++++-------- machine/cortex-m/src/stub.rs | 15 ++- machine/cortex-m/st/stm32l4/interface/clock.c | 17 ++- .../cortex-m/st/stm32l4/interface/export.h | 12 +- machine/cortex-m/st/stm32l4/interface/lib.c | 4 +- machine/cortex-m/st/stm32l4/interface/lib.h | 2 +- src/drivers.rs | 4 +- src/drivers/rtc.rs | 27 +++++ src/time.rs | 8 +- src/uapi/time.rs | 6 +- 12 files changed, 153 insertions(+), 94 deletions(-) rename src/drivers/clock.rs => machine/cortex-m/src/native/rtc.rs (57%) create mode 100644 src/drivers/rtc.rs diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index 0c704eba..4a9ccd6e 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -32,15 +32,17 @@ pub trait Machinelike { fn monotonic_now() -> u64; fn monotonic_freq() -> u64; - fn rtc_raw() -> u64; - fn set_rtc_raw(time: u64) -> i32; - fn init_rtc() -> i32; + // Returns the frequency of the machine's systick timer in Hz. + fn systick_freq() -> u64; + + fn init_rtc() -> Result<()>; + fn rtc() -> Result; + fn set_rtc(time: u64) -> Result<()>; + // index 0..32, 31 is used by the RTC fn rtc_backup_register(index: u8) -> u32; // index 0..32, 31 is used by the RTC fn set_rtc_backup_register(index: u8, value: u32); - // Returns the frequency of the machine's systick timer in Hz. - fn systick_freq() -> u64; type ExcepBacktrace: Display; type ExcepStackFrame: Display; diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index b926fadb..e0e668b6 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -9,6 +9,7 @@ pub mod excep; pub mod gpio; pub mod i2c; pub mod panic; +pub mod rtc; pub mod sched; pub mod spi; pub mod system; @@ -42,6 +43,10 @@ fn monotonic_overflow_irq(_ctx: *mut u8, _vector: usize, _userdata: Option) { + unsafe { bindings::css_lse_hndlr() } +} + impl hal_api::Machinelike for ArmMachine { fn init() { unsafe { @@ -73,6 +78,12 @@ impl hal_api::Machinelike for ArmMachine { if let Err(e) = register(vector, monotonic_overflow_irq, None) { panic!("failed to register monotonic timer IRQ at vector {vector}: {e}"); } + + /* TODO find vector + let vector = irqn as usize + 16; + if let Err(e) = register(vector, css_lse_irq, None) { + panic!("failed to register CSS LSE IRQ at vector {vector}: {e}"); + }*/ } fn print(s: &str) -> Result<()> { @@ -113,23 +124,27 @@ impl hal_api::Machinelike for ArmMachine { unsafe { bindings::monotonic_freq() } } - fn rtc_raw() -> u64 { - unsafe { bindings::rtc_raw() } + fn init_rtc() -> Result<()> { + rtc::init_rtc() } - fn set_rtc_raw(time: u64) -> i32 { - unsafe { bindings::set_rtc_raw(time) } + fn rtc() -> Result { + rtc::rtc() } - fn init_rtc() -> i32 { - unsafe { bindings::init_rtc() } + fn set_rtc(time: u64) -> Result<()> { + rtc::set_rtc(time) } fn rtc_backup_register(index: u8) -> u32 { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index != 31, "RTC uses this register for restart continuity"); unsafe { bindings::rtc_backup_register(index) } } fn set_rtc_backup_register(index: u8, value: u32) { + assert!(index < 32, "RTC backup register index out of bounds"); + assert!(index != 31, "RTC uses this register for restart continuity"); unsafe { bindings::set_rtc_backup_register(index, value) } } diff --git a/src/drivers/clock.rs b/machine/cortex-m/src/native/rtc.rs similarity index 57% rename from src/drivers/clock.rs rename to machine/cortex-m/src/native/rtc.rs index 3abd3482..c5f867c9 100644 --- a/src/drivers/clock.rs +++ b/machine/cortex-m/src/native/rtc.rs @@ -1,66 +1,81 @@ use hal_api::PosixError; -use crate::hal; -use crate::hal::Machinelike; - -/// The monotonic clock is brought up by [hal::Machine::init()] -pub fn init() { - match hal::Machine::init_rtc() { - 0 => (), - -4 => { - kprintln!("failed to initialize RTC: init clock source"); +use super::{Result, bindings}; + +#[allow(unused_macros)] +macro_rules! println { + ($($arg:tt)*) => ({ + use core::fmt::Write; + use super::print::Printer; + let mut printer = Printer; + printer.write_fmt(format_args!($($arg)*)).unwrap(); + printer.write_str("\n").unwrap(); + }); +} + +pub(crate) fn init_rtc() -> Result<()> { + let raw = unsafe { bindings::init_rtc() }; + match raw >> 56 { + 0 => Ok(()), + 0x04 => { + println!( + "failed to initialize RTC clock source: LSE failed with {}, LSI with {}", + raw & 0xff, + (raw >> 8) & 0xff + ); + Err(PosixError::EIO) + } + 0x05 => { + println!("failed to init RTC: {}", raw & 0xff); + Err(PosixError::EIO) + } + 0x08 => { + println!("failed to set RTC time: {}", raw & 0xff); + Err(PosixError::EIO) } - -5 => { - kprintln!("failed to initialize RTC: init RTC"); + 0x09 => { + println!("failed to set RTC date: {}", raw & 0xff); + Err(PosixError::EIO) } - ret => { - kprintln!("failed to initialize RTC: {ret}"); + _ => { + println!("unknown error code: {}", raw); + Err(PosixError::Unknown) } } } -pub fn rtc_backup_register(index: u8) -> u32 { - assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index != 31, "RTC uses this register for restart continuity"); - hal::Machine::rtc_backup_register(index) -} - -pub fn set_rtc_backup_register(index: u8, value: u32) { - assert!(index < 32, "RTC backup register index out of bounds"); - assert!(index != 31, "RTC uses this register for restart continuity"); - hal::Machine::set_rtc_backup_register(index, value) -} - -pub fn walltime() -> Result { - let raw = hal::Machine::rtc_raw(); - if raw == -1i64 as u64 { - kprintln!("failed to read RTC time"); - return Err(PosixError::EIO); - } - if raw == -2i64 as u64 { - kprintln!("failed to read RTC date"); - return Err(PosixError::EIO); +pub(crate) fn rtc() -> Result { + let raw = unsafe { bindings::rtc_raw() }; + match raw >> 56 { + 0 => Ok(rtc_raw_to_unix(raw)), + 0x06 => { + println!("failed to get RTC time: {}", raw & 0xff); + Err(PosixError::EIO) + } + 0x07 => { + println!("failed to get RTC date: {}", raw & 0xff); + Err(PosixError::EIO) + } + _ => { + println!("unknown error code: {}", raw); + Err(PosixError::Unknown) + } } - Ok(rtc_raw_to_unix(raw)) } -pub fn set_walltime(time: u64) -> Result<(), PosixError> { +pub(crate) fn set_rtc(time: u64) -> Result<()> { let raw = unix_to_rtc_raw(time); - match hal::Machine::set_rtc_raw(raw) { - 0 => Ok(()), - -1 => { - kprintln!("failed to set RTC time"); - return Err(PosixError::EINVAL); - } - -2 => { - kprintln!("failed to set RTC date"); - return Err(PosixError::EINVAL); - } - _ => { - kprintln!("unknown error setting RTC time"); - return Err(PosixError::Unknown); + let ret = unsafe { bindings::set_rtc_raw(raw) }; + if ret != 0 { + if ret >> 56 == 0x08 { + println!("failed to set RTC time: {}", ret & 0xff); + return Err(PosixError::EIO); + } else { + println!("failed to set RTC date: {}", ret & 0xff); + return Err(PosixError::EIO); } } + Ok(()) } const fn bcd_to_bin(value: u8) -> u8 { diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index 4099bef8..4e080359 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -47,24 +47,23 @@ impl hal_api::Machinelike for StubMachine { 0 } - fn rtc_raw() -> u64 { - 0 + fn init_rtc() -> Result<()> { + Ok(()) } - fn set_rtc_raw(_time: u64) -> i32 { - 0 + fn rtc() -> Result { + Ok(0) } - fn init_rtc() -> i32 { - 0 + fn set_rtc(time: u64) -> Result<()> { + Ok(()) } fn rtc_backup_register(index: u8) -> u32 { 0 } - fn set_rtc_backup_register(index: u8, value: u32) { - } + fn set_rtc_backup_register(index: u8, value: u32) {} fn systick_freq() -> u64 { 0 diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index 96d5309f..c83c4c85 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -4,7 +4,6 @@ #include #include "stm32l4xx_hal_rcc.h" #include "stm32l4xx_hal_rcc_ex.h" -#include #include static volatile uint64_t monotonic_hi = 0; @@ -32,8 +31,7 @@ static RTC_HandleTypeDef rtc_handle; * Try to use LSE, fall back to LSI and enable CSS if both are available. * @retval HAL_StatusTypeDef codes: * bit 0-1: selecting LSE clock source -* bit 2-3: selecting LSI clock source -* bit 4-5: HAL_TIMEOUT from waiting for LSI ready +* bit 8-9: selecting LSI clock source */ static int init_rtc_clock_source(void) { @@ -58,16 +56,17 @@ static int init_rtc_clock_source(void) status = HAL_RCCEx_PeriphCLKConfig(&periph); // if LSI selection also fails, return both errors if (status != HAL_OK) { - error |= status << 2; + error |= status << 8; return error; } } + _Bool lsi_ready = 1; // ensure LSI is ready uint32_t tickstart = HAL_GetTick(); while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) { if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) { - error |= HAL_TIMEOUT << 4; + lsi_ready = 0; break; } } @@ -75,7 +74,7 @@ static int init_rtc_clock_source(void) __HAL_RCC_RTC_ENABLE(); // clock security system requires both LSE and LSI to be enabled. - if (!error) { + if (!error && lsi_ready) { HAL_RCCEx_EnableLSECSS(); __HAL_RCC_ENABLE_IT(RCC_IT_LSECSS); } @@ -84,7 +83,7 @@ static int init_rtc_clock_source(void) return error; } -void handle_css_lse_interrupt() +void css_lse_hndlr() { HAL_PWR_EnableBkUpAccess(); __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS); @@ -309,12 +308,12 @@ void do_tick(void) } -uint32_t get_rtc_backup_register(uint32_t index) +uint32_t get_rtc_backup_register(uint8_t index) { return HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0 + index); } -void set_rtc_backup_register(uint32_t index, uint32_t value) +void set_rtc_backup_register(uint8_t index, uint32_t value) { HAL_PWR_EnableBkUpAccess(); HAL_RTCEx_BKUPWrite(&rtc_handle, RTC_BKP_DR0 + index, value); diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index 246d2a11..13c20938 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -253,9 +253,11 @@ unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); void do_tick(void); void tim2_hndlr(void); -int init_rtc(void); -unsigned long long rtc_raw(void); -int set_rtc_raw(unsigned long long time); -unsigned long rtc_backup_register(unsigned char index); -void set_rtc_backup_register(unsigned char index, unsigned long value); +uint64_t init_rtc(void); +uint64_t rtc_raw(void); +uint64_t set_rtc_raw(uint64_t time); +void css_lse_hndlr(void); + +uint32_t rtc_backup_register(uint8_t index); +void set_rtc_backup_register(uint8_t index, uint32_t value); diff --git a/machine/cortex-m/st/stm32l4/interface/lib.c b/machine/cortex-m/st/stm32l4/interface/lib.c index 7f3ffeda..283617cf 100644 --- a/machine/cortex-m/st/stm32l4/interface/lib.c +++ b/machine/cortex-m/st/stm32l4/interface/lib.c @@ -25,7 +25,7 @@ unsigned long long systick_freq(void) { return 1000; } -int init_hal(void) { +uint64_t init_hal(void) { #if OSIRIS_TUNING_ENABLEFPU init_fpu(); #endif @@ -33,7 +33,7 @@ int init_hal(void) { enable_faults(); - int ret = init_clock_cfg(); + uint64_t ret = init_clock_cfg(); if (ret != 0) { return ret; } diff --git a/machine/cortex-m/st/stm32l4/interface/lib.h b/machine/cortex-m/st/stm32l4/interface/lib.h index 9ddd3d0f..bc7e7e8e 100644 --- a/machine/cortex-m/st/stm32l4/interface/lib.h +++ b/machine/cortex-m/st/stm32l4/interface/lib.h @@ -2,7 +2,7 @@ #include -int init_clock_cfg(void); +uint64_t init_clock_cfg(void); unsigned long long monotonic_now(void); unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); diff --git a/src/drivers.rs b/src/drivers.rs index 4bf07bd5..157eac67 100644 --- a/src/drivers.rs +++ b/src/drivers.rs @@ -1,12 +1,12 @@ pub mod can; -pub mod clock; pub mod i2c; pub mod key; pub mod led; +pub mod rtc; pub mod spi; pub fn init() { - clock::init(); + rtc::init(); i2c::init(); spi::init(); can::init(); diff --git a/src/drivers/rtc.rs b/src/drivers/rtc.rs new file mode 100644 index 00000000..a998ae5b --- /dev/null +++ b/src/drivers/rtc.rs @@ -0,0 +1,27 @@ +use hal_api::PosixError; + +use crate::hal; +use crate::hal::Machinelike; + +/// The monotonic clock is brought up by [hal::Machine::init()] +pub fn init() { + if let Err(e) = hal::Machine::init_rtc() { + kprintln!("failed to activate RTC: {}", e); + } +} + +pub fn rtc_backup_register(index: u8) -> u32 { + hal::Machine::rtc_backup_register(index) +} + +pub fn set_rtc_backup_register(index: u8, value: u32) { + hal::Machine::set_rtc_backup_register(index, value) +} + +pub fn walltime() -> Result { + hal::Machine::rtc() +} + +pub fn set_walltime(time: u64) -> Result<(), PosixError> { + hal::Machine::set_rtc(time) +} diff --git a/src/time.rs b/src/time.rs index d3d58fae..1c2307da 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,4 +1,4 @@ -use crate::drivers::clock; +use crate::drivers::rtc; use crate::hal::{self, Machinelike}; use crate::{sched, sync}; @@ -10,14 +10,14 @@ extern "C" fn update_time(_ctx: *mut core::ffi::c_void) { kprintln!( "Time thread started with tick interval {} at {:?}", interval, - clock::walltime() + rtc::walltime() ); loop { let tick = tick(); sched::with(|sched| { - let _ = sched.sleep_until(tick + interval, tick); + let _ = sched.sleep_until(None, tick + interval, tick); }); - kprintln!("time is now {:?}", clock::walltime()); + kprintln!("time is now {:?}", rtc::walltime()); } } diff --git a/src/uapi/time.rs b/src/uapi/time.rs index c1b39dd2..18862751 100644 --- a/src/uapi/time.rs +++ b/src/uapi/time.rs @@ -1,6 +1,6 @@ use hal_api::PosixError; -use crate::{drivers::clock, time}; +use crate::{drivers::rtc, time}; pub fn mono_now() -> u64 { time::mono_now() @@ -15,9 +15,9 @@ pub fn tick() -> u64 { } pub fn walltime() -> Result { - clock::walltime() + rtc::walltime() } pub fn set_walltime(time: u64) -> Result<(), PosixError> { - clock::set_walltime(time) + rtc::set_walltime(time) } From 7555ca495340efd3ea22d3afd4e634c9f7e54ba1 Mon Sep 17 00:00:00 2001 From: Gabriel Kuznik Date: Fri, 29 May 2026 01:44:20 +0200 Subject: [PATCH 7/7] actually register CSS lSE interrupt handler prepare for CSS handler --- machine/cortex-m/src/native.rs | 25 ++++++++++++++----- machine/cortex-m/src/native/rtc.rs | 1 - machine/cortex-m/st/stm32l4/interface/clock.c | 17 ++++++++++++- .../cortex-m/st/stm32l4/interface/export.h | 5 ++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index e0e668b6..e774ea9d 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -43,8 +43,16 @@ fn monotonic_overflow_irq(_ctx: *mut u8, _vector: usize, _userdata: Option) { - unsafe { bindings::css_lse_hndlr() } +fn nmi_irq(_ctx: *mut u8, _vector: usize, _userdata: Option) { + if unsafe { bindings::irq_is_css() } { + unsafe { bindings::css_hndlr() } + } +} + +fn rcc_irq(_ctx: *mut u8, _vector: usize, _userdata: Option) { + if unsafe { bindings::irq_is_lse_css() } { + unsafe { bindings::css_lse_hndlr() } + } } impl hal_api::Machinelike for ArmMachine { @@ -79,11 +87,16 @@ impl hal_api::Machinelike for ArmMachine { panic!("failed to register monotonic timer IRQ at vector {vector}: {e}"); } - /* TODO find vector - let vector = irqn as usize + 16; - if let Err(e) = register(vector, css_lse_irq, None) { - panic!("failed to register CSS LSE IRQ at vector {vector}: {e}"); + /* TODO ensure NMI is not handled elsewhere + let vector = 2; + if let Err(e) = register(vector, nmi_irq, None) { + panic!("failed to register CSS IRQ at vector {vector}: {e}"); }*/ + + let vector = unsafe { bindings::CONST_RCC_IRQn as usize } + 16; + if let Err(e) = register(vector, rcc_irq, None) { + panic!("failed to register CSS LSE IRQ at vector {vector}: {e}"); + } } fn print(s: &str) -> Result<()> { diff --git a/machine/cortex-m/src/native/rtc.rs b/machine/cortex-m/src/native/rtc.rs index c5f867c9..4e57e2c3 100644 --- a/machine/cortex-m/src/native/rtc.rs +++ b/machine/cortex-m/src/native/rtc.rs @@ -2,7 +2,6 @@ use hal_api::PosixError; use super::{Result, bindings}; -#[allow(unused_macros)] macro_rules! println { ($($arg:tt)*) => ({ use core::fmt::Write; diff --git a/machine/cortex-m/st/stm32l4/interface/clock.c b/machine/cortex-m/st/stm32l4/interface/clock.c index c83c4c85..a91092a2 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -11,6 +11,8 @@ static volatile uint32_t tick = 0; #define RTC_BKP_MAGIC 0x4F534952U +const int CONST_RCC_IRQn = RCC_IRQn; + // use msb for the error type // lower byte(s) contain hal status enum ErrorTypes : uint64_t { @@ -83,10 +85,23 @@ static int init_rtc_clock_source(void) return error; } +_Bool irq_is_css(void) { + return __HAL_RCC_GET_IT(RCC_IT_CSS); +} + +_Bool irq_is_lse_css(void) { + return __HAL_RCC_GET_IT(RCC_IT_LSECSS); +} + +void css_hndlr() { + __HAL_RCC_CLEAR_IT(RCC_IT_CSS); + // TODO switch to HSI, reconfigure PLL +} + void css_lse_hndlr() { - HAL_PWR_EnableBkUpAccess(); __HAL_RCC_CLEAR_IT(RCC_IT_LSECSS); + HAL_PWR_EnableBkUpAccess(); // The software MUST then disable the LSECSSON bit HAL_RCCEx_DisableLSECSS(); diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index 13c20938..bc61534b 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -257,6 +257,11 @@ void tim2_hndlr(void); uint64_t init_rtc(void); uint64_t rtc_raw(void); uint64_t set_rtc_raw(uint64_t time); + +extern const int CONST_RCC_IRQn; +_Bool irq_is_css(void); +_Bool irq_is_lse_css(void); +void css_hndlr(void); void css_lse_hndlr(void); uint32_t rtc_backup_register(uint8_t index);