nrf51822学习之定时器的探究

来源:互联网 发布:ci 数据库 编辑:程序博客网 时间:2024/05/16 10:34

主程序调用的定时器初始化函数:timers_init();

内容如下:

static void timers_init(void)
{
    // Initialize timer module, making it use the scheduler
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);

    /* YOUR_JOB: Create any timers to be used by the application.
                 Below is an example of how to create a timer.
                 For every new timer needed, increase the value of the macro APP_TIMER_MAX_TIMERS by
                 one.
    err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
    APP_ERROR_CHECK(err_code); */
}

这个定时器初始化函数最终使用的是RTC时钟,作为整个程序的宏观脉搏,为调度器使用,当然用户也可以创建时钟。

 static uint32_t APP_TIMER_BUF[CEIL_DIV(APP_TIMER_BUF_SIZE((MAX_TIMERS),                    \
                                                                  (OP_QUEUES_SIZE) + 1),           \
                                               sizeof(uint32_t))];                                 \

这是计算要分配的定时器内存区大小,说到底就是分配一个静态的数组,这个数组的类型是uint32_t,细看这个数组的项数,有下面这个函数:

#define CEIL_DIV(A, B)      \
    /*lint -save -e573 */   \
    ((((A) - 1) / (B)) + 1) \
    /*lint -restore */

可以看到,这个数组是以uint32_t就是4个字节为单位的,具体计算再看:

APP_TIMER_BUF_SIZE((MAX_TIMERS),                    \
                                                                  (OP_QUEUES_SIZE) + 1),

这里各个含义如下:

#define APP_TIMER_BUF_SIZE(MAX_TIMERS, OP_QUEUE_SIZE)                                              \
    (                                                                                              \
        ((MAX_TIMERS) * APP_TIMER_NODE_SIZE)                                                       \
        +                                                                                          \
        (                                                                                          \
            APP_TIMER_INT_LEVELS                                                                   \
            *                                                                                      \
            (APP_TIMER_USER_SIZE + ((OP_QUEUE_SIZE) + 1) * APP_TIMER_USER_OP_SIZE)                 \
        )                                                                                          \
    )

其中传入的变量:

#define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
#define APP_TIMER_MAX_TIMERS            2                                           /**< Maximum number of simultaneously created timers. */
#define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */

也就是说 MAX_TIMERS=2  OP_QUEUE_SIZE)=4,再看其他的变量:

#define APP_TIMER_NODE_SIZE          40                         /**< Size of app_timer.timer_node_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_OP_SIZE       24                         /**< Size of app_timer.timer_user_op_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_USER_SIZE          8                          /**< Size of app_timer.timer_user_t (only for use inside APP_TIMER_BUF_SIZE()). */
#define APP_TIMER_INT_LEVELS         3                          /**< Number of interrupt levels from where timer operations may be initiated (only for use inside                      APP_TIMER_BUF_SIZE()). */

从这里看APP_TIMER_BUF_SIZE函数的功能就是计算出time模块一共需要多少内存区域,然后经过CEIL_DIV函数对齐4字节的计算就知道了要分配多少个数组项给定时器模块


分配了内存区,然后下来的就是初始化rtc时钟了:

        uint32_t ERR_CODE = app_timer_init((PRESCALER),                                            \
                                           (MAX_TIMERS),                                           \
                                           (OP_QUEUES_SIZE) + 1,                                   \
                                           APP_TIMER_BUF,                                          \
                                           (USE_SCHEDULER) ? app_timer_evt_schedule : NULL);       \

该函数的源代码如下:

uint32_t app_timer_init(uint32_t                      prescaler,//预分频器
                        uint8_t                       max_timers,//最大时间
                        uint8_t                       op_queues_size,
                        void *                        p_buffer,
                        app_timer_evt_schedule_func_t evt_schedule_func)
{
    int i;

    // Check that buffer is correctly aligned检查缓冲区是否正确字对齐
    if (!is_word_aligned(p_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;//无效的参数
    }
    // 检查空缓冲区
    if (p_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    
    // Stop RTC to prevent any running timers from expiring (in case of reinitialization)RTC停止
    rtc1_stop();
    
    m_evt_schedule_func = evt_schedule_func;//按键调度事件

    // Initialize timer node array初始化定时器节点数组
    m_node_array_size = max_timers;
    mp_nodes          = p_buffer;
    
    for (i = 0; i < max_timers; i++)
    {
        mp_nodes[i].state      = STATE_FREE;
        mp_nodes[i].is_running = false;
    }
    
    // Skip timer node array
    p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
    
    // Initialize users array
    m_user_array_size = APP_TIMER_INT_LEVELS;
    mp_users          = p_buffer;
    
    // Skip user array
    p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];

    // Initialize operation queues
    for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
    {
        timer_user_t * p_user = &mp_users[i];
        
        p_user->first              = 0;
        p_user->last               = 0;
        p_user->user_op_queue_size = op_queues_size;
        p_user->p_user_op_queue    = p_buffer;
    
        // Skip operation queue
        p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
    }

    m_timer_id_head             = TIMER_NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

    NVIC_ClearPendingIRQ(SWI0_IRQn);
    NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
    NVIC_EnableIRQ(SWI0_IRQn);

    rtc1_init(prescaler);

    m_ticks_latest = rtc1_counter_get();
    
    return NRF_SUCCESS;
}

首先要做的就是检查内存区是否是4字节对齐和是否存在

    // Check that buffer is correctly aligned检查缓冲区是否正确字对齐
    if (!is_word_aligned(p_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;//无效的参数
    }
    // 检查空缓冲区
    if (p_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

然后停止rtc

    // Stop RTC to prevent any running timers from expiring (in case of reinitialization)RTC停止
    rtc1_stop();

源码如下:

static void rtc1_stop(void)
{
    NVIC_DisableIRQ(RTC1_IRQn);

    NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;         //清除比较器
    NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;    //停止比较器使能

    NRF_RTC1->TASKS_STOP = 1;    //停止RTC模块
    nrf_delay_us(MAX_RTC_TASKS_DELAY);
}

然后根据传入进来的参数给全局变量赋值:

    m_evt_schedule_func = evt_schedule_func;//按键调度事件
    // Initialize timer node array初始化定时器节点数组
    m_node_array_size = max_timers;
    mp_nodes          = p_buffer;

主意这些全局变量,在后面才会使用,在本函数没有使用,只是赋值而已,下面给初始化定时器各个队列,比如设置定时器的使用标志和是否运行标志以及初始化操作队列

    for (i = 0; i < max_timers; i++)
    {
        mp_nodes[i].state      = STATE_FREE;
        mp_nodes[i].is_running = false;
    }

   // Skip timer node array
    p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
    
    // Initialize users array
    m_user_array_size = APP_TIMER_INT_LEVELS;
    mp_users          = p_buffer;
    
    // Skip user array
    p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];

    // Initialize operation queues
    for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
    {
        timer_user_t * p_user = &mp_users[i];
        
        p_user->first              = 0;
        p_user->last               = 0;
        p_user->user_op_queue_size = op_queues_size;
        p_user->p_user_op_queue    = p_buffer;
    
        // Skip operation queue
        p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
    }

    m_timer_id_head             = TIMER_NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

然后初始化一个软件中断,这个也是给后面的定时各个函数使用的使用的

    NVIC_ClearPendingIRQ(SWI0_IRQn);
    NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
    NVIC_EnableIRQ(SWI0_IRQn);


然后是rtc时钟的初始化

rtc1_init(prescaler);

这里传入的参数是#define APP_TIMER_PRESCALER             0    下面细看这个函数

static void rtc1_init(uint32_t prescaler)
{
    NRF_RTC1->PRESCALER = prescaler;
    NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI);
}

主意这里只是设置rtc的分频和中断优先级,优先级不论,说说这个分频,也就是rtc的频率是32768   ,中断不可能以这个频率去跑,那只能够说明定时器模块的频率毕竟和RTC的比较器有关了,或许不同的定时器模块他的比较器的值是不一样的吧。

最后是获取一下计数值,以更新一个全局变量:

 m_ticks_latest = rtc1_counter_get();


主意到这里并没有开始定时器

还有这里的定时器指的是RTC而不是51822的定时计数模块

到此初始化是分析完毕了

0 0