搜档网
当前位置:搜档网 › 协议栈工作原理介绍

协议栈工作原理介绍

协议栈工作原理介绍

CC2540集成了增强型的8051内核,TI为BLE协议栈搭建了一个简单的操作系统,即一种任务轮询机制。帮你做好了底层和蓝牙协议深层的内容,将复杂部分屏蔽掉。让用户通过API函数就可以轻易用蓝牙4.0,是开发起来更加方便,开发周期也可以相应缩短。

1.1.1工程文件介绍

安装完BLE协议栈之后,会在安装目录下看到以下文件结构:

图 3.2BLE栈目录

可看到Projects文件夹里面有很多工程,我们主要介绍SimpleBLECentral和SimpleBLEPeripheral。

ble文件夹中有很多工程文件,有些是具体的应用,例如

BloodPressure、GlucoseCollector、GlucoseSensor、HeartRate、HIDEmuKbd等都为传感器的实际应用,有相应标准的Profile(即通用的协议)。

其中还有4中角色:SimpleBLEBroadcaster、SimpleBLECentral、SimpleBLEObserver、SimpleBLEPeripheral。

他们都有自己的特点。

?Broadcaster广播员——非连接性的信号装置

?Observer观察者——扫描得到,但不能链接

?Peripheral从机——可链接,在单个链路层链接中作为从机?Central主机——扫描设备并发起链接,在单链路层或多链路层

中作为主机。

最后的BTool文件夹为BLE设备PC端的使用工具。

1.1.2OSAL介绍

协议栈是一个小操作系统。大家不要听到是操作系统就感觉到很复杂。回想

我们当初学习51单片机时候是不是会用到定时器的功能?嗯,我们会利用定时器计时,令LED一秒改变一次状态。好,现在进一步,我们利用同一个定时器计时,令LED1一秒闪烁一次,LED2二秒闪烁一次。这样就有2个任务了。再进一步…有n个LED,就有n个任务执行了。协议栈的最终工作原理也一样。从它工作开始,定时器周而复始地计时,有发送、接收…等任务要执行时就执行。这个方式称为任务轮询。

图 3.3任务轮询

现在我们直接打开协议栈,直接拿他们的东西来解剖!我们打开协议栈文件夹Texas Instruments\BLE-CC254x-1.2.1\Projects

\ble\SimpleBLEPeripheral\CC2540DB里面的工程文件SampleApp.eww。

图 3.4工程文件

打开后在IAR左边可看到左边的工程目录,我们暂时只需要关注App文件夹。

如图 3.5所示:

图 3.5工作空间目录

任何程序都在main函数开始运行,BLE也不例外。打开SimpleBLEPeripheral_Main.c文件,找到int main(void)函数。我们大概浏览一下main函数代码:

图 3.6协议栈主函数

1./**************************************************************

2.*@fn main

3.*@brief Start of application.

4.*@param none

5.*@return none

6.**************************************************************/

7.int main(void)

8.{

9./*Initialize hardware*/

10.HAL_BOARD_INIT();//初始化系统时钟

11.

12.//Initialize board I/O

13.InitBoard(OB_COLD);//初始化I/O,LED、Timer等

14.

15./*Initialze the HAL driver*/

16.HalDriverInit();//初始化芯片各硬件模块

17.

18./*Initialize NV system*/

19.osal_snv_init();//初始化Flash存储器

20.

21./*Initialize LL*/

22.

23./*Initialize the operating system*/

24.osal_init_system();//初始化操作系统

25.

26./*Enable interrupts*/

27.HAL_ENABLE_INTERRUPTS();//使能全部中断

28.//Final board initialization

29.InitBoard(OB_READY);//初始化按键

30.

31.#if defined(POWER_SAVING)

32.osal_pwrmgr_device(PWRMGR_BATTERY);//开启低功耗

33.#endif

34.

35./*Start OSAL*/

36.osal_start_system();

37.//No Return from here执行操作系统,进去后不会返回

38.

39.return0;

40.}

我们大概看了上面的代码后,可能感觉很多函数不认识。没关系,代码很有条理性,开始先执行初始化工作。包括硬件、GATT、GAP层、任务等的初始化。然后执行osal_start_system();操作系统。进去后可不会回来了。在这里,我

们重点了解2个函数:

初始化操作系统

osal_init_system();

运行操作系统

osal_start_system();

***怎么看?在函数名上单击右键——go to definition of…,便可以进入函数。***

1、我们先来看osal_init_system();系统初始化函数,进入函数。发现里面有

6个初始化函数,没事,我们需要做的是掐住咽喉。这里我们只关心

osalInitTasks();任务初始化函数。继续由该函数进入。

图 3.7osal_init_system()

终于到尽头了。这一下子代码更不熟悉了。不过我们可以发现,函数好像

能在taskID这个变量上找到一定的规律。请看下面程序注释。

图 3.8osalInitTasks()

1.void osalInitTasks(void)

2.{

3.uint8taskID=0;

4.//分配内存,返回指向缓冲区的指针

5.tasksEvents=(uint16*)osal_mem_alloc(sizeof(uint16)*

tasksCnt);

6.//设置所分配的内存空间单元值为0

7.osal_memset(tasksEvents,0,(sizeof(uint16)*tasksCnt));

8.

9.//任务优先级由高向低依次排列,高优先级对应taskID的值反而小

10./*LL Task*/

11.LL_Init(taskID++);

12.

13./*Hal Task*/

14.Hal_Init(taskID++);

15.

16./*HCI Task*/

17.HCI_Init(taskID++);

18.

19.#if defined(OSAL_CBTIMER_NUM_TASKS)

20./*Callback Timer Tasks*/

21.osal_CbTimerInit(taskID);

22.taskID+=OSAL_CBTIMER_NUM_TASKS;

23.#endif

24.

25./*L2CAP Task*/

26.L2CAP_Init(taskID++);

27.

28./*GAP Task*/

29.GAP_Init(taskID++);

30.

31./*GATT Task*/

32.GATT_Init(taskID++);

33.

34./*SM Task*/

35.SM_Init(taskID++);

36.

37./*Profiles*/

38.GAPRole_Init(taskID++);

39.GAPBondMgr_Init(taskID++);

40.

41.GATTServApp_Init(taskID++);

42.

43./*Application*/

44.SimpleBLEPeripheral_Init(taskID);//应用初始化,重点

45.}

第9-41行:BLE中各层的任务添加,越底层优先级越高

我们可以这样理解,函数对taskID个东西进行初始化,每初始化一个,taskID++。TI公司出品协议栈已完成的东西。这里先提前卖个关子SampleApp_Init(luste);很重要,也是我们应用协议栈例程的必需要函数,用户通常在这里初始化自己的东西。

至此,osal_init_system();大概了解完毕。

2、我们再来看第二个函数osal_start_system();运行操作系统。同样用go to

definition的方法进入该函数。再进入osal_run_system()

图 3.9osal_start_system()函数

图 3.10void osal_run_system(void)函数

1./****************************************************************

2.*@fn osal_run_system

3.*

4.*@brief

5.*

6.*This function will make one pass through the OSAL taskEvents

table

7.*and call the task_event_processor()function for the first task

that

8.*is found with at least one event pending.If there are no pending

9.*events(all tasks),this function puts the processor into Sleep.

10.*

11.*@param void

12.*

13.*@return none

14.*/

15.翻译:这个是任务系统轮询的主要函数。他会查找发生的事件然后调用相应

的事件执行函数。如果没有事件登记要发生,那么就进入睡眠模式。这个函数是永远不会返回的。

16.

17.void osal_run_system(void)

18.{

19.uint8idx=0;

20.

21.#ifndef HAL_BOARD_CC2538

22.//这里是在扫描哪个事件被触发了,然后置相应的标志位

23.osalTimeUpdate();

24.#endif

25.

26.Hal_ProcessPoll();

27.

28.do{

29.if(tasksEvents[idx])//Task is highest priority that is ready.

30.{

31.break;//得到待处理的最高优先级任务索引号idx

32.}

33.}while(++idx

34.

35.if(idx

36.{

37.uint16events;

38.halIntState_t intState;

39.

40.HAL_ENTER_CRITICAL_SECTION(intState);//进入临界区,保护

41.events=tasksEvents[idx];//提取需要处理的任务中的事件

42.tasksEvents[idx]=0;//清除本次任务的事件

43.HAL_EXIT_CRITICAL_SECTION(intState);//退出临界区

44.

45.activeTaskID=idx;

46.events=(tasksArr[idx])(idx,events);//通过指针调用任务处理

函数,关键

47.activeTaskID=TASK_NO_TASK;

48.

49.HAL_ENTER_CRITICAL_SECTION(intState);//进入临界区

50.tasksEvents[idx]|=events;//Add back unprocessed events to

the current task.保存未处理的事件

51.HAL_EXIT_CRITICAL_SECTION(intState);//退出临界区

52.}

53.#if defined(POWER_SAVING)

54.else//Complete pass through all task events with no activity?

55.{

56.osal_pwrmgr_powerconserve();//Put the processor/system into

sleep

57.}

58.#endif

59.

60./*Yield in case cooperative scheduling is being used.*/

61.#if defined(configUSE_PREEMPTION)&&(configUSE_PREEMPTION==0)

62.{

63.osal_task_yield();

64.}

65.#endif

66.}

我们来关注一下events=tasksEvents[idx];进入tasksEvents[idx]数组定义,如下图,发现恰好在刚刚osalInitTasks(void)函数上面。而且taskID一一对应。这就是初始化与调用的关系。taskID把任务联系起来了

图 3.11tasksEvents[idx]

关于协议栈的介绍先到这里,其他会在以后的实例中结合程序来介绍,这样会更直观。大家可以根据需要再熟悉一下函数里面的内容。游一下这个代码的海洋。我们可以总结出一个协议栈简单的工作流程,如图 3.12所示。

图 3.12BLE栈的工作流程

相关主题