006——GenericTimer(基于liteos-a)

目录

Generic Timer介绍

1.1 硬件结构

1.1.1 System Counter特性

1. 两种访问方式

2. CP15寄存器

3. MemoryMapped寄存器

1.1.2 Timer特性

1.2 SystemCounter时钟源

1.3 使用方法

GenericTimer源码分析

1.2 源码分析

1.2.1 初始化

1.2.2 启动Timer

1.2.3 中断处理


参考资料:

  • ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf

    • 《B8: The Generic Timer》

    • 《D5: System Level Implementation of the Generic Timer》

  • STM32MP157芯片手册DM00327659.pdf

    • 《46 System timer generator (STGEN)》

  • Linux时间子系统之(十七):ARM generic timer驱动代码分析

  • 《SEC_Exynos 4412 SCP_Users Manual_Ver.0.10.00_Preliminary》

Generic Timer介绍

1.1 硬件结构

        在操作系统中,需要一个系统时钟,各类芯片都有自己的定时器,它们的编程方法互不相同,这给系统移植带来麻烦。 Generic Timer是ARM推荐的一种硬件实现实现,可以实现统一的编程方法。 Generic Timer分为两部分:共享的System Counter、各个Processor专有的Timer。

  • System Counter:给所有Processor提供统一的时间

  • Timer:可以设置周期性的事件,给Processor提供中断信号

        下图是Generic Timer的硬件框图,红线表示时钟:System counter是时钟源,进入Porcessor中的Timer。 蓝线表示中断:Porcessor中的Timer产生的中断进入GIC,作为PPI(Private Peripheral Interrupt)传给Processor。 System Counter是系统级别的(System Level),给整个系统提供时钟,可以使用Memeory Mapped的寄存器来访问。

        每个Processor里都有一个Timer,这些Timer可以发出周期性的中断,给Processor提供系统时钟。Timer需要使用CP15协处理器命令来访问。

1.1.1 System Counter特性

规格描述
位宽(Width)至少56位,跟硬件实现。 读取时,可以得到64位的数值。
频率(Frequency)1M~50MHz,增加值可以调整: 比如时钟为8MHz时,每来一个时钟计数值增加1, 设置为4MHz时,每来一个时钟计数值增加2, 降低频率时可以降低功耗,同时增加步进值以维持时钟精度
溢出(Roll-over)不少于40年
精度(Accuracy)推荐:误差在24小时内不超过10秒
复位值(Start-up)从0开始
1. 两种访问方式

SystemCounter是给所有Processor使用的,它有两种访问方式:

  • CP15协处理器命令:某个Processor去访问它时可以使用CP15协处理器命令。

  • MemoryMapped寄存器:

    • 既然它是给所有Processor使用的,那么应该提供更高级的访问方法(System Level)

    • 而且有些Processor并没有实现CP15,所有也应该提供MemoryMapped的方法

2. CP15寄存器

下面这个表格列出了所有的寄存器,包括SystemCounter和Timer,不仅仅是SystemCounter。

3. MemoryMapped寄存器

这些寄存器在下列手册描述得比较清楚:

  • DM00327659.pdf的《46 System timer generator (STGEN)》

  • ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf的Table D5-1(下图):

在u-boot代码中可以看到这样的结构体:

/* System Counter */
struct sctr_regs {u32 cntcr;   // control register, 启动/停止u32 cntsr;   // status register, 是否启动/停止, 使用哪个频率u32 cntcv1;  // count value lower registeru32 cntcv2;  // count value upper register, cntcv1和cntcv2组成64位的计数值u32 resv1[4];u32 cntfid0; // base frequency register, 必须等于SystemCounter的输入频率u32 cntfid1; // cntfid1和cntfid2:其他频率u32 cntfid2;u32 resv2[1001];u32 counterid[1];
};

1.1.2 Timer特性

每个Processor都有一个Timer,它有3个寄存器,只能使用协处理器命令方位(CP15):

  • 64位的比较寄存器(CVAL):当SystemCounter的值等于它时,产生事件(中断)

    • SystemCounter总是增长的,所以Timer的64位比较寄存器也只能设置为大于SystemCounter的值

  • 被称为upcounter

  • 32位的TimerValue寄存器(TVAL)

    • 它是downconter

    • 比如设置为1000,表示再经过1000个时钟之后,就会产生事件(中断)

    • 实质是:设置64位的比较寄存器,让它等于SystemCounter+1000

  • 32位的控制寄存器(CTL)

    • 使能/禁止Timer

    • 使能输出:是否能产生事件(中断)

    • 状态:是否能产生了事件(中断)

1.2 SystemCounter时钟源

SystemCounter的时钟源,跟芯片设计相关。

以STM32MP157为例:

1.3 使用方法

 

  • 设置时钟源:芯片相关,一般u-boot里做好了

  • 设置/启动SystemCounter

  • 设置Processor的Timer:

    • 设置比较值、使能中断、使能Timer

    • 注册中断处理函数

(我不知道exynos4412太老了还是三星和其它厂商不一样,同样的ARM架构但是他的芯片里没有叫通用定时器的东西。只有下面这几个定时器加一个系统时钟,从功能上来看这个东西其实应该就是系统时钟,我的猜测不一定对。)

GenericTimer源码分析

1.2 源码分析

代码:kernel\liteos_a\platform\hw\arm\timer\arm_generic\arm_generic_timer.c

/** Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice, this list of*    conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright notice, this list*    of conditions and the following disclaimer in the documentation and/or other materials*    provided with the distribution.** 3. Neither the name of the copyright holder nor the names of its contributors may be used*    to endorse or promote products derived from this software without specific prior written*    permission.** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/#include "los_hw_pri.h"
#include "los_tick_pri.h"
#include "los_sys_pri.h"
#include "gic_common.h"#define STRING_COMB(x, y, z)        x ## y ## z#ifdef LOSCFG_ARCH_SECURE_MONITOR_MODE
#define TIMER_REG(reg)              STRING_COMB(TIMER_REG_, CNTPS, reg)
#else
#define TIMER_REG(reg)              STRING_COMB(TIMER_REG_, CNTP, reg)
#endif
#define TIMER_REG_CTL               TIMER_REG(_CTL)     /* 32 bits */
#define TIMER_REG_TVAL              TIMER_REG(_TVAL)    /* 32 bits */
#define TIMER_REG_CVAL              TIMER_REG(_CVAL)    /* 64 bits */
#define TIMER_REG_CT                TIMER_REG(CT)       /* 64 bits */#ifdef __LP64__#define TIMER_REG_CNTFRQ            cntfrq_el0/* CNTP AArch64 registers */
#define TIMER_REG_CNTP_CTL          cntp_ctl_el0
#define TIMER_REG_CNTP_TVAL         cntp_tval_el0
#define TIMER_REG_CNTP_CVAL         cntp_cval_el0
#define TIMER_REG_CNTPCT            cntpct_el0/* CNTPS AArch64 registers */
#define TIMER_REG_CNTPS_CTL         cntps_ctl_el1
#define TIMER_REG_CNTPS_TVAL        cntps_tval_el1
#define TIMER_REG_CNTPS_CVAL        cntps_cval_el1
#define TIMER_REG_CNTPSCT           cntpct_el0#define READ_TIMER_REG32(reg)       AARCH64_SYSREG_READ(reg)
#define READ_TIMER_REG64(reg)       AARCH64_SYSREG_READ(reg)
#define WRITE_TIMER_REG32(reg, val) AARCH64_SYSREG_WRITE(reg, (UINT64)(val))
#define WRITE_TIMER_REG64(reg, val) AARCH64_SYSREG_WRITE(reg, val)#else /* Aarch32 */#define TIMER_REG_CNTFRQ            CP15_REG(c14, 0, c0, 0)/* CNTP AArch32 registers */
#define TIMER_REG_CNTP_CTL          CP15_REG(c14, 0, c2, 1)
#define TIMER_REG_CNTP_TVAL         CP15_REG(c14, 0, c2, 0)
#define TIMER_REG_CNTP_CVAL         CP15_REG64(c14, 2)
#define TIMER_REG_CNTPCT            CP15_REG64(c14, 0)/* CNTPS AArch32 registers are banked and accessed though CNTP */
#define CNTPS CNTP#define READ_TIMER_REG32(reg)       ARM_SYSREG_READ(reg)
#define READ_TIMER_REG64(reg)       ARM_SYSREG64_READ(reg)
#define WRITE_TIMER_REG32(reg, val) ARM_SYSREG_WRITE(reg, val)
#define WRITE_TIMER_REG64(reg, val) ARM_SYSREG64_WRITE(reg, val)#endif#define OS_CYCLE_PER_TICK (g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND)UINT32 HalClockFreqRead(VOID)
{return READ_TIMER_REG32(TIMER_REG_CNTFRQ);
}VOID HalClockFreqWrite(UINT32 freq)
{WRITE_TIMER_REG32(TIMER_REG_CNTFRQ, freq);
}STATIC_INLINE VOID TimerCtlWrite(UINT32 cntpCtl)
{WRITE_TIMER_REG32(TIMER_REG_CTL, cntpCtl);
}STATIC_INLINE UINT64 TimerCvalRead(VOID)
{return READ_TIMER_REG64(TIMER_REG_CVAL);
}STATIC_INLINE VOID TimerCvalWrite(UINT64 cval)
{WRITE_TIMER_REG64(TIMER_REG_CVAL, cval);
}STATIC_INLINE VOID TimerTvalWrite(UINT32 tval)
{WRITE_TIMER_REG32(TIMER_REG_TVAL, tval);
}UINT64 HalClockGetCycles(VOID)
{UINT64 cntpct;cntpct = READ_TIMER_REG64(TIMER_REG_CT);return cntpct;
}LITE_OS_SEC_TEXT VOID OsTickEntry(VOID)
{TimerCtlWrite(0);OsTickHandler();/** use last cval to generate the next tick's timing is* absolute and accurate. DO NOT use tval to drive the* generic time in which case tick will be slower.*/TimerCvalWrite(TimerCvalRead() + OS_CYCLE_PER_TICK);TimerCtlWrite(1);
}LITE_OS_SEC_TEXT_INIT VOID HalClockInit(VOID)
{UINT32 ret;g_sysClock = HalClockFreqRead();ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0);if (ret != LOS_OK) {PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__, ret);}
}LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
{HalIrqUnmask(OS_TICK_INT_NUM);/* triggle the first tick */TimerCtlWrite(0);TimerTvalWrite(OS_CYCLE_PER_TICK);TimerCtlWrite(1);
}VOID HalDelayUs(UINT32 usecs)
{UINT64 cycles = (UINT64)usecs * HalClockFreqRead() / OS_SYS_US_PER_SECOND;UINT64 deadline = HalClockGetCycles() + cycles;while (HalClockGetCycles() < deadline) {__asm__ volatile ("nop");}
}UINT64 hi_sched_clock(VOID)
{return LOS_CurrNanosec();
}UINT32 HalClockGetTickTimerCycles(VOID)
{UINT64 cval = TimerCvalRead();UINT64 cycles = HalClockGetCycles();return (UINT32)((cval > cycles) ? (cval - cycles) : 0);
}VOID HalClockTickTimerReload(UINT32 cycles)
{HalIrqMask(OS_TICK_INT_NUM);HalIrqClear(OS_TICK_INT_NUM);TimerCtlWrite(0);TimerCvalWrite(HalClockGetCycles() + cycles);TimerCtlWrite(1);HalIrqUnmask(OS_TICK_INT_NUM);
}VOID HalClockIrqClear(VOID) {}

1.2.1 初始化

它做了2件事:

  • 读出SystemCounter的频率:以后设置中断周期时要用

  • 注册中断处理函数

LITE_OS_SEC_TEXT_INIT VOID HalClockInit(VOID)
{UINT32 ret;
​g_sysClock = HalClockFreqRead();ret = LOS_HwiCreate(OS_TICK_INT_NUM, MIN_INTERRUPT_PRIORITY, 0, OsTickEntry, 0);if (ret != LOS_OK) {PRINT_ERR("%s, %d create tick irq failed, ret:0x%x\n", __FUNCTION__, __LINE__,ret);}
}

1.2.2 启动Timer

它做了2件事:

  • 使能中断:中断号是29

  • 设置TimerValue寄存器:

    • OS_CYCLE_PER_TICK = g_sysClock / 100,也就是10MS之后产生中断

    • 设置TimerValue寄存器的实质,就是设置比较寄存器(CVAL) = 当前SystemCounter值 + OS_CYCLE_PER_TICK

LITE_OS_SEC_TEXT_INIT VOID HalClockStart(VOID)
{HalIrqUnmask(OS_TICK_INT_NUM);
​/* triggle the first tick */TimerCtlWrite(0);TimerTvalWrite(OS_CYCLE_PER_TICK);TimerCtlWrite(1);
}

1.2.3 中断处理

它做了2件事:

  • 调用OsTickHandler

  • 设置下一次中断时间:

    • 设置比较寄存器(CVAL) = 当前比较寄存器值 + OS_CYCLE_PER_TICK

    • 为什么不是当前SystemCounter值 + OS_CYCLE_PER_TICK

    • 因为处理中断也是要时间的,SystemCounter值一直在增加

    • 要让两次中断的间隔非常精确的话,要使用发生中断时的SystemCounter值,也就是比较寄存器的当前值

LITE_OS_SEC_TEXT VOID OsTickEntry(VOID)
{TimerCtlWrite(0);
​OsTickHandler();
​/** use last cval to generate the next tick's timing is* absolute and accurate. DO NOT use tval to drive the* generic time in which case tick will be slower.*/TimerCvalWrite(TimerCvalRead() + OS_CYCLE_PER_TICK);TimerCtlWrite(1);
}

        这张图片是对三个函数在定时器中的作用的表述,韦东山老师视频里画的,其实就是一个定时器的使用,没什么特别的东西,这期有点水哈哈哈哈哈,基本都是韦老师的笔记。因为定时器这个东西从学51开始我就学了,真的是没什么好说的的了。

STM32时钟与定时器_stm32定时器时钟-CSDN博客

Linux内核定时器-CSDN博客

我以前写过两篇相关的一个是M核的32用的库函数,一个是A核的跑了linux。这些都差不多。

 

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

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

相关文章

SQPSK

文章目录 [1]张显辉,沈国松.SQPSK调制体制在跟踪与数据中继卫星中的应用[J].遥测遥控,2007(S1):26-29.[2]保骏.QPSK、SQPSK信号解调相位模糊及其对Viterbi译码的影响[J].四川兵工学报,2011,32(03):53-55.[3]赵辉,严晓芳,张玉. 星载SQPSK高速调制系统的设计[C]//中国通信学会.20…

在服务器上训练faster-rcnn模型(pycharm和Termius)

本文主要介绍使用服务器训练模型的两种方式&#xff1a;pycharm&#xff08;可视化界面友好&#xff09;and终端&#xff0c;本人用的是macos系统&#xff0c;可能pycharm某些入口的位置不一样&#xff0c;本教程代码以faster-rcnn为例 准备工作&#xff1a; 1.知道自己所用服…

外卖店优先级c++

题目 输入样例&#xff1a; 2 6 6 1 1 5 2 3 1 6 2 2 1 6 2输出样例&#xff1a; 1样例解释 6时刻时&#xff0c;1 号店优先级降到 3&#xff0c;被移除出优先缓存&#xff1b;2 号店优先级升到 6&#xff0c;加入优先缓存。 所以是有 1 家店 (2 号) 在优先缓存中。 思路 …

docker 安装部署 jenkins

今天 小☀ 给大家普及一下什么是 jenkins&#xff01;&#xff01; Jenkins是一个开源软件项目&#xff0c;基于Java开发的持续集成工具。它提供了一个开放易用的软件平台&#xff0c;使软件项目可以进行持续集成。Jenkins起源于Hudson&#xff0c;主要用于持续、自动地构建、…

C语言 自定义类型:结构体

目录 前言 一、结构体类型 1.1 结构体的声明 1.2 结构体变量的创建和初始化 1.3 结构体的特殊声明 1.4 结构体的自引用 二、结构体的对齐 2.1 对齐规则 2.2 内存对齐的原因 2.3 修改默认对齐数 2.4 结构体传参 三、结构体实现位段 3.1 位段的内存分配 3.2 段的跨平…

通过JWT完成token登录验证

前言 什么是JWT&#xff1f; 全称是JSON Web token&#xff0c;是用于对应用程序上的用户进行身份验证的标记&#xff0c;使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据 使用JWT的优势 提高了程序的可伸缩性&#xff0c;也极大的提高了应用程序的安全…

几种常见的IO模型学习

IO模型 IO模型&#xff08;输入输出模型&#xff09;是计算机科学中用于描述程序如何处理输入、产生输出以及与外部系统交互的一种概念模型。在操作系统和网络编程中&#xff0c;IO模型尤其重要&#xff0c;因为它们决定了程序如何与文件、网络套接字和其他资源进行通信。以下…

Harbor介绍

1.什么是Harbor Harbor是一个开源的企业级Docker Registry管理项目&#xff0c;由VMware公司开源。 Harbor提供了比Docker官方公共镜像仓库更为丰富和安全的功能&#xff0c;尤其适合企业环境使用。以下是Harbor的一些关键特性&#xff1a; 权限管理&#xff08;RBAC&#x…

Ribbon知识点

1、通过类实现重写Ribbon规则 1.1注意 这个类一定不能跟启动类放在同一个包下面&#xff0c;不能被componentScan给扫描到。 需要如图放置&#xff1a; 要是被componentScan给扫描到&#xff0c;则会被所有的服务提供方所共享&#xff0c;那么就不能实现指定服务用不同的Ribbo…

灵神DP题单---划分型 DP---§6.1 判定能否划分

这里的状态定义一般使用DP【i】 表示 考虑前i个东西能否满足条件&#xff0c;然后我们枚举上一次的转移位置就好了 2369. 检查数组是否存在有效划分 需要注意的是我习惯从1开始写&#xff0c;所以要处理好边界的下标问题 class Solution { public:bool validPartition(vector&l…

java网络原理(三)----三次握手四次挥手

三次握手 三次握手是建立连接的过程&#xff0c;四次挥手是断开连接的过程&#xff0c;三次握手发生在socket.accept()之前。 客户端和服务器尝试建立连接的时候服务器就会和客户端进行一系列的数据交换称为握手&#xff0c;这个过程建立完了后&#xff0c;连接就好了。 A和B…

Matlab有限差分法求解狄利克雷(Dirichlet)边界的泊松(Poisson)问题,边界值为任意值

参考l链接&#xff1a; 有限差分法简介有限差分法-二维泊松方程及其Matlab程序实现弹性力学方程 有限差分法matlab,泊松方程的有限差分法的MATLAB实现 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Matrix method for Poisson Equation …

基于python+vue的OA公文发文管理系统flask-django-php-nodejs

系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方法对OA公文发文管理的现状进行系统调查。采用结构化的分析设计&#xff0c;该方法要求结合一定的图表&#xff0c;在模块化的基础上进行系统的开发工作。在设计中采用“自下而上”的…

使用 Amazon SageMaker 微调 Llama 2 模型

本篇文章主要介绍如何使用 Amazon SageMaker 进行 Llama 2 模型微调的示例。 这个示例主要包括: Llama 2 总体介绍Llama 2 微调介绍Llama 2 环境设置Llama 2 微调训练 前言 随着生成式 AI 的热度逐渐升高&#xff0c;国内外各种基座大语言竞相出炉&#xff0c;在其基础上衍生出…

测试开发工程师(QA)职业到底需要干些什么?part1:移动端QA

概述 移动端QA测试开发工作主要涉及对移动应用程序进行质量保证和测试的开发工作。以下是移动端QA测试开发人员的主要职责和工作内容&#xff1a; 测试计划和策略制定&#xff1a;参与制定移动应用程序的测试计划和策略&#xff0c;确定测试范围、测试目标和测试方法。考虑到…

Mysql---DML

文章目录 目录 一.DML概述 注入数据&#xff08; Insert&#xff09; 替换数据&#xff08;replace&#xff09; 删除数据 &#xff08;delete&#xff09; 修改数据 &#xff08;update&#xff09; 查询数据 &#xff08;select&#xff09; 二. 多表连接查询 内连接 子…

Linux环境JMeter脚本性能测试、easyNmon生成监控报告

一、下载JMeter安装包 Jmeter是Java开发的&#xff0c;需要依赖JDK环境&#xff0c;因此我们需提前安装好JDK。 Jmeter是开源的工具&#xff0c;我们直接到官网下载即可。 最新版本下载地址&#xff1a;Apache JMeter - Download Apache JMeter 二、安装JMeter #新建jmete…

【GIT】最好用的git可视化教程网站推荐

最好用可视化学习git 网站:https://learngitbranching.js.org/?demo&localezh_CN 玩遍所有关卡&#xff0c;花半天时间便能掌握git &#x1f603; 本地仓库 基础命令介绍 git commit 提交 git branch <分支名> 创建分支 git checkout <分支名> 切换分支 git…

鸿蒙Harmony应用开发—ArkTS(@State装饰器:组件内状态)

State装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI会发生对应的渲染改变。 在状态变量相关装饰器中&#xff0c;State是最基础的&#xff0c;使变量拥有状态属性的装饰器&a…

【C++ leetcode】双指针问题

1. 611. 有效三角形的个数 题目 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 画图 和 文字 分析 判断是否是三角形要得到三边&#xff0c;由于遍历三边要套三层循环&#x…