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?