From 77fbef7f6ad755a617edb6b55a9457c4e5cfbcbc 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/3] 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 | 143 ++++++++++++++++++ .../cortex-m/st/stm32l4/interface/export.h | 2 + src/lib.rs | 3 + src/time.rs | 125 +++++++++++++++ 7 files changed, 290 insertions(+) diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index 356436d..273305c 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -49,6 +49,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 e12ae1f..87bba3a 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -75,6 +75,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 8675f78..7939d76 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -37,6 +37,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 4110c3c..5ba1617 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -1,8 +1,99 @@ #include "lib.h" +#include #include +#include "stm32l4xx_hal_rcc.h" +#include static volatile uint64_t monotonic_hi = 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; @@ -99,6 +190,7 @@ void init_clock_cfg(void) SystemCoreClockUpdate(); init_monotonic_timer(); + init_rtc(); } unsigned long long monotonic_now(void) @@ -127,4 +219,55 @@ unsigned long long monotonic_now(void) unsigned long long monotonic_freq(void) { return 1000000ULL; +} +} + +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 9d5910b..df52cd8 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -23,3 +23,5 @@ void SystemClock_Config(void); unsigned long long monotonic_now(void); unsigned long long monotonic_freq(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 4f49b67..3a02cc6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,9 @@ pub unsafe extern "C" fn kernel_init() -> ! { idle::init(); kprintln!("Idle thread initialized."); + + time::init(); + kprintln!("Time thread initialized."); let (cyc, _ns) = hal::Machine::bench_end(); kprintln!("Kernel init took {} cycles.", cyc); diff --git a/src/time.rs b/src/time.rs index ed4e510..df82f27 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 b3e63aa4f6ea51a7bf266993d9368d5c1ce57719 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/3] 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 273305c..e923988 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -51,6 +51,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 87bba3a..454eb25 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -83,6 +83,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 7939d76..8cecd96 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -44,6 +44,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 5ba1617..c457a53 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -220,6 +220,16 @@ unsigned long long monotonic_freq(void) { return 1000000ULL; } + +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 df52cd8..bc5e8d7 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -25,3 +25,6 @@ unsigned long long monotonic_now(void); unsigned long long monotonic_freq(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 df82f27..5f7efd9 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 e446ad5570f3d91bb660d501c97645b4ef71ecd8 Mon Sep 17 00:00:00 2001 From: Gabriel <69007475+Friendly-Banana@users.noreply.github.com> Date: Sun, 3 May 2026 21:29:53 +0000 Subject: [PATCH 3/3] 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 | 84 ++++++++++--------- .../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, 107 insertions(+), 75 deletions(-) diff --git a/machine/api/src/lib.rs b/machine/api/src/lib.rs index e923988..f752322 100644 --- a/machine/api/src/lib.rs +++ b/machine/api/src/lib.rs @@ -49,10 +49,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 454eb25..9fc61e0 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -35,7 +35,10 @@ pub struct ArmMachine; impl hal_api::Machinelike for ArmMachine { fn init() { unsafe { - bindings::init_hal(); + let ret = bindings::init_hal(); + if ret != 0 { + panic!("init_hal failed: {}", ret); + } bindings::init_debug_uart(); bindings::dwt_init(); } @@ -75,16 +78,16 @@ impl hal_api::Machinelike for ArmMachine { unsafe { bindings::monotonic_freq() } } - fn get_rtc_raw() -> 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 8cecd96..0f87437 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -37,14 +37,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 c457a53..277e2ea 100644 --- a/machine/cortex-m/st/stm32l4/interface/clock.c +++ b/machine/cortex-m/st/stm32l4/interface/clock.c @@ -10,13 +10,19 @@ static volatile uint64_t monotonic_hi = 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--; @@ -35,37 +41,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; @@ -77,8 +84,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) { @@ -88,10 +94,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) @@ -144,7 +151,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}; @@ -153,7 +160,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 */ @@ -170,7 +177,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 = @@ -185,12 +192,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) @@ -221,7 +228,7 @@ unsigned long long monotonic_freq(void) return 1000000ULL; } -long get_rtc_backup_register(unsigned index) +long rtc_backup_register(unsigned index) { return HAL_RTCEx_BKUPRead(&rtc_handle, RTC_BKP_DR0 + index); } @@ -232,17 +239,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) | @@ -254,7 +261,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}; @@ -270,14 +277,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 bc5e8d7..eec9a83 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -2,7 +2,7 @@ // lib.c unsigned long long systick_freq(void); -void init_hal(void); +int init_hal(void); // uart.c int init_debug_uart(void); @@ -23,8 +23,8 @@ void SystemClock_Config(void); unsigned long long monotonic_now(void); unsigned long long monotonic_freq(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 41319fa..0b59f63 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 c66f171..acdce2d 100644 --- a/machine/cortex-m/st/stm32l4/interface/lib.h +++ b/machine/cortex-m/st/stm32l4/interface/lib.h @@ -1,3 +1,3 @@ #pragma once -void init_clock_cfg(void); \ No newline at end of file +int init_clock_cfg(void); \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3a02cc6..e9032aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,7 @@ pub unsafe extern "C" fn kernel_init() -> ! { idle::init(); kprintln!("Idle thread initialized."); - + time::init(); kprintln!("Time thread initialized."); diff --git a/src/time.rs b/src/time.rs index 5f7efd9..c9936ff 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));