Hello,
I’m trying to obtain millisecond precision on nRF Connect using the MCU’s internal RTC.
My code:
/*! * \file smtc_hal_rtc.c * * \brief RTC Hardware Abstraction Layer implementation * */ #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/rtc.h> #include <zephyr/drivers/counter.h> #include <zephyr/logging/log.h> #include <zephyr/sys/util.h> #include <nrfx_rtc.h> #include "smtc_hal_rtc.h" #include "smtc_hal_dbg_trace.h" LOG_MODULE_REGISTER(smtc_hal_rtc, LOG_LEVEL_INF); static struct k_sem wake_sem; static const struct device *const rtc_dev = DEVICE_DT_GET(DT_NODELABEL(rtc2)); static uint32_t freq = 32768; static uint32_t rtc_wrap_counter = 0; static hal_lp_timer_irq_t lptim_tmr_irq[2]; static void rtc_handler(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data); static void rtc_overflow_handler(const struct device *dev, void *user_data); static void rtc_wakeup_handler(void *obj); void hal_rtc_init( void ) { if (!device_is_ready(rtc_dev)) { LOG_ERR("RTC device not ready"); return; } struct counter_top_cfg top_cfg = { .ticks = 0xFFFFFF, // 24-bit RTC .callback = rtc_overflow_handler, .user_data = NULL, .flags = COUNTER_TOP_CFG_RESET_WHEN_LATE }; int err = counter_set_top_value(rtc_dev, &top_cfg); if (err) { LOG_ERR("Failed to set top value: %d", err); } counter_start(rtc_dev); } static void rtc_overflow_handler(const struct device *dev, void *user_data) { ARG_UNUSED(dev); ARG_UNUSED(user_data); rtc_wrap_counter++; LOG_INF("ENTROU"); } uint32_t hal_rtc_get_time_s(void) { uint32_t wrap1, wrap2, ticks; uint32_t total_ticks; do { wrap1 = rtc_wrap_counter; int err = counter_get_value(rtc_dev, &ticks); if (err) { LOG_ERR("Failed to get counter value: %d", err); return 0; } wrap2 = rtc_wrap_counter; } while (wrap1 != wrap2); total_ticks = ticks + (wrap1 * (1UL << 24)); return total_ticks / freq; } uint32_t hal_rtc_get_time_ms(void) { uint32_t ticks; int err = counter_get_value(rtc_dev, &ticks); if (err) { LOG_ERR("Failed to get counter value: %d", err); return 0; } uint32_t total_ticks = ticks + (rtc_wrap_counter * (1UL << 24)); uint32_t ms = (total_ticks * 1000UL) / freq; LOG_INF("ticks: %d", ticks); LOG_INF("total_ticks: %d", total_ticks); LOG_INF("ms: %d", ms); return ms; } void hal_lp_timer_start(const uint32_t milliseconds, const hal_lp_timer_irq_t *tmr_irq) { hal_lp_timer_irq_enable(); uint32_t freq = counter_get_frequency(rtc_dev); // 32768 uint32_t ticks = (milliseconds * freq) / 1000; struct counter_alarm_cfg alarm_cfg = { .callback = rtc_handler, .ticks = ticks, .user_data = (void *)tmr_irq, .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE }; int cancel_err = counter_cancel_channel_alarm(rtc_dev, 0); if (cancel_err && cancel_err != -ENOTSUP) { SMTC_HAL_TRACE_PRINTF("Erro ao cancelar alarme existente: %d", cancel_err); } int err = counter_set_channel_alarm(rtc_dev, 0, &alarm_cfg); if (err != 0) { SMTC_HAL_TRACE_PRINTF("Erro ao configurar alarme: %d", err); return; } static hal_lp_timer_irq_t persistent_irq; persistent_irq = *tmr_irq; lptim_tmr_irq[0] = persistent_irq; } void hal_lp_timer_stop(void) { hal_lp_timer_irq_disable(); int err = counter_cancel_channel_alarm(rtc_dev, 0); if (err != 0) { SMTC_HAL_TRACE_PRINTF("Failed to cancel alarm: %d", err); } NVIC_ClearPendingIRQ(RTC2_IRQn); } void hal_lp_timer_irq_enable( void ) { NVIC_EnableIRQ( RTC2_IRQn ); } void hal_lp_timer_irq_disable( void ) { NVIC_DisableIRQ( RTC2_IRQn ); } static void my_rtc_alarm_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data) { // ARG_UNUSED(dev); // ARG_UNUSED(chan_id); // ARG_UNUSED(ticks); // ARG_UNUSED(user_data); // // k_sem_give(&wake_sem); } void hal_rtc_wakeup_timer_set_ms(int32_t milliseconds) { // k_sem_init(&wake_sem, 0, 1); // uint32_t freq = counter_get_frequency(rtc_dev); // uint32_t ticks = (milliseconds * freq) / 1000; // struct counter_alarm_cfg alarm_cfg = { // .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, // .ticks = ticks, // .callback = my_rtc_alarm_callback, // .user_data = NULL, // }; // int cancel_err = counter_cancel_channel_alarm(rtc_dev, 1); // if (cancel_err && cancel_err != -ENOTSUP) { // LOG_ERR("Erro ao cancelar alarme existente: %d", cancel_err); // } // int err = counter_set_channel_alarm(rtc_dev, 1, &alarm_cfg); // if (err < 0) { // LOG_ERR("Erro ao configurar alarme (%d)", err); // return; // } // // k_sem_take(&wake_sem, K_FOREVER); // counter_cancel_channel_alarm(rtc_dev, 1); } static void rtc_handler(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data) { hal_lp_timer_irq_t *irq = (hal_lp_timer_irq_t *)user_data; if (irq && irq->callback) { irq->callback(irq->context); } } static void rtc_wakeup_handler( void* obj ){ // Implementação do handler de wakeup se necessário }
After 131000 ms, a got:
[00:02:18.097,473] <inf> smtc_hal_rtc: ms: 131023 [00:02:18.107,849] <inf> smtc_hal_rtc: ticks: 4294052 [00:02:18.108,184] <inf> smtc_hal_rtc: total_ticks: 4294052 [00:02:18.118,469] <inf> smtc_hal_rtc: ms: 131044 [00:02:18.123,809] <inf> smtc_hal_rtc: ticks: 4294575 [00:02:18.129,119] <inf> smtc_hal_rtc: total_ticks: 4294575 [00:02:18.134,429] <inf> smtc_hal_rtc: ms: 131060 [00:02:18.139,709] <inf> smtc_hal_rtc: ticks: 4295097 [00:02:18.145,019] <inf> smtc_hal_rtc: total_ticks: 4295097 [00:02:18.150,360] <inf> smtc_hal_rtc: ms: 3 [00:02:18.155,609] <inf> smtc_hal_rtc: ticks: 4295618 [00:02:18.160,919] <inf> smtc_hal_rtc: total_ticks: 4295618 [00:02:18.166,259] <inf> smtc_hal_rtc: ms: 19 [00:02:18.166,534] <inf> smtc_hal_rtc: ticks: 4295976 [00:02:18.171,844] <inf> smtc_hal_rtc: total_ticks: 4295976 [00:02:18.182,128] <inf> smtc_hal_rtc: ms: 30
Could someone help me find where my error is?