| | |
| | | /* |
| | | * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and |
| | | * Copyright (c) 2019-2025 Beijing Hanwei Innovation Technology Ltd. Co. and |
| | | * its subsidiaries and affiliates (collectly called MKSEMI). |
| | | * |
| | | * All rights reserved. |
| | |
| | | }, |
| | | }; |
| | | |
| | | int rtc_open(enum RTC_DEV_T id) |
| | | uint32_t rtc_ms(void) |
| | | { |
| | | uint32_t now = rtc_get(RTC_ID0); |
| | | |
| | | // split 15U to 5U+10U, for ~1ms resolution, and overflows when ticks > ~2^27(~4000s) |
| | | return ((now >> 5U) * 1000) >> 10U; |
| | | } |
| | | |
| | | uint32_t rtc_us(void) |
| | | { |
| | | uint32_t now = rtc_get(RTC_ID0); |
| | | |
| | | // x * 10^6 / 32768 ~= x * 30.518 ~= x * 61 / 2 |
| | | // resolution 61us(~2 ticks), overflows every 4300s |
| | | return (now >> 1U) * 61U; |
| | | } |
| | | |
| | | int rtc_open(enum RTC_DEV_T id, uint8_t rst_en) |
| | | { |
| | | if (id >= RTC_MAX_NUM) |
| | | { |
| | |
| | | |
| | | // enable RTC clock |
| | | clock_enable(CLOCK_RTC); |
| | | |
| | | if (rst_en) |
| | | { |
| | | reset_module(RESET_MODULE_RTC); |
| | | } |
| | | |
| | | rtc_handle[id].rtc_open_flag = 1; |
| | | |
| | | if ((rtc_handle[id].base->CTRL & RTC_CTRL_START_MSK) == 0) |
| | |
| | | uint32_t rtc_get(enum RTC_DEV_T id) |
| | | { |
| | | return rtc_handle[id].base->DATA; |
| | | } |
| | | |
| | | int rtc_set_alarm_lite(enum RTC_DEV_T id, uint32_t target) |
| | | { |
| | | rtc_handle[id].base->MATCH = target; |
| | | rtc_handle[id].base->INTR_CLR = RTC_INTR_CLR_MSK; |
| | | |
| | | return DRV_OK; |
| | | } |
| | | |
| | | int rtc_set_alarm(enum RTC_DEV_T id, uint32_t target, drv_callback_t callback) |
| | |
| | | |
| | | if (rtc_handle[id].alarm_callback != NULL) |
| | | { |
| | | uint32_t value = rtc_handle[id].base->DATA; |
| | | rtc_handle[id].alarm_callback(&value, 0); |
| | | rtc_handle[id].alarm_callback(&id, rtc_handle[id].base->MATCH); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | if (time->year < 1970 || time->month < 1 || time->month > 12 || time->day < 1 || time->day > rtc_month_days(time->month, time->year) || time->hour >= 24 || |
| | | time->minute >= 60 || time->second >= 60) |
| | | time->minute >= 60 || time->second >= 60) |
| | | { |
| | | return DRV_ERROR; |
| | | } |
| | |
| | | time->second = (uint8_t)(second - time->minute * 60); |
| | | } |
| | | |
| | | int rtc_open(enum RTC_DEV_T id, drv_callback_t callback) |
| | | int rtc_open(enum RTC_DEV_T id, uint8_t rst_en, drv_callback_t callback) |
| | | { |
| | | if (id >= RTC_MAX_NUM) |
| | | { |
| | |
| | | |
| | | // enable RTC clock |
| | | clock_enable(CLOCK_RTC); |
| | | |
| | | if (rst_en) |
| | | { |
| | | reset_module(RESET_MODULE_RTC); |
| | | } |
| | | |
| | | rtc_handle[id].rtc_open_flag = 1; |
| | | |
| | | if (rtc_handle[id].tick_int_en) |
| | |
| | | { |
| | | uint32_t value = rtc_handle[id].base->DATA; |
| | | rtc_second_to_time(value, &time); |
| | | rtc_handle[id].tick_callback(&time, 0); |
| | | rtc_handle[id].tick_callback(&id, (uint32_t)&time); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | uint32_t value = rtc_handle[id].base->DATA; |
| | | rtc_second_to_time(value, &time); |
| | | rtc_handle[id].alarm_callback(&time, 0); |
| | | rtc_handle[id].alarm_callback(&id, (uint32_t)(&time)); |
| | | } |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | void rco32k_clk_calibrate(enum RCO32_MEAS_TIME_T time) |
| | | void clk32k_ppm_calibrate(enum CLK32K_MEAS_TIME_T time) |
| | | { |
| | | enum RTC_DEV_T id = RTC_ID0; |
| | | if (rtc_handle[id].rtc_open_flag == 0) |
| | | { |
| | | // enable RTC clock |
| | | clock_enable(CLOCK_RTC); |
| | | if (sleep_timer_handle.enable == 0) |
| | | { |
| | | // enable RTC clock |
| | | clock_enable(CLOCK_RTC); |
| | | } |
| | | rtc_handle[id].base->CTRL = RTC_CTRL_START_MSK; |
| | | } |
| | | |
| | | NVIC_SetPriority(RCO32K_CAL_IRQn, IRQ_PRIORITY_NORMAL); |
| | | NVIC_ClearPendingIRQ(RCO32K_CAL_IRQn); |
| | | NVIC_EnableIRQ(RCO32K_CAL_IRQn); |
| | | NVIC_SetPriority(CLK32K_CAL_IRQn, IRQ_PRIORITY_NORMAL); |
| | | NVIC_ClearPendingIRQ(CLK32K_CAL_IRQn); |
| | | NVIC_EnableIRQ(CLK32K_CAL_IRQn); |
| | | |
| | | rtc_handle[id].base->MEASURE = 0; |
| | | rtc_handle[id].base->MEASURE = RTC_MEASURE_TIME(time) | RTC_MEASURE_EN_MSK; |
| | | } |
| | | |
| | | void RCO32K_CAL_IRQHandler(void) |
| | | void CLK32K_CAL_IRQHandler(void) |
| | | { |
| | | enum RTC_DEV_T id = RTC_ID0; |
| | | if ((rtc_handle[id].base->MEASURE & RTC_MEASURE_DONE_MSK) == 0) |
| | |
| | | uint32_t measure_cnt = rtc_handle[id].base->MEASURE & RTC_MEASURE_CNT_MSK; |
| | | uint32_t pclk = clock_get_frequency(CLOCK_APB_CLK); |
| | | |
| | | uint32_t ppm_target_cnt = measure_cycles * pclk / 32768; |
| | | int32_t ppm = (int32_t)((int32_t)(ppm_target_cnt - measure_cnt) * 1000000 / (int32_t)ppm_target_cnt); |
| | | uint32_t ppm_target_cnt = (uint32_t)((float)measure_cycles * ((float)pclk / 32768.0f)); |
| | | int32_t ppm = (int32_t)((int32_t)(measure_cnt - ppm_target_cnt) * 1000000 / (int32_t)ppm_target_cnt); |
| | | sleep_timer_ppm_set(ppm); |
| | | LOG_INFO(TRACE_MODULE_DRIVER, "RCO32K ppm %d\r\n", ppm); |
| | | LOG_INFO(TRACE_MODULE_DRIVER, "CLK32K ppm %d\r\n", ppm); |
| | | |
| | | if (rtc_handle[id].rtc_open_flag == 0) |
| | | { |
| | | rtc_handle[id].base->CTRL = 0; |
| | | // disable RTC clock |
| | | clock_disable(CLOCK_RTC); |
| | | if (sleep_timer_handle.enable == 0) |
| | | { |
| | | // disable RTC clock |
| | | clock_disable(CLOCK_RTC); |
| | | } |
| | | } |
| | | else |
| | | { |