您的位置:首页 > 其它

nrf51822学习之定时器的探究

2016-06-06 13:21 483 查看
[b]SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。[b]具体可咨询:http://www.syd-tek.com/[/b][/b]

nrf51822学习之定时器的探究

主程序调用的定时器初始化函数: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的定时计数模块

到此初始化是分析完毕了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息