开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer)
目录
往期文章传送门
一、硬件定时器
硬件实现
软件实现
二、上板测试
往期文章传送门
开发一个RISC-V上的操作系统(一)—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统(二)—— 系统引导程序(Bootloader)_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统(三)—— 串口驱动程序(UART)_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统(四)—— 内存管理_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统(五)—— 协作式多任务_Patarw_Li的博客-CSDN博客
开发一个RISC-V上的操作系统(六)—— 中断(interrupt)和异常(exception)_Patarw_Li的博客-CSDN博客
本节的代码在仓库的 05_HW_TIMER 目录下,仓库链接:riscv_os: 一个RISC-V上的简易操作系统
本文代码的运行调试会在前面开发的RISC-V处理器上进行,仓库链接:cpu_prj: 一个基于RISC-V指令集的CPU实现
一、硬件定时器
生活离不开对时间的管理,操作系统也是一样。
时钟节拍(Tick)
- 操作系统中最小的时间单位。
- Tick的单位(周期)由硬件定时器的周期决定(通常为1~100ms)。
- Tick周期越小,系统精度越高,但开销越大。
系统时钟
- 操作系统维护一个整形计数值,记录着系统启动直到当前发生的Tick总数。
硬件实现
在本项目中,timer作为一个外设挂载在总线rib上,rtl文件为 cpu_prj\FPGA\rtl\perips\timer.v :

五个读写信号用于读写timer模块中的寄存器,信号 timer_int_flag_o 用于给 clint 中断模块发出中断信号,verilog 代码如下:
// 32bit 定时器
module timer(input wire clk ,input wire rst_n ,// 读写信号 input wire wr_en_i , // write enableinput wire[`INST_ADDR_BUS] wr_addr_i , // write addressinput wire[`INST_REG_DATA] wr_data_i , // write datainput wire[`INST_ADDR_BUS] rd_addr_i , // read addressoutput reg [`INST_REG_DATA] rd_data_o , // read data// 中断信号output wire timer_int_flag_o );localparam TIMER_CTRL = 4'h0;localparam TIMER_COUNT = 4'h4;localparam TIMER_EVALUE = 4'h8;// [0]: timer enable// [1]: timer int enable// [2]: timer int pending, software write 0 to clear it// addr offset: 0x00reg[31:0] timer_ctrl;// timer current count, read only// addr offset: 0x04reg[31:0] timer_count;// timer expired value// addr offset: 0x08reg[31:0] timer_evalue;assign timer_int_flag_o = ((timer_ctrl[2] == 1'b1) && (timer_ctrl[1] == 1'b1))? 1'b1 : 1'b0;// 读写寄存器,write before readalways @ (posedge clk or negedge rst_n) beginif (!rst_n) begintimer_ctrl <= `ZERO_WORD;timer_evalue <= `ZERO_WORD;endelse beginif (wr_en_i == 1'b1) begincase (wr_addr_i[3:0])TIMER_CTRL: begin// 这里代表软件只能把 timer_ctrl[2]置0,无法将其置1timer_ctrl = {wr_data_i[31:3], (timer_ctrl[2] & wr_data_i[2]), wr_data_i[1:0]};endTIMER_EVALUE: begintimer_evalue = wr_data_i;endendcaseendif(timer_ctrl[0] == 1'b1 && timer_count >= timer_evalue) begintimer_ctrl[0] = 1'b0;timer_ctrl[2] = 1'b1;endcase (rd_addr_i[3:0])TIMER_CTRL: beginrd_data_o = timer_ctrl;endTIMER_COUNT: beginrd_data_o = timer_count;endTIMER_EVALUE: beginrd_data_o = timer_evalue;enddefault: beginrd_data_o = `ZERO_WORD;endendcaseendend// 计数器 timer_countalways @ (posedge clk or negedge rst_n) beginif (!rst_n) begintimer_count <= `ZERO_WORD;endelse beginif (timer_ctrl[0] != 1'b1 || timer_count >= timer_evalue) begintimer_count <= `ZERO_WORD;endelse begintimer_count <= timer_count + 1'b1;endendendendmodule
其中:
timer_ctrl 为控制寄存器,低三位有效,分别是第0位 timer enable ,置1则 timer_count 开始计时;第1位 timer int enable,置1则允许发出中断信号,反之则不允许;第2位 timer int pending,当 timer_count >= timer_evalue 时,就把该位置1,表示有中断信号要发出,需要软件置0。
timer_count 为计数寄存器(只读)。
timer_evalue 存放过期值,用来与 timer_count 寄存器比较,当 timer_count >= timer_evalue 时则发出中断信号。
软件实现
代码实现为 riscv_os/05_HW_TIMER/timer.c :
// 1s
#define TIMER_INTERVAL 50000000/** The TIMER control registers are memory-mapped at address TIMER (defined in inc/platform.h). * This macro returns the address of one of the registers.*/
#define TIMER_REG_ADDRESS(reg) ((volatile uint32_t *) (TIMER + reg))/** TIMER registers map* timer_count is a read-only reg*/
#define TIMER_CTRL 0
#define TIMER_COUNT 4
#define TIMER_EVALUE 8#define timer_read_reg(reg) (*(TIMER_REG_ADDRESS(reg)))
#define timer_write_reg(reg, data) (*(TIMER_REG_ADDRESS(reg)) = (data))#define TIMER_EN 1 << 0
#define TIMER_INT_EN 1 << 1
#define TIMER_INT_PENDING 1 << 2static uint32_t _tick = 0;void timer_load(uint32_t interval)
{timer_write_reg(TIMER_EVALUE, interval);timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) | (TIMER_EN)));
}/** enable timer interrupt*/
void timer_init()
{timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) | (TIMER_INT_EN)));timer_load(TIMER_INTERVAL);
}void timer_handler()
{timer_write_reg(TIMER_CTRL, (timer_read_reg(TIMER_CTRL) & ~(TIMER_INT_PENDING)));_tick++;printf("tick: %d\n", _tick);timer_load(TIMER_INTERVAL);
}
其中:
_tick 为该模块维护的全局时间节拍。
timer_load(uint32_t interval) 函数用于给定时器模块寄存器赋值,interval 个硬件时钟周期后发出定时器中断(如果 interval = 板子系统时钟频率,相当于1s)。
timer_init() 函数用于给定时器模块寄存器初始化。
timer_handler() 函数用于执行定时器中断处理,当定时器中断发生的时候,执行这个函数的内容。该函数会将 _tick 值加一后,执行 timer_load(uint32_t interval) 函数,从而达到持续计数的功能。
二、上板测试
烧录到板子上后,打开串口调试程序,可以看到tick值一直在计数,从而实现系统时钟的功能:

遇到问题欢迎加群 892873718 交流~
相关文章:
开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer)
目录 往期文章传送门 一、硬件定时器 硬件实现 软件实现 二、上板测试 往期文章传送门 开发一个RISC-V上的操作系统(一)—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统(二)—— 系统引导…...
电池的正极是带正电?
首先说明结论:电池正极带正电,负极带负电。 一个错误的实例: 如果说电流是从电池正极流动到电池负极,那么电子就是从负极流动到正极,那么正极就是带负电。----这个说法是错误的。这是因为,根据那么很出名…...
Go 协程为什么比进程和线程占用的系统资源低?
1 介绍 进程是一个程序在执行时所占据的独立虚拟内存空间,Linux为每个进程分配一个虚拟内存空间,包括栈、未使用的内存、堆、BSS、DATA和TEXT等。 线程可以看作是轻量级的进程,多个线程在一个进程中“共生”,每个线程拥有独立的…...
性能测试—Jmeter工具
文章目录 性能测试1. 术语介绍2. 方法3. 应用场景4. 工具(Jmeter)4.1 介绍4.2 元件和组件4.2.2 元件4.2.1 组件 4.3 作用域4.4 参数化4.5 执行脚本 性能测试 1. 术语介绍 响应时间(Response time):对请求作出响应所需要的时间。 在互联网上对…...
【分布式系统】聊聊高性能设计
每个程序员都应该知道的数字 高性能 对于以上的数字,其实每个程序员都应该了解,因为只有了解这些基本的数字,才能知道对于CPU、内存、磁盘、网络之间数据读写的时间。1000ms 1S。毫秒->微秒->纳秒-秒->分钟 为什么高性能如此重要的…...
自动驾驶数据集汇总
1.Nuscenes 数据集链接:nuScenes nuscenes数据集下有多个任务,涉及Detection(2D/3D)、Tracking、prediction、激光雷达分割、全景任务、规划控制等多个任务; nuScenes数据集是一个具有三维目标注释的大型自动驾驶数…...
面向对象的基本原则
背景 面向对象是抽象技术的一种实现,将对象作为真实世界中实体的抽象,代表了特定的一块密集而内聚的信息。在面向对象设计及实现中,重点考虑的就是如何做到关注点分离。因为对象内的联系通常比对象间的联系更强。关注点分离就是将对象中高频…...
C语言开发基础知识(一)
文章目录 数据类型宏变量函数inline 内联函数static 关键字的作用const 关键字的作用extern 关键字的作用volatile 关键字的作用include 关键字的作用数组、字符串指针堆内存管理结构体文件操作数据类型 C语言中数据类型分有符号和无符号,默认是有符号的。 有符号类型: 数据…...
API网关类型与区别
什么是API网关? 在现代软件架构中,API(应用程序编程接口)网关起着重要的作用。它是一个中间层,用于管理和控制应用程序之间的通信。API网关可以提供一些关键功能,如流量控制,安全认证ÿ…...
linux:nginx网站升级至http2
参考: 怎样把网站升级到http/2 - 知乎 HTTP/2 与 HTTP/1.1:它们如何影响 Web 性能? | Cloudflare 总结: nginx.conf修改 http2需要ssl支持 listen 443 ssl http2;...
Flutter:屏幕适配
flutter_screenutil flutter_screenutil是一个用于在Flutter应用程序中进行屏幕适配的工具包。它旨在帮助开发者在不同屏幕尺寸和密度的设备上创建响应式的UI布局。 flutter_screenutil提供了一些用于处理尺寸和间距的方法,使得开发者可以根据设备的屏幕尺寸和密度…...
中科亿海微ROM使用
标题 ROM(Read-Only Memory,只读存储器)是一种在FPGA(Field-Programmable Gate Array,现场可编程门阵列)中常用的存储器类型。与RAM(Random Access Memory,机存取存储器)…...
Python接口自动化测试之UnitTest详解
基本概念 UnitTest单元测试框架是受到JUnit的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享和关机代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。 它分为四个部分test fixture、TestC…...
python——案例17:判断某年是否是闰年
案例17:判断某年是否是闰年 判断依据:闰年就是能被400整除,或者能被4整除的年份numint(input(输入年份:))if num%1000: if num%4000: #整百年份的判断print("%s年是闰年"%num) #…...
allure测试报告
使用pytest结合Allure进行测试报告生成的简单教程 allure测试报告 Allure基于Java开发,因此我们需要提前安装Java 8或以上版本的环境。 ◆安装allure-pytest插件在DOS窗口输入命令“pip3 install allure-pytest”,然后按“Enter”键。 下载安装Allure…...
Vue 路由懒加载
Vue 路由懒加载 随着 Web 应用的复杂性不断增加,性能优化成为了开发人员必须面对的挑战之一。Vue 路由懒加载是一项关键技术,它可以帮助我们提高 Web 应用的加载速度,从而提升用户体验。 在本篇技术博文中,我们将深入探讨 Vue 路…...
软件设计师(七)面向对象技术
面向对象: Object-Oriented, 是一种以客观世界中的对象为中心的开发方法。 面向对象方法有Booch方法、Coad方法和OMT方法等。推出了同一建模语言UML。 面向对象方法包括面向对象分析、面向对象设计和面向对象实现。 一、面向对象基础 1、面向对象的基本…...
Qt中将信号封装在一个继承类中的方法
QLabel标签类对应的信号如下: Qt中标签是没有双击(double Click)这个信号的; 需求一:若想双击标签使其能够改变标签中文字的内容,那么就需要自定义一个“双击”信号,并将其封装在QLabel类的派生…...
Docker介绍
1. docker是什么 1.1 为什么会有docker出现? 假设你在开发一个项目的时候,你使用的是windows系统而且你的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。你正在开发的应用依赖于你当前的配置而且还要依赖于某些配置文件。此外…...
C++红黑树
一、红黑树的概念 红黑树是一种二叉搜索树,在其每个节点上增加一个存储位用于表示节点的颜色,可以是Red或Black 通过对任何一条从根到叶子的路径上的各个节点着色方式的限制,红黑树确保没有一条路径比其他路径长两倍 红黑树的性质ÿ…...
遗传算法实战:解码带时间窗约束的车辆路径规划(VRPTW)
1. 当物流遇上时间窗:VRPTW问题到底有多难? 想象一下你是一家生鲜电商的物流调度员,早上6点打开系统,屏幕上突然弹出16个新订单:王阿姨要7:30-8:00收到活鱼,李大爷要求8:15-8:45配送新鲜蔬菜,而…...
联想小新潮7000-13黑苹果安装全记录:无需无线网卡+双系统共存(附EFI文件)
联想小新潮7000-13黑苹果实战指南:无网卡方案与双系统精调 最近两年,黑苹果社区的技术方案越来越成熟,特别是对于联想小新潮7000-13这类热门机型,已经形成了相对稳定的解决方案。作为一名从2018年开始折腾黑苹果的老玩家…...
如何用茉莉花插件3步彻底解决Zotero中文文献管理难题
如何用茉莉花插件3步彻底解决Zotero中文文献管理难题 【免费下载链接】jasminum A Zotero add-on to retrive CNKI meta data. 一个简单的Zotero 插件,用于识别中文元数据 项目地址: https://gitcode.com/gh_mirrors/ja/jasminum 茉莉花(Jasminum)是一款专为…...
**无代码AI时代来临:用低门槛工具构建智能应用的实战指南**在人工智能飞速发展的今天,越来
无代码AI时代来临:用低门槛工具构建智能应用的实战指南 在人工智能飞速发展的今天,越来越多开发者开始关注如何让非程序员也能快速构建具备AI能力的应用。这正是“无代码AI”的核心价值所在——它打破了传统编程对技术门槛的依赖,使业务人员、…...
如何基于STM32、迪文串口屏与WIFI模组构建远程环境监控系统
1. 项目背景与系统架构设计 远程环境监控系统在智能家居、农业大棚、仓库管理等场景中应用广泛。这个项目最吸引我的地方在于它完美结合了本地显示和远程控制,用STM32作为"大脑",迪文串口屏当"脸面",WIFI模组充当"传…...
CHORD-X视觉战术指挥系统互联网技术应用:基于WebRTC的低延迟视频指挥通信
CHORD-X视觉战术指挥系统互联网技术应用:基于WebRTC的低延迟视频指挥通信 1. 引言 想象一下,在应急指挥或战术协同现场,前线人员通过摄像头捕捉到关键画面,指挥中心需要立即看到并做出决策。传统的方式,可能是通过专…...
DLSS智能管理终极指南:如何快速提升游戏性能的完整解决方案
DLSS智能管理终极指南:如何快速提升游戏性能的完整解决方案 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 你是否厌倦了手动管理游戏中的DLSS文件?当你想尝试新版本DLSS提升帧率时,…...
大麦网自动化抢票脚本:Python技术实现与优化指南
大麦网自动化抢票脚本:Python技术实现与优化指南 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 在热门演出票务秒速售罄的今天,手动抢票的成功率微乎…...
计算机视觉知识点-答题卡识别
之前跟同事聊过答题卡识别的原理,自己调研了一下,高考那种答题卡是通过一个专门的答题卡阅读器进行识别的,采用红外线扫描答题卡,被涂过2B碳的区域会被定位到,再加上一些矫正逻辑就能试下判卷的功能.这种方法的准确度很高.淘宝上查了下光标机的误码率是0.9999999(7个9).见下图.…...
MCA Selector:Minecraft世界区块管理的终极解决方案
MCA Selector:Minecraft世界区块管理的终极解决方案 【免费下载链接】mcaselector A tool to select chunks from Minecraft worlds for deletion or export. 项目地址: https://gitcode.com/gh_mirrors/mc/mcaselector MCA Selector是一款专业的Minecraft J…...
