tag 标签: osal

相关博文
  • 热度 23
    2015-9-21 16:09
    6586 次阅读|
    5 个评论
    接下来我们再看 main() 函数中另一个跟 OSAL 相关的函数—— osal_start_system() ,也位于 OSAL.c 中。 void osal_start_system( void ) { #if !defined ( ZBIT ) !defined ( UBIT )   for(;;)   // Forever Loop #endif   {     osal_run_system();   } } 一看这是个死循环,相当于单片机程序最后一行 while(1); 。这个函数最主要的部分还是 osal_run_system() ,找到它,也在 OSAL.c 中。 void osal_run_system( void ) {   uint8 idx = 0;   #ifndef HAL_BOARD_CC2538   osalTimeUpdate(); #endif     Hal_ProcessPoll();     do {     if (tasksEvents )   // Task is highest priority that is ready.     {       break;     }   } while (++idx tasksCnt);     if (idx tasksCnt)   {     uint16 events;     halIntState_t intState;       HAL_ENTER_CRITICAL_SECTION(intState);     events = tasksEvents ;     tasksEvents = 0;   // Clear the Events for this task.     HAL_EXIT_CRITICAL_SECTION(intState);       activeTaskID = idx;     events = (tasksArr )( idx, events );     activeTaskID = TASK_NO_TASK;       HAL_ENTER_CRITICAL_SECTION(intState);     tasksEvents |= events;   // Add back unprocessed events to the current task.     HAL_EXIT_CRITICAL_SECTION(intState);   } #if defined( POWER_SAVING )   else   // Complete pass through all task events with no activity?   {     osal_pwrmgr_powerconserve();   // Put the processor/system into sleep   } #endif     /* Yield in case cooperative scheduling is being used. */ #if defined (configUSE_PREEMPTION) (configUSE_PREEMPTION == 0)   {     osal_task_yield();   } #endif } 去掉条件编译部分,最核心的是一个 do-while 循环,一个 if 判断。 do-while 循环: do {     if (tasksEvents )   // Task is highest priority that is ready.     {       break;     }   } while (++idx tasksCnt); 这个循环就是完成判断当前的事件表中有没有事件发生,如果有就跳出来,执行下面的代码。   if (idx tasksCnt)   {     uint16 events;     halIntState_t intState;       HAL_ENTER_CRITICAL_SECTION(intState);     events = tasksEvents ;     tasksEvents = 0;   // Clear the Events for this task.     HAL_EXIT_CRITICAL_SECTION(intState);       activeTaskID = idx;     events = (tasksArr )( idx, events );     activeTaskID = TASK_NO_TASK;       HAL_ENTER_CRITICAL_SECTION(intState);     tasksEvents |= events;   // Add back unprocessed events to the current task.     HAL_EXIT_CRITICAL_SECTION(intState);   } 这部分代码应该是 OSAL 最核心最精髓的部分了。前面的循环中已经确定有事件发生了。 HAL_ENTER_CRITICAL_SECTION(intState); 和 HAL_EXIT_CRITICAL_SECTION(intState); 分别是关中断和使能中断,以防止在执行代码时被中断打断。将事件表 tasksEvents )( idx, events ); 就是去处理事件了,这里的 tasksArr |= events; 就是把没有响应的事件再放回到 tasksEvents ,它被定义在 OSAL_KeyFobDemo.c 中。 // The order in this table must be identical to the task initialization calls below in osalInitTask. const pTaskEventHandlerFn tasksArr 是一个函数指针数组,里面保存了所有事件处理函数的地址。当有事件发生时,就执行 events = (tasksArr )( idx, events ); 一句,就是对应的 tasksArr 。 tasksEvents 中哪个事件非 0 ,即事件被触发了;然后在 if 中把该事件清 0 ,执行 tasksArr 中。这也是为什么在 osalInitTask() 中进行初始化的时候,初始化的顺序要和 tasksArr[] 一致。 以上是我对 OSAL 的理解,因为 C 语言的基本不够瓷实,说得也很大白话。之所以敢这么大胆贴出来,也是请大家多批评指正,让我能得到提高。
  • 热度 21
    2015-9-21 16:09
    13038 次阅读|
    2 个评论
      TI 的蓝牙 4.0BLE 协议栈为 BLE-CC254x-1.4.0 ,即现在的版本是 1.4 版本的。可以从 TI 官方下载或从附件中下载安装,默认是安装在 C 盘中。因为上一篇博文提到进行空中固件升级,当时没有安装在 C 盘下,死活生成不了 bin 文件,改在 C 盘下生成了。所以,我个人建议,还是默认安装吧,也占不了多大空间。 TI 蓝牙 4.0BLE 协议栈的结构如下图所示: 由控制器和主机两部分构成,分层的思想很明晰。 主机包括物理层 PHY 、数据链路层 LL 和主机控制器接口 HCI 构成。物理层 PHY 是 1Mbps 自适应跳频的 GFSK 射频,工作于免许可证的 2.4G 频段。数据链路层 LL 用于控制设备的射频状态,使设备工作于 Standby (准备)、 Advertising (广播)、 Scanning (扫描)、 Initiating (初始化)、 Connected (连接)五种状态中的一种。主机控制器接口 HCI 为主机和控制器之前提供标准的通信接口。 主机包括逻辑链路控制及自适应协议层 L2CAP 、安全管理层 SM 、属性协议层 ATT 、通用访问配置文件层 GAP 、通用属性配置文件层 GATT 构成。逻辑链路控制及自适应协议层 L2CAP 为上层提供数据封装服务,允许逻辑上的点对点通信。安全管理层 SM 配对和密钥分发服务,实现安全连接和数据交换。属性协议层 ATT 允许设备向其他设备展示一块特定的数据,这块数据称之为“属性”。通用属性配置文件层 GATT 定义了使用 ATT 的服务框架和配置文件( profile ), BLE 中所有数据的通信都要通过 GATT 层。通用访问配置文件层 GAP 提供设备通信的接口,负责处理访问模式和程序,包括设备发现、建立连接、终止连接、初始化安全和设备配置等。对于我们来说,直接接触的是 GAP 和 GATT 两个层。 最早接触这个项目的时候,听说 CC2540/2541 是 51 内核的 SOC ,当时我心想,毛毛雨啦, 51 的东东还不简单。等真接手了才发现,头大了, TI 的工程师把协议栈封装和规划得都很好,不能不佩服。 先分析协议栈的流程吧,这里以 TI 的 KeyFobDemo 为例,该工程位于 C:\Texas Instruments\BLE-CC254x-1.4.0\Projects\ble\KeyFob 中。先看下工程的架构。对于我们开发来说, App 和 Profile 两个文件夹中的内容是最主要的。 先从 main() 函数入手,打开 App 文件夹下的 KeyFob_Main.c ,找到 main() 函数: int main(void) {   /* Initialize hardware */   HAL_BOARD_INIT();// 初始化硬件     // Initialize board I/O   InitBoard( OB_COLD );// 初始化板卡 IO     /* Initialze the HAL driver */   HalDriverInit();// 初始化 HAL 层驱动     /* Initialize NV system */   osal_snv_init();// 初始化 Flash     /* Initialize LL */     /* Initialize the operating system */   osal_init_system();// 初始化 OSAL     /* 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 // 启动 OSAL     return 0; } //////////////// 上述代码,我加入了简单的中文注释,会发现有个很重要的东西—— OSAL , Operation System Abstraction Layer ,操作系统抽象层。 OSAL 还不是操作系统,但是实现了 OS 的很多功能。从前面的代码中我们可以看到,跟 OSAL 相关的有两个函数 osal_init_system() 和 osal_start_system() ( osal_pwrmgr_device() 暂时先不去理会)。我们依次来看看。 在 IAR 环境中,可以在代码中 osal_init_system() 上单击鼠标右键,打开“ Go to definition of osal_init_system ”, osal_init_system() 在 OSAL.c 中,下面就是该函数的代码: uint8 osal_init_system( void ) {   // Initialize the Memory Allocation System   osal_mem_init();// 初始化内存分配系统     // Initialize the message queue   osal_qHead = NULL;// 初始化消息队列     // Initialize the timers   osalTimerInit();// 初始化定时器     // Initialize the Power Management System   osal_pwrmgr_init();// 初始化电源管理系统     // Initialize the system tasks.   osalInitTasks();// 初始化系统任务     // Setup efficient search for the first free block of heap.   osal_mem_kick();     return ( SUCCESS ); } 该函数是完成一系列的初始化,跟操作系统有关的,仿佛是 osalInitTasks() ,我们进到这个函数里面。 osalInitTasks() 在 OSAL_KeyfobDemo.c 中。 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 */   GAPRole_Init( taskID++ );   GAPBondMgr_Init( taskID++ );     GATTServApp_Init( taskID++ );     /* Application */   KeyFobApp_Init( taskID ); } 从每行代码,可以看到整个事件初始化的过程也是分层的。从链路层任务初始化( LL_Init )到硬件抽象层( Hal_Init )、主机控制器接口( HCI_Init )、逻辑链路控制及自适应协议层( L2CAP_Init )、 GAP 层( GAP_Init )、 GATT 层( GATT_Init )、安全管理层( SM_Init )。然后完成 GAP 层的配制( GAPRole_Init )、蓝牙绑定的管理初始化( GAPBondMgr_Init )及 GATT 层服务的初始化( GATTServApp_Init )。最后完成的是应用层的初始化( KeyFobApp_Init )。程序是一行一行地执行,各层的任务也是依次的完成初始化。