上一篇文章《蓝牙单芯片DA14580的硬件架构和低功耗》阐述了DA14580的硬件架构和低功耗的工作原理。本文文章阐述该平台的软件体系,并着重分析消息事件的处理机制。
一、DA14580SOC硬件组成和软件体系组成
DA14580芯片硬件架构包含三个部分:
1)使用ARM公司的cortex M0作为CPUprocessor处理器。
2)使用RivieraWaves公司的IP核作为BLEcore和基带、射频部分。
3)集成时钟管理CMU、电源管理PMU、memory控制存储和其它外围模块控制器,如GPIO、UART、I2C、SPI和timer等等。
对应地,DA14580平台SDK的软件组成也包含下面组成部分:
1)ARMcortex M0平台相关的库文件,如启动、CMSIS(the cortex Microcontroller software interface standard)支持的寄存器訪问、中断异常訪问接口等。
2)RW公司的BLE驱动、射频驱动。此外RW BLE还集成了系统的内核部分,其提供消息处理、定时器和任务调度等核心功能。
所以DA14580平台SDK的开发是基于RW公司研发的内核,而不是DIALOG公司研发的。
此部分大部分的代码都是固化在ROM里面。
3)SOC集成的其它模块的驱动。由DIALOG公司提供,如UART驱动等,此外其调用RW内核的相关接口来完毕消息循环和低功耗功能。
4)应用程序。调用以上三个部分的接口来完毕自己定义功能。
我们重点分析2)中的RW内核机制和功能。
二、RW内核
RW内核的指导文档为《RW-BT-KERNEL-SW-FS.pdf》。其主要包含下面三个部分:
1)Message,消息处理机制。
2)Taskand Schedule,任务和调度。
3)Timer,定时器用法。
三、Task
RW在BLE协议栈层次的基础上抽象了多个任务task。每一个task完毕一个软件层次的功能。所以说RW内核是支持多个任务task的。但本质上。RW内核也是一个单任务内核,所以各个task能够看成是能够完毕特定功能的独立函数体或者函数集合。
每一个task都有一个task ID。其具有优先级功能。相似于UCOS的优先级。
RW内核和UCOS的差别是:UCOS是多任务内核,具有时间片轮流运行,并具有相互排斥同步。
四、Message
4.1 消息标识
一个消息就要区分它是属于哪个task的。并且还要区分同一个task里面的不同消息。所以一个Message包含两个部分:
TASK_TYPE即是task的ID。在调度时。优先级高的task的消息会先得到运行处理。
4.2 消息结构体元素
我们仅仅须要关注红色圈着的这五个元素,第一个元素能够看出消息结构体节点是以链表的形式来管理的。HCI相关的是指USB dongle这样的应用形式,由PC主机控制蓝牙BLE,咱们不讨论这样的应用。
红色圈到的五个元素分别的是:
1)id。即第一点说到的消息标识。
2)消息由哪个目标task处理。
3)发出消息的task
4)消息參数的长度
5)消息參数的结构体地址
消息參数结构体是能够自己定义的,这里通过void*转换传入地址。
4.3 消息动态内存管理
RW内核专门给消息处理提供动态内存管理机制。接口是:
void*ke_msg_alloc(ke_msg_id_t const id, ke_task_id_t const dest_id,
ke_task_id_t const src_id,uint16_t const param_len);
一般给应用提供一个宏,用于简化写法:
#defineKE_MSG_ALLOC(id, dest, src, param_str) \
(struct param_str*) ke_msg_alloc(id, dest, src, sizeof(structparam_str))
释放接口是:void ke_msg_free(struct ke_msg const *param);. 在调度机制里面会通过推断消息处理的返回值对消息进行对应的处理,如释放消息的内存。用户编程一般不用调用释放接口。
4.4 消息接口
1)带參数的消息发送
voidke_msg_send(void const *param_ptr); param_ptr须要通过ke_msg_alloc接口申请动态内存。
一般的命令消息发送写法例如以下:
structgapm_set_dev_config_cmd* cmd = KE_MSG_ALLOC(GAPM_SET_DEV_CONFIG_CMD,
TASK_GAPM, TASK_APP,gapm_set_dev_config_cmd);
ke_msg_send(cmd);
2)不带參数的消息发送
voidke_msg_send_basic(ke_msg_id_t const id, ke_task_id_t const dest_id,ke_task_id_t const src_id)
五、TIMER
5.1 定时单位
10ms,RW内核提供一个定时器,其并非DA14580集成的TIMER1和TIMER3。对定时器的初始化等工作是在BLE初始化内部的,不须要用户编程设置。
用户仅仅须要调用RW内核的TIMER接口就可以。
5.2 设置timer
voidke_timer_set(ke_msg_id_t const timer_id, ke_task_id_t const task, uint16_tconst delay);
timer_id是定时器消息。其属于一种不带參数的MESSAGE,delay是定时时间,10ms为单位,当时间到达时,RW内核会发送timer_id到目标task的消息队列。当内核schedule时即会运行定时器对应的回调。
六、Schedule
1.先取出最高优先级task的消息事件,该消息从消息队列中pop出来
2.依据task的状态和消息ID来得到对应的handler
3.运行该handler回调
4.依据回调的返回值对消息进行处理
1)假设返回KE_MSG_CONSUMED,则内核free掉该消息。
2)假设返回KE_MSG_NO_FREE。则内核不处理该消息,但该消息也不会又一次放到消息队列,即内核不能再从消息队列中获得该消息。
3)假设返回KE_MSG_SAVED。则内核不free该消息。并且将该消息又一次入列。
七、基于状态机的RW内核消息处理机制
Task数据结构例如以下:
RW内核是基于状态机对消息进行处理的。从ke_task_desc看来,一个task包含显式的状态处理state_handler和默认的状态处理default_handler。
state是task的状态机变量,task可能有多个状态。那么state_handler是状态处理集合,每一个状态可能会处理多个消息回调。比如上层task会发送消息来运行调用,或者下层task发送消息来运行回调。
default_handler处理的消息代表该task在随意状态时都可能受到的消息,比如底层task发出的断开连接消息。
我们也能够得出。ke_state_handler代表一个状态下的多个消息处理。
因此,state_handler是一个ke_state_handler数组,而default_handler则是ke_state_handler元素。
八、參考文献:
《UM-B-015_DA14580 Software architecture v4.0.pdf》、
《RW-BT-KERNEL-SW-FS.pdf》。
下一篇。敬请期待:
全球最低功耗蓝牙单芯片DA14580的软件体系
-层次架构和BLE消息事件处理过程
技术咨询请发邮件:yqwucheng@163.com。
百分百原创。每周两篇。阿里、魅族、nvidia、龙芯、炬力、拓尔思等*企业资深project师分享----嵌入式、Linux、物联网、GPU、Android、自己主动驾驶等技术,欢迎扫码关注微信公众号:嵌入式企鹅圈,实时推送原创文章!