zoukankan      html  css  js  c++  java
  • 如何快速理解一个全新的嵌入式操作系统(续)(转载)

    ---基于TI CC254X OSAL的分析

    当工具链配置完成后,SourceInsight向你展示一份源码工程,不借助百度和开发文档,能否在一两个小时内理解源码的组成框架和接口,进行快速开发?

    上一篇《如何快速理解一个全新的嵌入式操作系统》我们已经分析了如何快速理解OSAL的任务调度和任务间通信(其实OSAL只是酷似多任务操作系统的单任务系统),再理解好OASL的消息产生和处理过程,我们就能够进行快速开发了。

    一、消息的来源

    嵌入式系统的消息包括两种,一是系统消息,包括低电、热插拔等,由系统进程去处理;二是用户消息,包括Timer、按键、串口、绘图等消息,由各应用进程进行处理。对于TI CC254x的OSAL,我们理解好Timer、key、UART就已足够。

    二、HAL

    OSAL向用户提供HAL硬件抽象层,对CC254x的所支持的硬件模块进行了封装抽象,如timer、key、UART、LED、LCD、flash、ADC等等,并向用户提供硬件模块的操作接口。

    CC254x是低功耗蓝牙集成芯片,用户的产品和电路设计一般都会参考官方的典型电路,而OSAL为官方针对典型电路所设计的系统库和接口,用户的代码编程就只需要按照其提供的HAL接口进行调用就可以实现功能,而不需要通过GPIO级别的驱动编程来实现模块的功能。

    针对CC254x的编程是应用编程,关注的是HAL接口,可以认为是基于硬件功能的API接口,而且电路的外设的功能也相对固定,如LED、LCD、UART所使用的pin脚都是相对固定的,因此调用简单的HAL层接口即可实现功能;而驱动编程则是针对SOC片上资源来进行开发,需要根据SOC的datasheet明确的物理地址资源进行访问和控制,并向用户提供API接口。从两者的区别可以理解HAL硬件抽象层的含义。当然,透传理解SOC datasheet也有助于HAL接口编程。

    三、Timer

    对于Timer定时器接口,一般是设置定时器、编写定时器时间到达时的回调函数。而定时器模块的初始化函数一般由系统初始化完成。

    OSAL对于Timer的HAL层代码对用户并不透明,我们可以理解Timer的HAL层是设置Timer模块的硬件相关操作,并且实现了Timer中断时的服务处理过程。OSAL的Timer的封装接口实际上是在HAL层的基础进行再次封装。其主要提供的接口如下:

    uint8osal_start_timerEx( uint8 taskID, uint16 event_id, uint32 timeout_value )

    taskID标识哪个目标任务来处理这个定时到达消息,即当定时完成时,定时器中断服务器函数会往这个目标任务的taskEvents[taskID]写入event_id这个消息;event_id可以由用户自定义;timeout_value是定时时间,1毫秒为单位。

    可见这个定时接口并没有设置定时完成时的回调函数,而是在定时完成时向这个目标任务发送一个事件。而在目标任务的执行过程中要检测这个事件并执行相应的处理。

    四、UART

           UARTHAL层代码对用户是透明的,对于用户编程来说,最重要的就是串口的初始化(波特率)、串口输入、串口输出。

    1.     串口初始化

    voidNPI_InitTransport( npiCBack_t npiCBack )

    串口的初始化并没有带taskId这个参数,可见其是一个全局的系统级的接口。串口的使用一般是使用中断串口输入,非中断直接串口输出。该函数里面设置波特率是115200.

    npiCBack是串口HAL提供给用户的一个回调函数,即在串口中断时会调用该回调函数。而串口中断有以下几种事件:

    一般我们都会在该回调函数中实现串口接收,如实现串口透传模式。回调接口声明如下:

    typedefvoid (*npiCBack_t) ( uint8 port, uint8 event )

           port是UART0或者UART1,而event即是串口中断事件。

    2.     串口输入

    uint16NPI_ReadTransport( uint8 *buf, uint16 len )

    3.     串口输出

    uint16NPI_WriteTransport( uint8 *buf, uint16 len )

    从这些接口来看其前缀是NPI,真实的意义是Network Processor Interface (NPI),表示所谓的网络传输层。其实只是更高一层的数据输入输出罢了。NPI的底层可以是UART、SPI或者USB等等。我们这里默认是使用UART。

    五、按键消息来源和处理

    1. 代码理解前的思考

    1)按键消息按理是跟应用相关的,因此其必然是跟某个taskId绑定。在这种简单的嵌入式系统中,一般是由一个称为UI的任务来统一处理按键的消息。

    2)按照上一篇文章和上一节Timer的分析,OSAL的设计是将事件event_id发往目标task,即设置taskEvents[tasked]。我们可以想象在按键中断(或者按键轮询)时检测到按键会往目标task发一个按键事件。但是,我们再细想,发一个KEY事件够了吗?很明显taskEvents的元素才是16bit,每个bit表示一个事件,最多只能代表16种事件,就算这16事件都用来表示不同的按键,也显得不够。因为系统可能有更多的按键啊,如果这样设计扩展性就太差了。事实上,它只是发了一个KEY_CHANGE事件,而键值是以MSG消息的形式发到系统的消息队列,而该消息也会带上目标taskId的标识。

    3)以上两点是OSAL的KEY处理机制。对于用户快速开发,则需要知晓如何增加一个按键,或者改变一个按键对应的GPIO;处理按键的过程在哪里实现?

    带着以上问题,我们从头到尾跟踪一次KEY处理的过程。OSAL对KEY的处理机制有点绕,但封装得挺有意思的。

    对Key处理机制真正的理解过程应该是倒序的,即从按键的处理一步一步往前推,在现场教学时,对着代码反跟踪能够更加体现本文的方法论。为了表述更加有条理性,这里就从头到尾正序阐述。

    2. 初始化

           1)main->HalDriverInit->HalKeyInit

     

    2)main->InitBoard( OB_READY )

    OnboardKeyIntEnable= HAL_KEY_INTERRUPT_ENABLE;

    HalKeyConfig(OnboardKeyIntEnable, OnBoard_KeyCallback);

    相关的代码在hal_keys.c和hal_keys.h,若要增加按键或者修改按键设置即修改这里。

    OnBoard_KeyCallback是按键中断的回调函数。我们在下一步再展开其实现过程,现在跟踪在哪里会调用这个回调。我们从中断的源头开始跟踪。

    3. 中断的执行过程

     

    4.     HAL层任务的处理过程

     

    pHalKeyProcessFunction即是之前在HalKeyConfig接口中设置的OnBoard_KeyCallback,继续跟踪这个函数的实现:

    这个 registeredKeysTaskID是什么,就是处理按键消息的任务Id。在哪里被初始化呢?

    5.     按键处理任务的初始化

    main-> osal_init_system-> osalInitTasks-> SimpleBLEPeripheral_Init

    -> RegisterForKeys( simpleBLEPeripheral_TaskID )

    即在这个函数里面将simpleBLEPeripheral_TaskID赋值给registeredKeysTaskID,即SimpleBLEPeripheral对应的任务来处理这个消息。

    6.     按键的处理

     

    用户添加的按键处理即在simpleBLEPeripheral_HandleKeys函数中。

    请一步步地印证第一点,代码理解前的思考。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      转载自:https://blog.csdn.net/yueqian_scut/article/details/48882465                                                                                                                                                                              

  • 相关阅读:
    点击子窗体给父窗体上的对象赋值
    框架使用及规范参考
    像Google日历一样的日程管理
    TreeView 和 Menu 的用法
    甘特图-svg版 支持客户端事件
    js获取DropDownList的选择项
    GridView,Repeater分页控件:WebPager(开源)
    TextBox 禁止客户端输入 前台通过JS赋值 并在后台获取
    对象实体 参考标准
    以编程方式控制ScriptManager
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/10630415.html
Copyright © 2011-2022 走看看