[NCS] nrf5340 rtc使用

1.SDK版驱动实现

1.1 API介绍

  • NRFX_TIMER_INSTANCE

/** @brief 创建定时器结构体指针. */
#define NRFX_TIMER_INSTANCE(id)                                   \
{                                                                 \
    .p_reg            = NRFX_CONCAT_2(NRF_TIMER, id),             \
    .instance_id      = NRFX_CONCAT_3(NRFX_TIMER, id, _INST_IDX), \
    .cc_channel_count = NRF_TIMER_CC_CHANNEL_COUNT(id),           \
}
  • nrfx_timer_init

/**
 * @brief 初始化定时器
 *
 * @param[in] p_instance          为定时器结构体指针.
 * @param[in] p_config            定时器配置参数.
 * @param[in] timer_event_handler 定时器处理程序.
 *
 * @retval NRFX_SUCCESS             成功初始化.
 * @retval NRFX_ERROR_INVALID_STATE 已经初始化.
 */
nrfx_err_t nrfx_timer_init(nrfx_timer_t const *        p_instance,
                           nrfx_timer_config_t const * p_config,
                           nrfx_timer_event_handler_t  timer_event_handler);
  • nrfx_timer_uninit

/**
 * @brief 取消定时器初始化.
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_uninit(nrfx_timer_t const * p_instance);
  • nrfx_timer_enable

/**
 * @brief 使能定时器.
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_enable(nrfx_timer_t const * p_instance);
  • nrfx_timer_disable

/**
 * @brief 关闭定时器.
 *
 * The timer will allow to enter the lowest possible SYSTEM_ON state
 * only after this function is called.
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_disable(nrfx_timer_t const * p_instance);
  • nrfx_timer_pause

/**
 * @brief 终止定时器.
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_pause(nrfx_timer_t const * p_instance);
  • nrfx_timer_resume

/**
 * @brief 恢复定时器.
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_resume(nrfx_timer_t const * p_instance);
  • nrfx_timer_clear

/**
 * @brief 清除定时器。
 *
 * @param[in] p_instance 为定时器结构体指针.
 */
void nrfx_timer_clear(nrfx_timer_t const * p_instance);

1.2 移植

1.2.1 bsp_timer.h

#ifndef __BSP_TIMER_H
#define __BSP_TIMER_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <zephyr/kernel.h>

/*
    在此定义若干个软件定时器全局变量
    注意,必须增加__IO 即 volatile,因为这个变量在中断和主程序中同时被访问,有可能造成编译器错误优化。
*/
#define TMR_COUNT 2 /* 软件定时器的个数 (定时器ID范围 0 - 3) */

    /* 定时器结构体,成员变量必须是 volatile, 否则C编译器优化时可能有问题 */
    typedef enum
    {
        TMR_ONCE_MODE = 0, /* 一次工作模式 */
        TMR_AUTO_MODE = 1  /* 自动定时工作模式 */
    } tmr_mode_t;

    /* 定时器结构体,成员变量必须是 volatile, 否则C编译器优化时可能有问题 */
    typedef struct
    {
        volatile uint8_t Mode;     /* 计数器模式,1次性 */
        volatile uint8_t Flag;     /* 定时到达标志  */
        volatile uint32_t Count;   /* 计数器 */
        volatile uint32_t PreLoad; /* 计数器预装值 */
    } soft_tmr_t;

    /* 提供给其他C文件调用的函数 */
    void bsp_StartTimer(uint8_t _id, tmr_mode_t n_timer_mode);
    void bsp_StopTimer(uint8_t _id);

    void bsp_InitTimer(void);

#ifdef __cplusplus
}
#endif

#endif //__BSP_TIMER_H

1.2.2 bsp_timer.c

#include "bsp_timer.h"

#include <nrfx_log.h>
#include <nrfx_timer.h>

/** @brief Symbol specifying timer instance to be used. */
#define TIMER_INST_IDX_0 0
#define TIMER_INST_IDX_1 1

/** @brief Symbol specifying time in milliseconds to wait for handler execution. */
#define TIME_TO_WAIT_10_MS 10UL
#define TIME_TO_WAIT_50_MS 50UL

/* 定于软件定时器结构体变量 */
static soft_tmr_t s_tTmr[TMR_COUNT] = {0};

uint32_t desired_ticks;

static void
timer0_handler(nrf_timer_event_t event_type, void *p_context)
{
    if (event_type == NRF_TIMER_EVENT_COMPARE0)
    {
        // NRFX_LOG_INFO("timer0");
        printf("timer0\r\n");

        if (s_tTmr[0].Mode == TMR_AUTO_MODE)
        {
            nrfx_timer_t timer_inst_0 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_0);
            nrfx_timer_clear(&timer_inst_0);
            nrfx_timer_resume(&timer_inst_0);
        }
    }
}

static void
timer1_handler(nrf_timer_event_t event_type, void *p_context)
{
    if (event_type == NRF_TIMER_EVENT_COMPARE0)
    {
        NRFX_LOG_INFO("timer1");
        printf("timer1\r\n");

        if (s_tTmr[1].Mode == TMR_AUTO_MODE)
        {
            nrfx_timer_t timer_inst_1 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_1);
            nrfx_timer_clear(&timer_inst_1);
            nrfx_timer_resume(&timer_inst_1);
        }
    }
}

void bsp_StartTimer(uint8_t _id, tmr_mode_t n_timer_mode)
{
    if (_id == 0)
    {
        s_tTmr[0].Mode = n_timer_mode;

        nrfx_timer_t timer_inst_0 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_0);
        nrfx_timer_enable(&timer_inst_0);
        NRFX_LOG_INFO("Timer0 status: %s", nrfx_timer_is_enabled(&timer_inst_0) ? "enabled" : "disabled");
    }
    else if (_id == 1)
    {
        s_tTmr[1].Mode = n_timer_mode;

        nrfx_timer_t timer_inst_1 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_1);
        nrfx_timer_enable(&timer_inst_1);
        NRFX_LOG_INFO("Timer1 status: %s", nrfx_timer_is_enabled(&timer_inst_1) ? "enabled" : "disabled");
    }
}

void bsp_StopTimer(uint8_t _id)
{
    if (_id == 0)
    {

        nrfx_timer_t timer_inst_0 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_0);
        nrfx_timer_pause(&timer_inst_0);
        NRFX_LOG_INFO("Timer0 stop");
    }
    else if (_id == 1)
    {
        nrfx_timer_t timer_inst_1 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_1);
        nrfx_timer_pause(&timer_inst_1);
        NRFX_LOG_INFO("Timer1 stop");
    }
}

void bsp_InitTimer(void)
{
    nrfx_err_t status;

    /* timer 0 */
    nrfx_timer_t timer_inst_0 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_0);

    uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer_inst_0.p_reg);
    nrfx_timer_config_t config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
    config.bit_width = NRF_TIMER_BIT_WIDTH_32;
    config.p_context = "Timer0";

    status = nrfx_timer_init(&timer_inst_0, &config, timer0_handler);
    NRFX_ASSERT(status == NRFX_SUCCESS);

#if defined(__ZEPHYR__)
    IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX_0)), IRQ_PRIO_LOWEST,
                       NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX_0), 0);
#endif

    nrfx_timer_clear(&timer_inst_0);

    /* Creating variable desired_ticks to store the output of nrfx_timer_ms_to_ticks function */
    desired_ticks = nrfx_timer_ms_to_ticks(&timer_inst_0, TIME_TO_WAIT_10_MS);
    NRFX_LOG_INFO("Time to wait: %lu ms", TIME_TO_WAIT_10_MS);

    /*
     * Setting the timer channel NRF_TIMER_CC_CHANNEL0 in the extended compare mode to stop the timer and
     * trigger an interrupt if internal counter register is equal to desired_ticks.
     */
    nrfx_timer_extended_compare(&timer_inst_0, NRF_TIMER_CC_CHANNEL0, desired_ticks,
                                NRF_TIMER_SHORT_COMPARE0_STOP_MASK, true);

    /* timer 1 */
    nrfx_timer_t timer_inst_1 = NRFX_TIMER_INSTANCE(TIMER_INST_IDX_1);

    base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer_inst_1.p_reg);
    nrfx_timer_config_t config1 = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
    config1.bit_width = NRF_TIMER_BIT_WIDTH_32;
    config1.p_context = "Timer1";

    status = nrfx_timer_init(&timer_inst_1, &config1, timer1_handler);
    NRFX_ASSERT(status == NRFX_SUCCESS);

#if defined(__ZEPHYR__)
    IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER_INST_IDX_1)), IRQ_PRIO_LOWEST,
                       NRFX_TIMER_INST_HANDLER_GET(TIMER_INST_IDX_1), 0);
#endif

    nrfx_timer_clear(&timer_inst_1);

    /* 转滴答计数 */
    desired_ticks = nrfx_timer_ms_to_ticks(&timer_inst_1, TIME_TO_WAIT_50_MS);
    NRFX_LOG_INFO("Time to wait: %lu ms", TIME_TO_WAIT_50_MS);

    /*
     * Setting the timer channel NRF_TIMER_CC_CHANNEL0 in the extended compare mode to stop the timer and
     * trigger an interrupt if internal counter register is equal to desired_ticks.
     */
    nrfx_timer_extended_compare(&timer_inst_1, NRF_TIMER_CC_CHANNEL0, desired_ticks,
                                NRF_TIMER_SHORT_COMPARE0_STOP_MASK, true);
}

1.2.3 main()添加

bsp_InitTimer();

bsp_StartTimer(0, TMR_AUTO_MODE);
bsp_StartTimer(1, TMR_AUTO_MODE);

在进入while()之前添加此函数即可。

1.3 测试

程序中设置的时间是timer0——10ms,timer1——50ms.可以看出是有效的运行5个timer0和1个timer1的。

2 基于zephyr实现

此例程基于LED的例程修改,不懂的可以翻看之前的GPIO设置博客。

2.1 prj.comf文件使能RTC

CONFIG_LOG=y			#开启log打印
CONFIG_NRF53_SYNC_RTC=y #使能rtc

2.2 main修改

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include "bsp_led.h"

#include <zephyr/device.h>
#include <zephyr/sys/printk.h>
#include <zephyr/logging/log.h>/* log头文件 */

LOG_MODULE_REGISTER(main);

/* 定时器延迟 */
#define TIME0_MS 50
#define TIME1_MS 200

/* 定时器处理函数 */
static void timeout_handler0(struct k_timer *timer);
static void timeout_handler1(struct k_timer *timer);

/* 初始化定时器 */
K_TIMER_DEFINE(timer, timeout_handler0, NULL);
K_TIMER_DEFINE(timer1, timeout_handler1, NULL);

static void timeout_handler0(struct k_timer *timer)
{
	uint32_t now = sys_clock_tick_get_32();
	bsp_LedToggle(0);
	LOG_INF("timer 0 at %d ticks", now);
}

static void timeout_handler1(struct k_timer *timer)
{
	uint32_t now = sys_clock_tick_get_32();
	bsp_LedToggle(1);
	LOG_INF("timer 1 at %d ticks", now);
}

int main(void)
{
	int ret;

	bsp_InitLed(); /* LED初始化 */

	LOG_INF("zephyr using rtc");

	k_timer_start(&timer, K_MSEC(TIME0_MS), K_MSEC(TIME0_MS)); /* 启动定时器 */
	k_timer_start(&timer1, K_MSEC(TIME1_MS), K_MSEC(TIME1_MS));

	return 0;
}

2.3 测试

posted @ 2024-03-15 11:59  wfagly  阅读(378)  评论(0)    收藏  举报