开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer)

这篇具有很好参考价值的文章主要介绍了开发一个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 : 

开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer),RISC-V上的操作系统设计,risc-v,linux

五个读写信号用于读写timer模块中的寄存器,信号 timer_int_flag_o 用于给 clint 中断模块发出中断信号,verilog 代码如下:

// 32bit 定时器
module timer(

    input   wire                        clk                 ,
    input   wire                        rst_n               ,
    
    // 读写信号    
    input   wire                        wr_en_i             , // write enable
    input   wire[`INST_ADDR_BUS]        wr_addr_i           , // write address
    input   wire[`INST_REG_DATA]        wr_data_i           , // write data
    input   wire[`INST_ADDR_BUS]        rd_addr_i           , // read address
    output  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: 0x00
    reg[31:0] timer_ctrl;

    // timer current count, read only
    // addr offset: 0x04
    reg[31:0] timer_count;

    // timer expired value
    // addr offset: 0x08
    reg[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 read
    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            timer_ctrl <= `ZERO_WORD;
            timer_evalue <= `ZERO_WORD;
        end
        else begin
            if (wr_en_i == 1'b1) begin
                case (wr_addr_i[3:0])
                    TIMER_CTRL: begin
                        // 这里代表软件只能把 timer_ctrl[2]置0,无法将其置1
                        timer_ctrl = {wr_data_i[31:3], (timer_ctrl[2] & wr_data_i[2]), wr_data_i[1:0]};
                    end
                    TIMER_EVALUE: begin
                        timer_evalue = wr_data_i;
                    end
                endcase
            end
            
            if(timer_ctrl[0] == 1'b1 && timer_count >= timer_evalue) begin
                timer_ctrl[0] = 1'b0;
                timer_ctrl[2] = 1'b1;
            end
            
            case (rd_addr_i[3:0])
                TIMER_CTRL: begin
                    rd_data_o = timer_ctrl;
                end
                TIMER_COUNT: begin
                    rd_data_o = timer_count;
                end
                TIMER_EVALUE: begin
                    rd_data_o = timer_evalue;
                end
                default: begin
                    rd_data_o = `ZERO_WORD;
                end
            endcase
        end
    end
    
    // 计数器 timer_count
    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            timer_count <= `ZERO_WORD;
        end
        else begin
            if (timer_ctrl[0] != 1'b1 || timer_count >= timer_evalue) begin
                timer_count <= `ZERO_WORD;
            end
            else begin
                timer_count <= timer_count + 1'b1;
            end
        end
    end
    
    
endmodule

其中:

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 << 2

static 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值一直在计数,从而实现系统时钟的功能:

开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer),RISC-V上的操作系统设计,risc-v,linux

遇到问题欢迎加群 892873718 交流~ 文章来源地址https://www.toymoban.com/news/detail-653143.html

到了这里,关于开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从零学习开发一个RISC-V操作系统(四)丨RISC-V汇编语言编程

       本系列是博主参考B站课程学习开发一个RISC-V的操作系统的学习笔记,计划从RISC-V的底层汇编指令学起,结合C语言,在Ubuntu 20.04上开发一个简易的操作系统。一个目的是通过实践操作学习和了解什么是操作系统,第二个目的是为之后学习RISC-V的集成电路设计打下一定基础

    2024年01月25日
    浏览(32)
  • 从头开发一个RISC-V的操作系统(一)计算机系统漫游

    目标:通过这一个系列课程的学习,开发出一个简易的在RISC-V指令集架构上运行的操作系统。 这个系列的大部分文章和知识来自于:[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春,以及相关的github地址。 在这个过程中,这个系列相当于是我的学习笔记,做

    2024年04月09日
    浏览(42)
  • 从头开发一个RISC-V的操作系统(三)编译与链接

    目标:通过这一个系列课程的学习,开发出一个简易的在RISC-V指令集架构上运行的操作系统。 这个系列的大部分文章和知识来自于:[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春,以及相关的github地址。 在这个过程中,这个系列相当于是我的学习笔记,做

    2024年04月09日
    浏览(43)
  • xv6(RISC-V)操作系统源码分析第二节——操作系统组织

    一个操作系统至少需要满足以下三个要求: 多路复用 进程隔离 进程通信 硬件CPU的数量有限,且往往少于同时存在的进程数量。而操作系统需要支持进程的并发执行,所以操作系统应该能使多个进程分时共享计算机的资源。 一个进程的运行,应当具有一定的独立性,这个独

    2024年02月03日
    浏览(38)
  • RISC-V公测平台发布 · 数据库在RISC-V服务器上的适配评估

    前言 上一期讲到YCSB在RISC-V服务器上对MySQL进行性能测试(RISC-V公测平台发布 · 使用YCSB测试SG2042上的MySQL性能),在这一期文章中,我们继续深入讨论RISC-V+数据库的应用。本期就继续利用HS-2平台来测试数据库软件在RISC-V服务器上的兼容性。 参与此次实验的数据库如下: Red

    2024年02月12日
    浏览(34)
  • 在FPGA上运行轻量级Linux系统的RISC-V内核 FPGA开发

    随着嵌入式系统的发展,FPGA(现场可编程门阵列)在实现高性能和灵活性方面发挥着重要作用。RISC-V是一种基于开放指令集架构(ISA)的处理器架构,它在嵌入式系统中越来越受欢迎。本文将介绍如何在FPGA上实现一个轻量级Linux系统,其中包括RISC-V内核的开发。 为了在FPGA上

    2024年02月04日
    浏览(38)
  • RISC-V IOPMP实际用例-Rapid-k模型在NVIDIA上的应用

    安全之安全(security²)博客目录导读 2023 RISC-V中国峰会 安全相关议题汇总 说明:本文参考RISC-V 2023中国峰会如下议题,版权归原作者所有。

    2024年02月11日
    浏览(78)
  • RISC-V公测平台发布 · 第一个WEB Server “Hello RISC-V world!”

    RISC-V公测平台Web Server地址:http://175.8.161.253:8081 Web Server是互联网应用的基础设施,无论是用户访问网站,还是后端服务提供商和开发者构建各种应用程序,Web Server都在其中扮演着至关重要的角色。 显而易见,对于RISC-V生态来说, Web Server也是不可缺少的一部分 。 接下来我们

    2024年02月14日
    浏览(44)
  • 简单介绍STM32上的FreeRTOS实时操作系统

    FreeRTOS是一款广泛使用的开源实时操作系统(RTOS),它为嵌入式系统提供了可靠的任务调度和并发管理。在嵌入式领域中,STM32微控制器广受欢迎,并且与FreeRTOS的结合使用可以提供强大的功能和灵活性。在本篇博客中,我们将深入探究STM32上的FreeRTOS,并了解其核心概念、任

    2024年02月16日
    浏览(46)
  • 博流RISC-V芯片BL616开发环境搭建

    本文分别介绍博流RISC-V芯片 BL616 在 Windows和Linux 下开发环境搭建,本文同时适用BL618,BL602,BL702,BL808系列芯片。 Windows 我们在日常工作中会经常使用到 git,windows 环境下载 git 安装包安装后即可使用。下载地址:https://git-scm.com/download/win。 当前 64bit 操作系统下最新版本为

    2024年02月11日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包