Z-Stack中OSAL定时器事件触发流程分析

2023-11-22 22:48

本文主要是介绍Z-Stack中OSAL定时器事件触发流程分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面:之所以会注意到定时器事件是因为在做断点调试的时候会进入osal_start_timerEx这个函数,而且这个函数之后还会涉及到hal_uartpoll有关DMA之类的函数,于是发现了这篇文章,写得很详细。

     我们先看一下osal_start_timerEx()函数,是怎么调用到最后的osal_set_event()函数,触发事件处理的。下面是osal_start_timerEx()函数的源代码,从中间我们并没有看到有关osal_set_events()函数的相关信息。当然这个函数中没有直接的调用该函数,那osal_set_events()函数,是怎么和我们的osal_start_timerEx()函数联系起来的呢?我们应该先从系统中的主循环开始查找其中的奥妙。 
byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )
{
halIntState_t intState;
  osalTimerRec_t *newTimer;
 
  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
 
  // Add timer
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
  if ( newTimer )
  {
#ifdef POWER_SAVING
    // Update timer registers
    osal_retune_timers();
    (void)timerActive;
#endif
    // Does the timer need to be started?
    if ( timerActive == FALSE )
    {
      osal_timer_activate( TRUE );
    }
  }
   先在osal_start_system( void )函数开始时调用Hal_ProcessPoll();因为Hal_ProcessPoll()函数是在一个死循环中,所以每过一定的时间就会执行到。在Z-Stack OSAL中这个时种节奏定义是1ms,由8bits HW_TIMER4来控制,这些都可以有程序员进行修改,我们先看一下Hal_ProcessPoll()函数。
void Hal_ProcessPoll ()
{
 
 
  HalTimerTick();
 
 
#if (defined HAL_UART) && (HAL_UART == TRUE)
  HalUARTPoll();
#endif
 
}
   在这是就会有一个疑问是在什么时候溢出呢?我们知道每个系统都会有一个节拍,也就是系统的时钟,在OSAL中也不例外,这个时钟就是由Timer4提供的计时的。
在void InitBoard(byte level)函数中调用下面这个函数,进行了配置
HalTimerConfig (OSAL_TIMER,                     // 8bit timer2
                  HAL_TIMER_MODE_CTC,         // Clear Timer on Compare
                  HAL_TIMER_CHANNEL_SINGLE,    // Channel 1 - default
                  HAL_TIMER_CH_MODE_OUTPUT_COMPARE,   // Output Compare mode
                  OnboardTimerIntEnable,           // Use interrupt
                  Onboard_TimerCallBack);         // Channel Mode
 
      OSAL的Timer定义好之后,就要启动Timer,在网络层初始化函数nwk_init(taskID++)执行完后,Timer启动了,也就是说在网络层的初始化函数中启动了Timer,网络层的代码是不开源的,所以也就无法看到其真正的启动代码。
   每当1ms心跳来临时,Timer4的中断标志置位,这样在OSAL的死循环中,通过一开始的Hal_ProcessPoll()函数检测到这中断标志位,在Hal_ProcessPoll ()函数中调用了  HalTimerTick();函数,这个函数是专门用来检测是否有硬件定时器溢出的。如果定时器有溢出的话,就要调用halProcessTimerX ();(X表示 1 3 4).这里假设是HalProcessTimer4(),在HalProcessTimer4()中,通过下面的一句话,调用了函数
halTimerSendCallBack (HAL_TIMER_2, 
HAL_TIMER_CHANNEL_B,
HAL_TIMER_CH_MODE_OUTPUT_COMPARE);
在halTimerSendCallBack中调用了真正的回调函数,
if (halTimerRecord[hwtimerid].callBackFunc)
    (halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
这个回调函数通过
uint8 HalTimerConfig (uint8 timerId, uint8 opMode, uint8 channel, uint8 channelMode,bool intEnable, halTimerCBack_t cBack)
   也就是前面的那个函数。进行的配置。在InitBoard()函数中调用了函数HalTimerConfig()。
   也就是调用了Onboard_TimerCallBack()函数,在这个函数中调用了osal_update_timers();函数,这个函数又调用了osalTimerUpdate( tmr_decr_time );这个函数中又调用了osal_set_events()函数。
osalTimerUpdate( tmr_decr_time )函数会去轮询Timer事件链表,Timer事件链表是下面这样一个数据结构,next指向下一个Timer事件,timerout值表明本Timer事件还需要timerout个心跳才需要被处理,因为些处的心跳是1ms,所以也就是说还需要timerout个ms才处理。也就是检测timeout是否小于1ms,如果小于1ms,则发出event_flag这个消息到消息队列,这个消息隶属于task_id这个任务,如果不大于1ms,说明该Timer事件还不到处理的时间,则Timeout= Timeout-1,然后继续等待下一次心跳,Timer事件链表的维护是通过osal_start_timerEx()这个函数来实现的。这样就把前面的osalTimerUpdate( tmr_decr_time )函数和我们应用程序中经常调用的osal_start_timerEx()函数联系在了一起,
typedef struct
{
  void *next;
  UINT16 timeout;
  UINT16 event_flag;
  byte task_id;
} osalTimerRec_t;
   如果到达定时器的定时值,也就是说Timeout< 1ms后,就会发送一个event_flag这个消息给消息队列,这样在主循环中就可以检测到这个消息,并且检测到这个消息是属于那个任务的,然后,调用相应的消息处理函数。

这篇关于Z-Stack中OSAL定时器事件触发流程分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/413466

相关文章

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、