TI 系列的蓝牙芯片在协议栈支持上比较完善,最近使用CC254x系列BLE芯片,发现其协议栈的实现挺有意思,这里做点简单分析。
1.协议栈结构
CC2540 集成了增强型的 8051 内核, TI 为 BLE 协议栈搭建了一个简单的操作系统OSAL,即一种任务轮询机制。帮你做好了底层和蓝牙协议深层的内容,将复杂部分屏蔽掉。让用户通过 API 函数就可以轻易用蓝牙 4.0,是开发起来更加方便,开发周期也可以相应缩短。
安装完 BLE 协议栈之后,会在安装目录下看到以下文件结构:
其中,Accessories存放附件,如:USB驱动和hex文件。Components即为OSAL操作系统的底层实现,里面包括OSAL的各层具体实现。
Documents为协议栈相关说明文档,Projects为官方提供的demos,很多demo都是可以直接修改使用的,其中重点关心四个demo:
SimpleBLEBroadcaster、SimpleBLECentral、SimpleBLEObserver、SimpleBLEPeripheral。
这四个代码是CC254x开发的基本模板,他们都有自己的特点。
· Broadcaster 广播员 —— 非连接性的信号装置
· Observer 观察者 —— 扫描得到,但不能链接
· Peripheral 从机 —— 可链接,在单个链路层链接中作为从机
· Central 主机 —— 扫描设备并发起链接,在单链路层或多链路层中作为主机。
2.协议栈OSAL原理分析
协议栈中所谓的OSAL就是一个小型的操作系统,实现了最基本的任务轮询。
直接从main函数开始解剖:
- int main(void)
- {
- /* Initialize hardware */
- HAL_BOARD_INIT();
- // Initialize board I/O
- InitBoard( OB_COLD );
- /* Initialze the HAL driver */
- HalDriverInit();
- /* Initialize NV system */
- osal_snv_init();
- /* Initialize LL */
- /* Initialize the operating system */
- osal_init_system();
- /* Enable interrupts */
- HAL_ENABLE_INTERRUPTS();
- // Final board initialization
- InitBoard( OB_READY );
- #if defined ( POWER_SAVING )
- osal_pwrmgr_device( PWRMGR_BATTERY );
- #endif
- /* Start OSAL */
- osal_start_system(); // No Return from here
- return 0;
- }
主函数一进去就是各种系统初始化:包括硬件、GATT、 GAP 层、任务等的初始化。然后执行 osal_start_system();操作系统。我们重点关心2 个函数: 我们先来看 osal_init_system();系统初始化函数,进入函数。发现里面有 6个初始化函数,这里我们只关心osalInitTasks();任务初始化函数。继续由该函数进入,进入后发现终于看到各层任务的添加,taskID 依次递增表示优先级降低,即越底层优先级越高(LL、HAL、HCI、L2CAP、GAP、GATT、SM、Profiles、Application)
- void osalInitTasks( void )
- {
- uint8 taskID = 0;
- tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
- osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
- /* LL Task */
- LL_Init( taskID++ );
- /* Hal Task */
- Hal_Init( taskID++ );
- /* HCI Task */
- HCI_Init( taskID++ );
- #if defined ( OSAL_CBTIMER_NUM_TASKS )
- /* Callback Timer Tasks */
- osal_CbTimerInit( taskID );
- taskID += OSAL_CBTIMER_NUM_TASKS;
- #endif
- /* L2CAP Task */
- L2CAP_Init( taskID++ );
- /* GAP Task */
- GAP_Init( taskID++ );
- /* GATT Task */
- GATT_Init( taskID++ );
- /* SM Task */
- SM_Init( taskID++ );
- /* Profiles */
- GAPCentralRole_Init( taskID++ );
- GAPBondMgr_Init( taskID++ );
- GATTServApp_Init( taskID++ );
- /* Application */
- SimpleBLECentral_Init( taskID );
- }
最高层即应用层优先级最低,最后执行应用层的任务初始化。我们再来看第二个函数 osal_start_system();运行操作系统。同样用 go to definition 的方法进入该函数。再进入 osal_run_system() ,我们欣喜地发现这里就是任务轮询的基本轮廓,源码和分析如下:
- void osal_run_system( void )
- {
- uint8 idx = 0;
- #ifndef HAL_BOARD_CC2538
- osalTimeUpdate();
- #endif
- Hal_ProcessPoll();
- //这段代码扫描触发的任务
- do {
- if (tasksEvents[idx]) //优先级高的任务被置位,说明有任务触发
- {
- break;//跳出任务扫描,得到的idx即为任务ID!
- }
- } while (++idx < tasksCnt);//idx从0开始递增,先查询高优先级的任务
- if (idx < tasksCnt)
- {
- uint16 events;
- halIntState_t intState;
- //然后进入临界保护区,提取事件后清清除
- HAL_ENTER_CRITICAL_SECTION(intState);
- events = tasksEvents[idx];
- tasksEvents[idx] = 0; // 清除
- HAL_EXIT_CRITICAL_SECTION(intState);
- //然后通过函数指针调用对应的任务处理函数
- activeTaskID = idx;
- events = (tasksArr[idx])( idx, events );
- activeTaskID = TASK_NO_TASK;
- //taskArr[]即为函数指针数组,存放所有定义好的处理任务函数的入口地址
- HAL_ENTER_CRITICAL_SECTION(intState);
- tasksEvents[idx] |= events; // 保存未处理的事件
- HAL_EXIT_CRITICAL_SECTION(intState);
- }
- #if defined( POWER_SAVING )//如果定义了节能模式
- else
- {
- osal_pwrmgr_powerconserve(); //进入睡眠
- }
- #endif
- #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
- {
- osal_task_yield();
- }
- #endif
- }
可见协议栈就是一个被称为OSAL的小型操作系统,基本流程如下:各种初始化---运行操作系统---有任务触发---执行任务
以上只是对协议栈OSAL系统的简单分析,关于蓝牙通信的API 部分后文再续。
联系客服