OpenVela之 Arch Timer 驱动框架使用指南

一、概述

在嵌入式系统开发中,定时器是实现任务调度、精确延时等功能的核心组件。Arch Timer 作为基于 Timer Driver 实现的间隔定时器,在系统调度中扮演着重要角色。本文将全面介绍 Arch Timer 驱动框架,从基本概念到实际应用,帮助开发者快速掌握其使用与开发技巧。

二、认识 Arch Timer

1. 什么是 Arch Timer

Arch Timer 是基于 Timer Driver 实现的间隔定时器,为操作系统的 sched 模块提供了丰富的 timer 接口。它支持两种工作模式,以满足不同场景的需求:

  • Tickless 模式:允许更灵活高效的系统调度,无周期性时钟中断,系统在无任务执行时进入空闲模式,有效降低功耗。
  • Tick 模式:提供固定时间间隔的调度机制,按照配置的固定周期运行,保证周期性任务的稳定执行。

Arch timer 在系统中的位置框架如下图所示:
在这里插入图片描述

2. Arch Timer 的驱动框架

Arch Timer 的驱动框架分为 upper - half 和 lower - half 两部分:

  • upper - half 部分:由 openvela 提供,其中 up_timer_initialize 接口需由芯片厂商实现。
  • lower - half 部分:需芯片厂商进行适配,实现硬件级别的控制。

应用程序可通过标准的 POSIX API 接口或 ioctl 接口,调用这两部分的接口来完成相应功能。
在这里插入图片描述

三、Arch Timer 接口详解

sched 模块依赖于 arch 模块提供的定时器接口,这些接口定义在 /include/nuttx/arch.h 头文件中。在 Tickless 模式下,接口按时间单位分为基于微秒(us)和基于计时单元(tick)的两组,开发者可通过配置选项 CONFIG_SCHED_TICKLESS_TICK_ARGUMENT 选择启用哪一组。默认支持 tick 接口以确保运行效率,部分主要接口如下:

Arch Timer 接口说明

接口名称功能描述
up_timer_set_lowerhalf初始化 Arch Timer 定时器,设置一个 timer_lowerhalf_s 实例,并启动定时器
up_timer_tick_start启动定时器,仅在 Tickless 模式下使用,参数为超时时间(单位:tick)
up_timer_tick_cancel停止 Arch Timer 定时器,仅在 Tickless 模式中使用,返回当前剩余 tick 数
up_timer_getmask获取定时器支持的时间掩码(mask)的值
up_timer_gettick获取定时器当前已经经过的 tick 数值
up_udelay实现以微秒(us)为单位的延时操作
up_mdelay实现以毫秒(ms)为单位的延时操作

四、Timer Driver 深入了解

1. 配置说明

启用和调整 Timer Driver 功能需配置三个关键选项:

CONFIG_TIMER:启用 Timer Driver 功能。
CONFIG_TIMER_ARCH:启用 arch timer 模块。
CONFIG_SCHED_TICKLESS:启用 Tickless 模式。

相关配置文件路径如下:

sched/Kconfig:包含 SCHED_TICKLESS 等相关配置。

# sched/Kconfig
config SCHED_TICKLESSdepends on ARCH_HAVE_TICKLESSconfig SCHED_TICKLESS_TICK_ARGUMENT
config SCHED_TICKLESS_LIMIT_MAX_SLEEP

drivers/timers/Kconfig:包含 TIMER 和 TIMER_ARCH 等配置。

# drivers/timers/Kconfig
config TIMER
......
if TIMER
config TIMER_ARCHselect ARCH_HAVE_TICKLESSselect ARCH_HAVE_TIMEKEEPINGselect SCHED_TICKLESS_LIMIT_MAX_SLEEP  if SCHED_TICKLESSselect SCHED_TICKLESS_TICK_ARGUMENT  if SCHED_TICKLESS
#endif

可通过以下命令检查配置是否正确:

grep -rE "CONFIG_TIMER|CONFIG_TIMER_ARCH|CONFIG_ARCH_HAVE_TICKLESS|CONFIG_ARCH_HAVE_TIMEKEEPING|CONFIG_SCHED_TICKLESS_TICK_ARGUMENT|CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP" nuttx/.config

2. 初始化

在 board 初始化过程中,需调用具体厂商实现的 ***_timer_initialize 函数,完成分配并初始化 struct timer_lowerhalf_s 结构实例、注册 Timer 驱动等操作,注册后会生成 /dev/timer 设备节点,并绑定相关结构实例。

/***************************************************************************** Name: timer_register** Description:*   This function binds an instance of a "lower half" timer driver with the*   "upper half" timer device and registers that device so that can be used*   by application code.**   When this function is called, the "lower half" driver should be in the*   disabled state (as if the stop() method had already been called).**   NOTE:  Normally, this function would not be called by application code.*   Rather it is called indirectly through the architecture-specific*   initialization.** Input Parameters:*   dev path - The full path to the driver to be registered in the NuttX*     pseudo-filesystem.  The recommended convention is to name all timer*     drivers as "/dev/timer0", "/dev/timer1", etc.  where the driver*     path differs only in the "minor" number at the end of the device name.*   lower - A pointer to an instance of lower half timer driver.  This*     instance is bound to the timer driver and must persists as long as*     the driver persists.** Returned Value:*   On success, a non-NULL handle is returned to the caller.  In the event*   of any failure, a NULL value is returned.*****************************************************************************/FAR void *timer_register(FAR const char *path,FAR struct timer_lowerhalf_s *lower);

3. 上下层接口

  • upper - half 接口:主要供 sched 调用,根据配置可选择以 struct timespec 或 tick 为单位的接口,减少时间转换工作。

  • lower - half 接口:通过 struct timer_ops_s 提供标准化接口,供 upper - half、ioctl 系统调用等使用,按时间单位分为两组,开发者可根据需求选择实现,未实现的接口有默认实现。

struct timer_ops_s
{/* Required methods *******************************************************/CODE int (*start)(FAR struct timer_lowerhalf_s *lower);CODE int (*stop)(FAR struct timer_lowerhalf_s *lower);CODE int (*getstatus)(FAR struct timer_lowerhalf_s *lower,FAR struct timer_status_s *status);CODE int (*settimeout)(FAR struct timer_lowerhalf_s *lower,uint32_t timeout);CODE void (*setcallback)(FAR struct timer_lowerhalf_s *lower,CODE tccb_t callback, FAR void *arg);CODE int (*maxtimeout)(FAR struct timer_lowerhalf_s *lower,FAR uint32_t *maxtimeout);CODE int (*ioctl)(FAR struct timer_lowerhalf_s *lower, int cmd,unsigned long arg);CODE int (*tick_getstatus)(FAR struct timer_lowerhalf_s *lower,FAR struct timer_status_s *status);CODE int (*tick_setttimeout)(FAR struct timer_lowerhalf_s *lower,uint32_t timeout);CODE int (*tick_maxtimeout)(FAR struct timer_lowerhalf_s *lower,FAR uint32_t *maxtimeout);
};

五、调用流程解析

  1. Tickless 模式
  • 模式概述:sched 动态管理软件定时器,选择最短时长的定时器作为下一次超时时间,动态调用启动或停止函数。
  • 调用流程:初始化定时器后,sched 计算超时时间,配置并启动定时器,超时后触发回调函数通知 sched,随后重新分配时长并启动下一个定时器或任务。

以下为 Tickless 模式下的调用流程图

在这里插入图片描述

  1. Tick 模式
  • 模式概述:sched 启用固定时间间隔的周期性定时器,间隔由 CONFIG_USEC_PER_TICK 配置,系统初始化时启动,无需频繁调用启动和停止接口。
  • 流程描述:初始化时启动周期性定时器,按固定周期触发事件,触发调度器调度,保证周期性任务执行。

六、驱动适配实例

以 nrf52(基于 ARMv7 - M 架构)为例,驱动适配主要包括两部分:

1. 实现 up_timer_initialize 接口

在平台特定代码中实现该接口,调用 timer_register 函数注册定时器驱动,生成设备节点。初始化调用流程如下:

nx_start
-> clock_initialize-> up_timer_initialize      #开发者实现-> systick_initialize    #开发者实现-> timer_register-> up_timer_set_lowerhalf

以下为 systick_initialize 的实现参考:

struct timer_lowerhalf_s *systick_initialize(bool coreclk,unsigned int freq, int minor)
{struct systick_lowerhalf_s *lower =(struct systick_lowerhalf_s *)&g_systick_lower;.../* Register the timer driver if need */if (minor >= 0){char devname[32];sprintf(devname, "/dev/timer%d", minor);timer_register(devname, (struct timer_lowerhalf_s *)lower);}return (struct timer_lowerhalf_s *)lower;
}

2. 实现 lower - half 接口

通过定义 struct timer_ops_s 结构的实例,实现其中的方法,如 startstop 等,以控制硬件运行。

在 ARMv7-M 的 Arch Timer 适配中,lower-half 方法的出现形式如下:

文件路径: arch/arm/src/armv7-m/arm_systick.c

/* "Lower half" driver methods */
static const struct timer_ops_s g_systick_ops =
{.start       = systick_start,.stop        = systick_stop,.getstatus   = systick_getstatus,.settimeout  = systick_settimeout,.setcallback = systick_setcallback,.maxtimeout  = systick_maxtimeout,
};

七、POSIX API 与测试实例

1. POSIX API

包括 timer_createtimer_deletetimer_settime 等接口,用于创建、删除、配置定时器等操作。

  1. timer_create
/*
* 函数:timer_create
* 参数:clockid,定时类型;evp,sigevent结构体,用来指定定时器到期时如何相应
*       timerid,返回一个timerid
* 返回:0 success | -1 error
* 说明:创建一个定时器
*/
int timer_create(clockid_t clockid, FAR struct sigevent *evp,FAR timer_t *timerid);
  1. timer_delete
/*
* 函数:timer_delete
* 参数:timerid,执行timer_create返回的timerid
* 返回:0 success | -1 error
* 说明:删除一个定时器
*/
int timer_delete(timer_t timerid);
  1. timer_settime
/* 设置定时器
* 函数:timer_settime
* 参数:timerid:id
*      flags:相对时间/绝对时间
*      value:定时时间和间隔
*      ovalue:若不为NULL,则返回上次定时的剩余到期时间 
* 返回:0 success | -1 error
* 说明:设置定时
*/
int timer_settime(timer_t timerid, int flags,FAR const struct itimerspec *value,FAR struct itimerspec *ovalue);

2. IOCTL 接口

应用级别的程序可以通过 ioctl 函数直接操作定时器(前提是在 bringup 过程中已注册 /dev/timer 设备节点)。

支持的 IOCTL 命令

IOCTL 命令功能描述参数类型参数说明
TCIOC_START启动定时器
TCIOC_STOP停止定时器
TCIOC_GETSTATUS获取当前定时器的状态struct timer_status_s*用于存储定时器状态信息的结构体指针
TCIOC_SETTIMEOUT设置定时器间隔时间(单位:微秒)32位无符号整数定时器的间隔时间值
TCIOC_NOTIFICATION设置定时器超时消息struct timer_notify_s*包含超时通知配置的结构体指针
TCIOC_MAXTIMEOUT获取定时器支持的最大时延(单位:微秒)uint32_t*用于存储最大时延值的指针

3. 测试实例

  1. TIMER API 测试:通过 cmocka 测试框架验证 POSIX API 的工作,包括创建、配置、以及删除定时器的全过程。

此部分介绍如何测试定时器相关功能,通过 cmocka 测试框架(可参考文档:OpenVela之开发自测试框架cmocka进行cmocka相关配置)验证 POSIX API 的工作,包括创建、配置、以及删除定时器的全过程。

  • 代码位置:apps/testing/drivertest/drivertest_posix_timer.c
  • 测试框架:cmocka
  • 依赖配置:
    • TESTING_CMOCKA
    • TESTING_DRIVER_TEST
    • CONFIG_SIG_EVTHREAD

在这里插入图片描述

在这里插入图片描述

  • 运行步骤:
  1. 启用上述配置,并构建固件。
  2. 在 NuttShell(NSH)中运行以下命令:
nsh> cmocka_posix_timer

在这里插入图片描述

  1. IOCTL 测试:通过 IOCTL 命令控制定时器设备,测试启动、停止、设置间隔等功能。
  • 代码路径:apps/testing/drivertest/drivertest_timer.c
  • 测试框架:cmocka
  • 依赖配置:
    • TESTING_CMOCKA
    • TESTING_DRIVER_TEST

在这里插入图片描述

在这里插入图片描述

  • 测试步骤:
  1. 启用依赖配置,并构建功能完整的固件。
  2. 在 NuttShell(NSH)中运行以下命令:
nsh> cmocka_driver_timer

在这里插入图片描述

总结

Arch Timer 驱动框架为嵌入式系统提供了灵活高效的定时器解决方案,支持两种工作模式,满足不同调度需求。通过本文的介绍,相信开发者对其原理、接口、配置和应用有了全面的了解,能够根据实际需求进行开发和适配,充分发挥其在系统调度中的作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/89271.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/89271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AAC编解码

AAC(Advanced Audio Coding,高级音频编码)是一种基于心理声学原理的有损音频编解码技术,广泛应用于流媒体、数字广播、移动音频等场景。其编解码流程围绕 “保留人耳可感知信息、去除冗余” 设计,分为编码(…

STM32 | HC-SR04 超声波传感器测距

模块:HC-SR04感应角度:不大于15度 探测距离:2cm-450cm 高精度:可达0.3cmTrig:触发信号,接收MCU发送的控制脉冲,MCU对应GPIO 设置为输出Echo:反馈信号,向MCU发送数据…

【RTSP从零实践】12、TCP传输H264格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

【unitrix】 6.1 类型化整数特征(t_int.rs)

一、源码 这段代码定义了一个 Rust 特征(trait)TInt 和一些实现,用于表示类型化的整数。 use crate::number::{Null, B, Bit, TNumber};/// 类型化整数标记特征 /// /// 要求: /// - 实现 TNumber /// - 可复制 (Copy) /// - 默认…

速通LVS

一、LVS的使用lvs部署命令介绍lvs软件相关信息:程序包:ipvsadm Unit File: ipvsadm.service 主程序:/usr/sbin/ipvsadm 规则保存工具:/usr/sbin/ipvsadm-save 规则重载工具:/usr/sbin/ipvsadm-restore 配置文件&#x…

Nginx,MD5和Knife4j

一、 Nginx: 项目网关与流量调度核心原理反向代理 (Reverse Proxy):在Web架构中,Nginx作为系统的统一入口(API网关),接收所有外部客户端请求。它通过解析请求的URL路径(location指令),判断请求的…

多态,内部类(匿名内部类),常用API(1)

多态 什么是多态? 同一个对象在不同时刻表现出来的不同形态(多种形态) 例:Cat extends Animal 第一种形态:Cat c1 new Cat(); //c1是只猫 第二种形态:Animal c2 new Cat(); //c2是个动物 &#xff08…

Qt小组件 - 7 SQL Thread Qt访问数据库ORM

简介网上关于Qt访问数据库的资料大多使用QSqlDatabase模块。虽然这在C中尚可接受,但在Python中使用就显得过于繁琐了——不仅要手动编写SQL语句,还与Python追求简洁的理念背道而驰。在这里写一个基于sqlalchemy的示例,也可以使用其他的ORM库 …

使用Gin框架构建高并发教练预约微服务:架构设计与实战解析

项目概述 技术栈 Web框架:Gin(高性能HTTP框架)数据存储:Redis(内存数据库,用于高并发读写) 项目结构 coach-booking-service ├── main.go # 程序入口,路由初始化&am…

深入拆解Spring第二大核心思想:AOP

什么是AOP Aspect Oriented Programming(面向切面编程) 什么是面向切面编程呢? 切⾯就是指某⼀类特定问题, 所以AOP也可以理解为面向特定方法编程. 什么是面向特定方法编程呢? 比如对于"登录校验", 就是⼀类特定问题. 登录校验拦截器, 就是…

linux服务器stress-ng的使用

安装方法 • Ubuntu/Debian:sudo apt update && sudo apt install stress-ng -y• CentOS/RHEL(需EPEL源):sudo yum install epel-release -ysudo yum install stress-ng -y• 源码编译(适合定制化需求&#x…

探索阿里云DMS:解锁高效数据管理新姿势

一、阿里云 DMS 是什么 阿里云 DMS,全称为 Data Management Service,即数据管理服务 ,是一种集数据管理、结构管理、安全管理于一体的全面数据库服务平台。它能够有效地支持各类数据库产品,包括但不限于 MySQL、SQL Server、Post…

python爬取新浪财经网站上行业板块股票信息的代码

在这个多行业持续高速发展的时代,科技正在改变着我们的生活。 在世界科技领域中,中国正占据越来越重要的位置。当下,每个行业都提到了区块链、人工智能、大数据、5G等科技力量,强调了科技在行业咨询与数据分析领域的重要意义。 随…

【JAVA】监听windows中鼠标侧面键的按钮按下事件

监听windows中鼠标侧面键的按钮按下事件用到的包核心类使用这个类用到的包 jna-5.11.0.jar jna-platform-5.11.0.jar核心类 package sample.tt.mouse;import com.sun.jna.Pointer; import com.sun.jna.platform.win32.*; import com.sun.jna.platform.win32.WinDef.HMODULE; …

Redis突发写入阻断?解析“MISCONF Redis is configured to save RDB…“故障处理

当你的Redis服务器突然拒绝写入并抛出 MISCONF Redis is configured to save RDB snapshots... 错误时,别慌!这是Redis的数据安全保护机制在发挥作用。本文带你深度解析故障根因,并提供完整的解决方案。🔥 故障现象还原 客户端&am…

产品更新丨谷云科技 iPaaS 集成平台 V7.6 版本发布

六月,谷云科技iPaaS集成平台更新了V7.6版本。这次更新中我们着重对API网关、API编排、组织管理权限、API监控等功能进行了增强以及优化,一起来看看有什么新变化吧! 网关、监控、编排、组织权限全方位升级 1.API网关 错误码预警,可…

图像处理中的模板匹配:原理与实现

目录 一、什么是模板匹配? 二、模板匹配的匹配方法 1. 平方差匹配(cv2.TM_SQDIFF) 2. 归一化平方差匹配(cv2.TM_SQDIFF_NORMED) 3. 相关匹配(cv2.TM_CCORR) 4. 归一化相关匹配&#xff08…

高性能架构模式——高性能NoSQL

目录 一、关系数据库的缺点二、常见的 NoSQL 方案分 类2.1、K-V 存储2.2、文档数据库2.3、列式数据库2.4、全文搜索引擎三、高性能 NoSQL 方案的典型特征和应用场景3.1、K-V 存储典型特征和应用场景3.2、文档数据库典型特征和应用场景3.1.1、文档数据库的 no-schema 特性的优势…

正确选择光伏方案设计软件:人力成本优化的关键一步

在竞争激烈的市场环境中,企业无不追求效率提升与成本控制。设计环节作为产品开发的核心流程,其效率高低直接影响整体项目进度与资源消耗。错误的设计软件选择如同在信息高速公路上设置路障——它不会阻止前行,却会让每一次沟通、每一次修改都…

Git问题排查与故障解决详解

前言 在使用Git进行版本控制的过程中,开发者常常会遇到各种各样的问题和错误。本文将详细介绍常见的Git问题及其解决方法,帮助开发者快速定位和解决问题,避免在开发过程中浪费时间。 1. 基础错误与解决 1.1 身份配置问题 问题&#xff1a…