【最通用版FPGA 实现 SPI 驱动】

最近研究了一下SPI协议的FPGA实现,发现网上很多大佬分享的方法都是针对某一特定的flash芯片或者某一传感器芯片来设计电路结构的。所以想根据SPI(Serial Peripheral Interface)的基本通讯协议实现一个通用版的SPI Master驱动。SPI在嵌入式领域是一个很成熟且应用非常广泛的通信协议,其通信协议的具体内容在此不再赘述。
SPI协议有四种模式,0模式和3模式应用最为广泛,本文以0模式为基础设计FPGA电路结构。
在这里插入图片描述
如上图所示,SPI通信可以理解为主机和从机之间两个双向移位寄存器之间的数据交换,所以每个时钟节拍数据的发送和接收都是同时进行的。

模块结构

一个模块的设计首先要站在用户的角度去考虑,比如其他开发者调用该模块的时候应该如何使用,这样就比较容易确定模块的输入输出信号。本模块设计的特点在于可以由用户自己定义每次数据传输的长度。所以调用该模块接收数据时,要事先知道所对接的从机的数据什么时候发送过来,根据byte_cnt 和bit_cnt来定位接收到的数据。
在这里插入图片描述

输入信号:

  • clk 该模块的驱动时钟,根据需要提供
  • rst_n 模块复位信号,低电平有效
  • spi_start 模块唤醒信号,只允许cs为高定平时提供一个时钟宽度的脉冲
  • user_data 要发送的数据
  • data_width 本次唤醒要发送的数据宽度,代表要发送多少个字节
  • miso 主机输入从机输出

输出信号:

  • bit_cnt 数据传输位计数器
  • byte_cnt 数据传输字节计数器
  • cs 片选信号
  • mosi 主机输出,从机输入
  • rev_data 模块接收到的数据

verilog代码实现

驱动设计代码

module spi_drv (input              clk,          //50Minput              rst_n,input              spi_start,input [31:0]       data_width,input [7:0]        user_data,output reg [2:0]   bit_cnt,output reg [31:0]  byte_cnt,output reg [7:0]   rev_data,output             sck,   //spi通信同步时钟output             cs,    //片选信号output             mosi,  // master output slave inputinput              miso   // master input slave output
);wire       spi_en;   //模块使能信号
reg        spi_run;  //模块状态寄存器
reg        spi_clk;  //sck时钟
reg [7:0]  sen_buf;  //输出缓冲寄存器
reg [7:0]  rev_buf;  //输入缓冲寄存器assign cs     = ~spi_run;
assign sck    = (spi_run == 1'b1) ? spi_clk : 1'b0;
assign mosi   = (spi_run == 1'b1) ? sen_buf[7 - bit_cnt] : 1'b0;
assign spi_en = spi_start & (~spi_run);always @(posedge clk or negedge rst_n) beginif(!rst_n)spi_run <= 1'b0;else if(spi_en == 1'b1)spi_run <= 1'b1;else if((byte_cnt == data_width - 1'b1)&&(bit_cnt == 3'd7)&&(spi_clk == 1'b1))spi_run <= 1'b0;elsespi_run <= spi_run;
endalways @(posedge clk or negedge rst_n) beginif(!rst_n)sen_buf <= 8'd0;else if(spi_en == 1'b1)sen_buf <= user_data;else if((bit_cnt == 8'd7)&&(spi_clk == 1'b1))sen_buf <= user_data;elsesen_buf <= sen_buf;
endalways @(posedge clk or negedge rst_n) beginif(!rst_n)spi_clk <= 1'b0;else if(spi_run == 1'b1)spi_clk <= ~spi_clk;elsespi_clk <= 1'b0;
endalways @(posedge clk or negedge rst_n) beginif(!rst_n)bit_cnt <= 3'd0;else if(spi_run == 1'b1)beginif((bit_cnt == 3'd7)&&(spi_clk == 1'b1))bit_cnt <= 3'd0;else if(spi_clk == 1'b1)bit_cnt <= bit_cnt + 1'b1;elsebit_cnt <= bit_cnt;endelsebit_cnt <= 3'd0;
endalways @(posedge clk or negedge rst_n) beginif(!rst_n)byte_cnt <= 32'd0;else if(spi_run == 1'b1)beginif((byte_cnt == data_width - 1'b1)&&(bit_cnt == 3'd7)&&(spi_clk == 1'b1))byte_cnt <= 32'd0;else if((bit_cnt == 3'd7)&&(spi_clk == 1'b1))byte_cnt <= byte_cnt + 1'b1;elsebyte_cnt <= byte_cnt;endelsebyte_cnt <= 32'd0;
endalways @(posedge spi_clk or negedge rst_n) beginif(!rst_n)rev_buf <= 8'd0;else if(spi_run == 1'b1)rev_buf <= {rev_buf[6:0],miso};elserev_buf <= 8'd0;
endalways @(posedge clk or negedge rst_n) beginif(!rst_n)rev_data <= 8'd0;else if(spi_run == 1'b1)beginif((bit_cnt == 3'd7)&&(spi_clk == 1'b1))rev_data <= rev_buf;elserev_data <= rev_data;endelserev_data <= 8'd0;
endendmodule

仿真激励代码

`timescale 1ns/1nsmodule spi_drv_tb();parameter T = 10;parameter [7:0] CMD     = 8'b1010_0000;
parameter [7:0] REG_ADR = 8'b0000_0001;reg [7:0] reg_value0;
reg [7:0] reg_value1;reg clk;
reg rst_n;
reg spi_start;reg [31:0] data_width;
reg [7:0]  user_data;wire [2:0]  bit_cnt;
wire [31:0] byte_cnt;reg miso;initial beginclk         <= 1'b0;rst_n       <= 1'b0;spi_start   <= 1'b0;data_width  <= 32'd4;user_data   <= 8'd0;miso 	<= 1'b0;reg_value0  <= 8'b1010_1010;reg_value1  <= 8'b1010_1010;
endinitial begin#(2*T) rst_n <= 1'b1;
endinitial begin#(5*T) spi_start <= 1'b1; #(2*T) spi_start <= 1'b0;
endalways @(negedge clk)beginif(spi_start)user_data <= CMD;else if((bit_cnt == 3'd7)&&(byte_cnt == 32'd0)) user_data <= REG_ADR;else if((bit_cnt == 3'd7)&&(byte_cnt == 32'd1)) user_data <= 8'd0;else if((bit_cnt == 3'd7)&&(byte_cnt == 32'd2)) user_data <= 8'd0;else if((bit_cnt == 3'd7)&&(byte_cnt == 32'd3)) user_data <= 8'd0;elseuser_data <= user_data;
endalways @(*) beginif(byte_cnt == 32'd2)miso <= reg_value0[7 - bit_cnt];else if(byte_cnt == 32'd3)miso <= reg_value1[7 - bit_cnt];elsemiso <= 8'd0;
endspi_drv spi_drv_m0(.clk(clk),.rst_n(rst_n),.spi_start(spi_start),.data_width(data_width),.user_data(user_data),.bit_cnt(bit_cnt),.byte_cnt(byte_cnt),.miso(miso)
);always #T clk = ~clk;endmodule

Modelsim仿真结果

在这里插入图片描述

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

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

相关文章

同源策略与跨域

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 不论个人练习还是实际开…

HR看好的字符函数和字符串处理函数!!!

本篇会加入个人的所谓‘鱼式疯言’❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的&#xff0c;可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 前言 在本篇…

mybatis整合(手动添加jar包方式)

操作步骤 创建数据库 建立user表 放入数据 1、创建javaweb工程并添加Jar包 用到的jar包 junit 用于测试 mybatis框架&#xff1a;mybatis-3.5.9.jar mysql数据库&#xff1a;mysql-connector-java-8.0.28.jar 2、添加MyBatis核心配置文件 <?xml version"1.0"…

Leetcode刷题详解——乘积为正数的最长子数组长度

1. 题目链接&#xff1a;1567. 乘积为正数的最长子数组长度 2. 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数组的长度。 一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。 请你返回乘积为正数的最长子数组长度。 示…

什么是结构化数据?哪些OCR软件可将图片文字转为结构化数据?

结构化数据是指按照一定的数据模型组织和存储的数据&#xff0c;具有明确的数据类型和数据关系&#xff0c;并且可通过计算机程序进行处理和分析。这种数据通常存储在定义明确的模式中&#xff0c;例如数据库&#xff0c;采用表格的形式存储&#xff0c;每个数据项都有特定的字…

Mover Creator 用户界面

1 “开始”对话框 首次打开 Mover Creator 时&#xff0c;出现的第一个页面是“开始”对话框&#xff0c;如下所示。从这里开始&#xff0c;用户可以选择开始设计飞机、武器或发动机。在上述每种情况下&#xff0c;用户都可以创建新模型或编辑现有模型。 1.1 新建模型 如果用…

Apache Doris 详细教程(二)

5、doris的查询语法 5.1、doris查询语法整体结构 SELECT [ALL | DISTINCT | DISTINCTROW ] -- 对查询字段的结果是否需要去重&#xff0c;还是全部保留等参数 select_expr [, select_expr ...] -- select的查询字段 [FROM table_references [PARTITION…

94基于matlab的蚁群算法 (ACO) 对付的图像边缘检测问题

基于matlab的蚁群算法 (ACO) 对付的图像边缘检测问题。提出基于蚁群算法的边缘检测方法是能够建立一个信息素矩阵表示提出了一种在图像每个像素位置的边缘信息根据大量的蚂蚁的运动有哪些派去在图像上移动。此外&#xff0c;运动这些蚂蚁是由图像的局部变化驱动强度值。数据可更…

U1编译概述

文章目录 基本概念定义一些概念 编译流程词法分析语法分析语义分析、生成中间代码中间代码 代码优化生成目标程序五个阶段中都需要做的两件事符号表管理出错处理 总结 其他概念多层中间表示和遍&#xff08;PASS&#xff09;三端模式课程概述 基本概念 定义 用高级语言编制的…

【Java 基础】18 I/O流

文章目录 1.基本概念2.字节流3.字符流4.标准输入输出5.最佳实践 I/O流&#xff08;Input/Output 流&#xff09;是计算机程序中不可或缺的一部分&#xff0c; 往大了说所有的操作都是IO。Java 提供了强大而灵活的 I/O 框架&#xff0c;支持各种数据的 读取和 写入操作。 1.基…

45 - 多线程性能优化常见问题

1、使用系统命令查看上下文切换 上下文切换常见的监测工具 1.1、Linux 命令行工具之 vmstat 命令 vmstat 是一款指定采样周期和次数的功能性监测工具&#xff0c;我们可以使用它监控进程上下文切换的情况。 vmstat 1 3 命令行代表每秒收集一次性能指标&#xff0c;总共获取 …

【JavaSE】:String(二):深入String

深入String 一.字符串的存储二.字符串的不可变性三.字符串修改四.StringBuilder和StringBuffer 一.字符串的存储 我们知道双引号里的数据都是字符串常量&#xff0c;储存在字符串常量池当中。 例子 直接使用是比较地址。字符串常量池有一个特点&#xff1b;它会先检查该常量是否…

LLM-Intro to Large Language Models

LLM some LLM’s model and weight are not opened to user what is? Llama 270b model 2 files parameters file parameter or weight of neural networkparameter – 2bytes, float number code run parameters(inference) c or python, etcfor c, 500 lines code withou…

中介者模式 rust和java的实现

文章目录 中介者模式介绍实现javarustrust仓库 中介者模式 中介者模式&#xff08;Mediator Pattern&#xff09;又被称为 调停者模式 。 它定义了一个中介对象来封装一系列对象之间的交互关系。 中介者使各个对象之间不需要显式地相互引用&#xff0c;从而使耦合性降低&#…

计算机网络扫盲(4)——时延

一、概述 在这里&#xff0c;我们考虑分组交换网的情况&#xff0c;因特网可以被看成是一种基础设施&#xff0c;该基础设施为运行在端系统上的分布式应用提供服务。在理想情况下&#xff0c;我们希望因特网服务能够在任意两个端系统之间随心所欲地移动数据而没有任何数据地丢失…

韩语图片文字如何转为纯文本?

如何将上图为韩语的图片转为文本文件&#xff1f;这个需要用到OCR程序&#xff0c;操作方法如下&#xff1a; 一、打开金鸣识别网站。 二、点击“点击添加图片/PDF”&#xff0c;将待识别的图片添加到列表。 三、识别模块点选“通用文字”&#xff0c;输出格式选择“纯文本输出…

陀螺仪LSM6DSV16X与AI集成(1)----轮询获取陀螺仪数据

陀螺仪LSM6DSV16X与AI集成.1--轮询获取陀螺仪数据 概述视频教学样品申请通信模式管脚定义IIC通信模式速率生成STM32CUBEMX串口配置IIC配置CS和SA0设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置设置量程和速率配置过滤链轮询读取数据主程序演示 概述 本文将介绍如何使…

PPT设置背景颜色

问题描述&#xff1a;PPT如何设置背景颜色&#xff1f; 问题解决&#xff1a;设计→设置背景格式→颜色→蓝色&#xff08;最好选择看着比较舒服的颜色&#xff09;

如何通过缺口发现短线机会?

一、认识缺口形态 新手一开始接触技术分析&#xff0c;可能都以为“缺口”是一个很高深的技术形态。其实缺口很简单&#xff0c;就是K线图中的价格空白区域&#xff0c;也就是股价上涨或下跌的过程中&#xff0c;跳过了这个价格。根据跳空的方向不同&#xff0c;缺口可以分为向…

AArch64中的虚拟化

运行在EL2或更高级别的软件具有对虚拟化的几个控制权限&#xff1a; • 第二阶段翻译&#xff08;Stage 2 translation&#xff09; • EL1/0指令和寄存器访问trapping • 虚拟异常生成 非安全状态和安全状态下的异常级别&#xff08;ELs&#xff09;如下图所示&#xff1a; 在…