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的定时计数模块
到此初始化是分析完毕了
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的定时计数模块
到此初始化是分析完毕了
相关文章推荐
- nrf51822学习之BLE400初次接触
- nrf51822学习之BLE400与青风开发板调试RADIO模块
- nrf51822学习之第一个BLE程序分析
- nrf51822学习之样例从广播机制窥探整个工程的运行
- facebook post注册。封号。研究
- 在神画Z1看《极限挑战》
- hbuilder 如何调试PHP
- IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
- STM32 串口初始化时的BUG
- Eclipse(properties)插件:PropertyEditor在线安装
- make 2>&1 | tee log.txt之小析
- Android项目开发第四周学习总结
- 自定义百度地图导航控件
- Linux的文件与目录管理的bash shell命令
- 电脑改成护眼的绿豆沙色 RGB 值
- Java基本数据结构总结
- 使用QEMU调试Linux内核代码
- C#.Net 如何动态加载与卸载程序集(.dll或者.exe)1----C#中动态加载和卸载DLL
- IntelliJ IDEA 常用快捷键
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf