八、RISC-V SoC外设——GPIO接口 代码讲解

2023-11-19

前几篇博文中注释了RISC-V的内核CPU部分,从这篇开始来介绍RISC-V SoC的外设部分。

另外,在最后一个章节中会上传额外添加详细注释的工程代码,完全开源,如有需要可自行下载。

目录

0 RISC-V SoC注解系列文章目录

1. 结构

2. GPIO模块

2.1 输入和输出端口

2.2 代码注解

2.3 GPIO功能实现


 

0 RISC-V SoC注解系列文章目录

零、RISC-V SoC软核笔记详解——前言

 一、RISC-V SoC内核注解——取指

 二、RISC-V SoC内核注解——译码

三、RISC-V SoC内核注解——执行

四、RISC-V SoC内核注解——除法(试商法)

五、RISC-V SoC内核注解——中断

六、RISC-V SoC内核注解——通用寄存器

七、RISC-V SoC内核注解——总线

八、RISC-V SoC外设注解——GPIO

九、RISC-V SoC外设注解——SPI接口

十、RISC-V SoC外设注解——timer定时器

十一、RISC-V SoC外设注解——UART模块(终篇)

1. 结构

如下图,我们之前介绍的RISC-V内核部分,是图中左上角的RISC-V处理器核。而内核和所有的外设都挂载在总线上,内核通过总线和外设进行数据交互。这六个外设中,RAM和ROM外设已经在之前的博文中进行了解析,因此不再赘述。现在我们来介绍外设中的GPIO外设。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ29kZV9jb3B5MQ==,size_15,color_FFFFFF,t_70,g_se,x_16

2. GPIO模块

2.1 输入和输出端口

input wire clk,  
input wire rst,  
  
input wire we_i,  //总线写使能
input wire[31:0] addr_i,   //总线 配置IO口寄存器地址
input wire[31:0] data_i,   //总线 写数据(用来配置IO口相关寄存器)
input wire[1:0] io_pin_i,  //输入模式下,IO口的输入逻辑电平
  
output wire[31:0] reg_ctrl,  //IO口控制寄存器数据 0: 高阻,1:输出,2:输入
output wire[31:0] reg_data,  //IO口数据寄存器数据
output reg[31:0] data_o       // 总线读IO口寄存器数据

2.2 代码注解

Step1:先设计两个寄存器:gpio_ctrl(控制GPIO的输入和输出模式); gpio_data(存放GPIO的输入或输出数据)。

// 每2位控制1个IO的模式,最多支持16个IO  
// 0: 高阻,1:输出,2:输入  
reg[31:0] gpio_ctrl;  
// 输入输出数据  
reg[31:0] gpio_data;  
  
assign reg_ctrl = gpio_ctrl;  
assign reg_data = gpio_data; 

Step2:给这两个寄存器规划地址。

// GPIO控制寄存器的地址  
localparam GPIO_CTRL = 4'h0;  
// GPIO数据寄存器的地址  
localparam GPIO_DATA = 4'h4;  

Step3:通过寄存器寻址来,对上述定义的两个寄存器进行写操作,通过配置gpio_ctrl寄存器来实现GPIO的输入输出。

// 写寄存器  
always @ (posedge clk) begin  
    if (rst == 1'b0) begin  
        gpio_data <= 32'h0;  
        gpio_ctrl <= 32'h0;  
    end else begin  
        if (we_i == 1'b1) begin  
            case (addr_i[3:0])  //寄存器寻址
                GPIO_CTRL: begin  
                    gpio_ctrl <= data_i;  //通过配置寄存器gpio_ctrl来实现GPIO的输入输出
                end  
                GPIO_DATA: begin  
                    gpio_data <= data_i;  
                end  
            endcase  
        end else begin  //如果IO口是输入模式,则将输入的逻辑电平存放到gpio_data寄存器中
            if (gpio_ctrl[1:0] == 2'b10) begin  
                gpio_data[0] <= io_pin_i[0];  
            end  
            if (gpio_ctrl[3:2] == 2'b10) begin  
                gpio_data[1] <= io_pin_i[1];  
            end  
        end  
    end  
end

以下代码是通过总线来读IO口相关寄存器数据。

// 读寄存器  
always @ (*) begin  
    if (rst == 1'b0) begin  
        data_o = 32'h0;  
    end else begin  
        case (addr_i[3:0])  
            GPIO_CTRL: begin  
                data_o = gpio_ctrl;  
            end  
            GPIO_DATA: begin  
                data_o = gpio_data;  
            end  
            default: begin  
                data_o = 32'h0;  
            end  
        endcase  
    end  
end  

2.3 GPIO功能实现

在顶层tinyriscv_soc_top.v模块中,

// io0  
assign gpio[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz;  
assign io_in[0] = gpio[0];  
// io1  
assign gpio[1] = (gpio_ctrl[3:2] == 2'b01)? gpio_data[1]: 1'bz;  
assign io_in[1] = gpio[1];  
// gpio模块例化  
gpio gpio_0(  
    .clk(clk),  
    .rst(rst),  
    .we_i(s4_we_o),  
    .addr_i(s4_addr_o),  
    .data_i(s4_data_o),  
    .data_o(s4_data_i),  
    .io_pin_i(io_in),  
    .reg_ctrl(gpio_ctrl),  
    .reg_data(gpio_data)  
);  

上述代码中:

gpio[0] = (gpio_ctrl[1:0] == 2'b01)? gpio_data[0]: 1'bz; 

是说当配置寄存器gpio_ctrl[1:0]为1时,说明GPIO为输出模式,将gpio_data[0]输出至对应的IO口,如果gpio_ctrl[1:0]不为1,即为0或2,对应高阻态和输入模式,都将GPIO设置为高阻态,原因如下:

高阻态是一个数字电路里常见的术语,指的是电路的一种输出状态,既不是高电平也不是低电平,如果高阻态再输入下一级电路的话,对下级电路无任何影响,和没接一样,如果用万用表测的话有可能是高电平也有可能是低电平,随它后面接的东西而定。

 

参考:

从零开始写RISC-V处理器 | liangkangnan的博客 (gitee.io)

tinyriscv: 一个从零开始写的极简、非常易懂的RISC-V处理器核。 (gitee.com)

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

八、RISC-V SoC外设——GPIO接口 代码讲解 的相关文章

  • 实验1-FPGA编程入门

    文章目录 一 认识全加器 二 输入原理图实现1位加法器 一 半加器原理图输入 二 全加器原理图输入 三 Verilog语言实现全加器 四 总结 五 资料参考 一 认识全加器 一 半加器 1 逻辑分析 如下图所示 半加器只有两个输入和两个输出
  • IC数字后端

    在 innovus 里面 有时候我们需要控制 tie cell 的 fanout 和 net length 来避免 tie cell 可能出现 max transition 或者 max fanout 的违例 一般来说 只要 fanout
  • 【DDR3 控制器设计】(3)DDR3 的写操作设计

    写在前面 本系列为 DDR3 控制器设计总结 此系列包含 DDR3 控制器相关设计 认识 MIG 初始化 读写操作 FIFO 接口等 通过此系列的学习可以加深对 DDR3 读写时序的理解以及 FIFO 接口设计等 附上汇总博客直达链接 DD
  • 【Xilinx Vivado时序分析/约束系列4】FPGA开发时序分析/约束-实验工程上手实操

    目录 建立工程 添加顶层 模块1 模块2 添加约束文件 编辑时钟约束 打开布线设计 代码代表的含义 时序报告 进行时序分析 Summary 包含了汇总的信息量 Source Clock Path 这部分是表示Tclk1的延时细节 Data
  • BUCK电路分析(二)

    BUCK电路分析 二 PSIM仿真同步BUCK电路 在上片文章中 初步的分析了BUCK电路的工作原理 本章使用PSIM软件仿真BUCK电路 观察分析BUCK电路器件关键波形 图1是同步BUCK电路图 开关频率设置为200K 固定占空比 在仿
  • Linux芯片级移植与底层驱动

    原文地址 http blog csdn net 21cnbao article details 8545088 1 SoC Linux底层驱动的组成和现状 为了让Linux在一个全新的ARM SoC上运行 需要提供大量的底层支撑 如定时器节
  • PAJ7620U2手势识别——配置0x00寄存器(3)

    文章目录 前言 一 为啥要配置0x00寄存器 二 配置步骤 1 单个读操作步骤图 2 模块状态转移图绘制 3 模块波形图绘制 4 上板验证 5 参考代码 总结 前言 在前面的教程中 小编带领各位读者学习了如何通过I2C协议去唤醒PAJ762
  • 【FPGA多周期时序约束详解】- 解读FPGA多周期时序约束的全过程

    FPGA多周期时序约束详解 解读FPGA多周期时序约束的全过程 FPGA作为数字电路设计的常见工具 其设计中必然会遇到时序约束的问题 而多周期时序约束更是FPGA设计中不可避免的难点之一 本文将详细介绍FPGA多周期时序约束的全过程 并结合
  • 画时序图软件——TimeGen和Timing Designer下载

    在写实验报告的时候需要画波形图 但是手头没有很好的软件 就上网搜了一些 分享出来 这里分享的是TimeGen和Timing Designer两个软件 资源均来自网上 有侵权请联系 TimeGen使用和安装都比较简单 我发的应该里面有破解方法
  • 【FMC141】基于VITA57.4标准的4通道2.8GSPS 16位DA播放子卡(2片DAC39J84)

    FMC141是一款基于VITA57 4标准的4通道2 8GSPS 2 5GSPS 1 6GSPS采样率16位DA播放FMC子卡 该板卡为FMC 标准 符合VITA57 4与VITA57 1规范 16通道的JESD204B接口通过FMC 连接
  • 串口通信知识点总结

    串口是串行接口 serial port 的简称 也称为串行通信接口或COM接口 串口通信是指采用串行通信协议 serial communication 在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式 串口按电气标准及协议来划分
  • 基于FPGA的简易BPSK和QPSK

    1 框图 2 顶层 3 m generator M序列的生成 输出速率为500Kbps 4 S2P是串并转换模块 将1bit的m序列转换到50M时钟下的2bit M序列数据 就有4个象限 5 my pll是生成256M的时钟作为载波 因为s
  • ARM/neon memcpy 针对*未缓存*内存进行了优化?

    我使用的是基于 Xilinx Zynq 7000 ARM 的 SoC 我正在努力处理 DMA 缓冲区 需要帮助映射 Xilinx ARM SoC Zynq 7000 上的预留 可缓存 DMA 缓冲区 https stackoverflow
  • 如何为 Risc-V(汇编语言)编写旋转操作 我们有像 8086 中那样的命令吗?

    我以前使用过8086的汇编语言 8086中的旋转操作只是一个命令 但我在 Risc V 汇编语言中找不到旋转操作的特定关键字 看起来扩展 B 最终应该定义这样的指令 在那之前你必须使用左移和右移来组合它 这是 MIPS32R2 rotrv
  • Vivado ILA的debug信息保存与读取

    保存 write hw ila data D Project FPGA ILA Debug Data 202401041115 ila upload hw ila data hw ila 1 读取 display hw ila data r
  • 使用 Clang 为 RISC-V 进行编译

    我正在尝试使用构建一个 hello world 程序Clang 版本 12 0 1 适用于 RISC V 架构 我已经安装了它LLVM 版本 12 0 1 具有以下设置 cmake G Unix Makefiles DLLVM ENABLE
  • RISC-V 使用 LUI 和 ADDI 构建 32 位常量

    LUI 加载立即数 用于构建32位常量并使用U型格式 LUI 将 U 立即数放入目标寄存器 rd 的高 20 位 并用零填充最低 12 位 我在手册中找到了这个 但是如果我想将 0xffffffff 移动到寄存器 我需要的所有代码是 LUI
  • TRICONEX MA2211-100 芯片上相互连接

    TRICONEX MA2211 100 芯片上相互连接 TRICONEX MA2211 100 所有相同的组件 io的电源 处理器 和内存将需要 但是 你可以看到所有这些带存储器和处理器的OO板 针不能嵌入到一个小的单片机上 现在是 普拉克
  • 数组和结构体可以以不同的方式初始化吗?

    我的问题可能看起来很奇怪 事实上 这是上下文 我目前在切换时遇到一个奇怪的问题 关于我正在从事的项目 核心从pullinino到CV32 也发生了一些其他变化 例如关于crt0 如一些数据内存重置 这是一个 真实的 例子 说明了一个非常简单
  • 为什么 RISC-V S-B 和 U-J 指令类型以这种方式编码?

    我正在读一本书 计算机组织与设计RISC V版 我遇到了 S B 和 U J 指令类型的编码 我上面提到的那些类型有奇怪的编码立即字段 S B 类型将直接字段分为两部分 这是有道理的 因为所有指令编码都必须相似 但我无法理解为什么立即字段以

随机推荐

  • maven 教程

    Maven项目管理 Maven是什么 Maven是Apache下的项目管理工具 它由纯Java语言开发 可以帮助我们更方便的管理和构建Java项目 为什么要使用Maven jar包管理 从Maven中央仓库获取标准的规范的jar包以及相关依
  • 故障:fork failed:Resource Temporarily Unavailable解决方案

    故障 fork failed Resource Temporarily Unavailable解决方案 在一次crontab bkapp txt导入N多定时任务时候 该用户无法执行任何命令 再ssh连报fork failed Resourc
  • oVirt快速安装指南

    介绍 此文档是针对第一次安装使用oVirt的用户 带领你们逐步完成oVirt的安装 基本环境设置和安装虚拟机 css 系统需求 下面介绍的系统要求只适合典型的中小规模环境的安装 若是对于安装 系统规划和负载均衡有特殊要求的用户 也可使用下面
  • 如何看待中小企业实现数字化转型难的问题?_光点科技

    中小企业在今天的商业环境中扮演着至关重要的角色 它们为就业创造了大量机会 促进了创新 支持了经济增长 然而 中小企业在数字化转型方面面临着许多挑战 这些挑战使得实现数字化转型变得困难 资源限制 中小企业通常拥有有限的资金和人力资源 这使得数
  • Onvif协议学习:12、修改分辨率

    Onvif协议学习 12 修改分辨率 文章目录 Onvif协议学习 12 修改分辨率 1 原理简介 2 函数接口 3 编码流程 4 示例代码 原文链接 https blog csdn net benkaoya article details
  • fc2 php,fc2fans_club.py

    import re from lxml import etree need install import json import ADC function def getTitle htmlcode 获取厂商 print htmlcode
  • 简单看看TypeScript、C# 和 Delphi 这三种编程语言

    TypeScript C 和 Delphi 是三种不同的编程语言 它们都有自己的特点和适用领域 在本篇博客中 我们将对这三种语言进行比较和介绍 分析它们的共同点和区别 TypeScript 是由微软公司的 Anders Hejlsberg
  • xctf-supersqli

    xctf supersqli 堆叠注入 一 堆叠注入 本次采用的靶场xctf的supersqli 一 堆叠注入 进入靶场 发现一个提示框 先随便点一下提交 发现输出了些东西 输入1 判断存在注入点 分别输如1 1 1 2 判断为单引号注入
  • MatConvNet 框架的mnist实例

    mnist 手写是被 cnn mnist m 主函数代码 function net info cnn mnist varargin 主函数 cnn mnist 功能 1 初始化CNN 2 设置各项参数 3 读取和保存数据集 4 初始化tra
  • (图像变换)Python-opencv,(批处理笛卡尔坐标系,也就是平时咱们看到的正常图片)二维彩色图像转化为极坐标系下的图像

    这个其实代码量不大 但对于我这个啥也编不出来的废柴来说我觉得真的好不容易 历经两天的痛苦折磨 终于完成了 下面进入正题 昨天我找了一天代码 然后挑挑拣拣也就找到一篇还是c 的图像极坐标化处理 代码如下 include
  • linux查看显卡型号p4卡或者t4卡_NVIDIA Tesla GPU系列P4、T4、P40以及V100参数性能对比...

    NVIDIA Tesla系列GPU适用于高性能计算 HPC 深度学习等超大规模数据计算 Tesla系列GPU能够处理解析PB级的数据 速度比使用传统CPU快几个数量级 NVIDIA Tesla GPU系列P4 T4 P40以及V100是Te
  • substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。

    tableData sbsj result sbsj substr 0 result sbsj indexOf
  • 使用JDBC操作数据库

    导包 数据库驱动包 msql connector java 1 掌握JDBC连接数据库 1 1 JDBC 流程图 mermaid svg oRZnGw9oql7DhsSu label font family trebuchet ms ver
  • 数据结构与集合之(1)ArrayList 与 Arrays

    数据结构是指逻辑意义上的数据组织方式及其处理方式 从 直接前驱 和 直接后继 个数的维度来看 大体可以将数据结构分为以下四类 1 线性结构 0 至 1 个直接前驱 和 直接后继 线性结构包括 顺序表 链表 栈 队列等 2 树结构 0 至 1
  • 【python数据分析(22)】Matplotlib库绘图的图表样式参数(linestyle、marker、color、style)

    1 linestyle线条参数 默认是导入了相关的库 这里的代码就不再显示了 solid line style 实线样式 dashed line style 虚线样式 dash dot line style 虚点线样式 dotted lin
  • TP6框架--CRMEB学习笔记:项目初始化+环境配置

    这里给大家分享我在网上总结出来的一些知识 希望对大家有所帮助 最近在研究一个基于TP6的框架CRMEB 这里分享下我的开发心得 首先要获取原始项目文件 这里是git地址 https gitee com ZhongBangKeJi CRMEB
  • websocket协议

    WebSocket是一种在Web应用程序中实现实时双向通信的协议 一种在单个TCP连接上进行全双工通信的协议 它使得客户端和服务器之间的数据交换变得更加简单 允许服务端主动向客户端推送数据 WebSocket 与 HTTP 2 一样 其实都
  • C++-必知必会_类模板成员特化(条款48)

    类模板成员特化 再提醒一下 虽然模板的特化和类的派生之间没有任何关 系 但在特化模板的时候 不妨借鉴一下派生的精神 也就意味 着一个完全特化或局部特化通常必须重新实现 主模板具备的 所有能力 例1 主模板 template lt typen
  • Mariadb数据库之主从复制同步配置实战

    Mariadb数据库之主从复制同步配置实战 一 环境规划 二 Mariadb的主从复制介绍 1 主从复制简介 2 半同步复制介绍 3 主从复制原理图 三 安装Mariadb 1 配置yum仓库 2 检查yum仓库 3 安装mariadb 4
  • 八、RISC-V SoC外设——GPIO接口 代码讲解

    前几篇博文中注释了RISC V的内核CPU部分 从这篇开始来介绍RISC V SoC的外设部分 另外 在最后一个章节中会上传额外添加详细注释的工程代码 完全开源 如有需要可自行下载 目录 0 RISC V SoC注解系列文章目录 1 结构