FPGA|Verilog-自己写的SPI驱动

news/2025/3/11 11:03:26/

1. 状态变量设置

localparam IDLE = 6'b00_0001;

localparam GEN_DCLK = 6'b00_0010;

localparam ACK = 6'b00_0100;

这里采用状态独热编码(One-Hot Encoding)

在 FPGA 开发中,独热编码能简化组合逻辑、提升时序性能

2. 两段式状态机,明晰跳转条件

3. 采用end_cnt_clk和end_cnt_num结合的方式方便时序控制,准确进行clk_div的分频

4. 仿真效果展示

仿真上板通过 

 5. 全部代码

module spi_driver1(input                               clk                        ,input                               rst                        ,input                               MISO                       ,output reg                          MOSI                       ,// 1input                               CPOL                       ,input                               CPHA                       ,input              [   7:0]         data_in                    ,output reg         [   7:0]         data_out                   ,//input              [  15:0]         clk_div                    ,output                              nCS                        ,// 1input                               nCTRL                      ,output reg                          DCLK                       ,// 1input                               wr_req                     ,output                              wr_ack                      // 1
);localparam IDLE     = 6'b00_0001;
localparam GEN_DCLK = 6'b00_0010;
localparam ACK      = 6'b00_0100;reg [5:0]cstate;
reg [5:0]nstate;reg [25:0]cnt_clk;
reg [7:0]cnt_num;
reg [7:0]num;wire [15:0]MAX_CNT = clk_div;
wire add_cnt_clk = cstate != IDLE;
wire end_cnt_clk = add_cnt_clk && cnt_clk == MAX_CNT - 1;
wire add_cnt_num = end_cnt_clk;
wire end_cnt_num = add_cnt_num && cnt_num == num - 1;
assign nCS = nCTRL;
assign wr_ack = cstate == ACK && end_cnt_clk;always @(posedge clk or posedge rst) beginif(rst)begincnt_clk <= 26'd0;end else if(add_cnt_clk)beginif(end_cnt_clk)cnt_clk <= 26'd0;else cnt_clk <= cnt_clk + 26'd1;end 
endalways @(posedge clk or posedge rst) beginif(rst)begincnt_num <= 8'd0;end else if(add_cnt_num)beginif(end_cnt_num)cnt_num <= 8'd0;else cnt_num <= cnt_num + 8'd1;end 
endreg [8*20-1:0]state_name;
always @(*) begincase (cstate)IDLE    :begin num = 1;  state_name = "IDLE    "; endGEN_DCLK:begin num = 8;  state_name = "GEN_DCLK"; endACK     :begin num = 1;  state_name = "ACK     "; enddefault :begin num = 1;  state_name = "IDLE    "; endendcase
endwire IDLE_GEN_DCLK  = (cstate == IDLE)      && wr_req           ;
wire GEN_DCLK_ACK   = (cstate == GEN_DCLK)  && end_cnt_num      ; 
wire ACK_IDLE       = (cstate == ACK)       && end_cnt_num      ; always @(posedge clk or posedge rst) beginif(rst)beginDCLK <= (CPOL == 1'b0)?1'b0:1'b1;end else if(cstate == GEN_DCLK && (cnt_clk == MAX_CNT/2 - 1 || cnt_clk == MAX_CNT - 1))beginDCLK <= ~DCLK;end
endreg flag_mosi;
always @(posedge clk or posedge rst) beginif(rst)beginMOSI <= 1'b0;flag_mosi <= 1'b0;end else if(cstate == GEN_DCLK)beginif(CPOL == 1'b0 && cnt_clk == 0)beginMOSI <= data_in[7 - cnt_num];flag_mosi <= 1'b1;end else if(CPOL == 1'b1 && cnt_clk == MAX_CNT/2 - 1)beginMOSI <= data_in[7 - cnt_num];flag_mosi <= 1'b1;end else begin flag_mosi <= 1'b0;endend else if(cstate == ACK)beginMOSI <= 1'b0;flag_mosi <= 1'b0;end 
endreg flag_data_out;
always @(posedge clk or posedge rst) beginif(rst)begindata_out <= 8'd0;flag_data_out <= 1'b0;end else if(cstate == GEN_DCLK)beginif(CPOL == 1'b0 && cnt_clk == MAX_CNT/2 - 1)begindata_out <= {data_out[6:0],MISO};flag_data_out <= 1'b1;end else if(CPOL == 1'b1 && cnt_clk == MAX_CNT - 1)begindata_out <= {data_out[6:0],MISO};flag_data_out <= 1'b1;end else beginflag_data_out <= 1'b0;endend else beginflag_data_out <= 1'b0;end
endalways @(posedge clk or posedge rst) beginif(rst)begincstate <= IDLE;end else begincstate <= nstate;end
endalways @(*) begincase (cstate)IDLE    :if(IDLE_GEN_DCLK)nstate = GEN_DCLK;else nstate = cstate;GEN_DCLK:if(GEN_DCLK_ACK)nstate = ACK;else nstate = cstate;ACK     :if(ACK_IDLE)nstate = IDLE;else nstate = cstate;default :nstate = IDLE;endcase
endendmodule


http://www.ppmy.cn/news/1578326.html

相关文章

3.3.5 VO-O语法- 高级语法

VO语言还提供了一些个性化的高级语法特性&#xff0c;这些语法特性有别于传统的编程语言。但可以更好的帮助开发者实现高效、稳定的生产级数据流程。 调度运行 在现行的编程语言中&#xff0c;调度运行不在语法表示范围之内。这属于具体的代码实现逻辑。但在VO语言设计中&…

Spring Cloud之远程调用OpenFeign参数传递

目录 OpenFeign参数传递 传递单个参数 传递多个参数 传递对象 传递JSON OpenFeign参数传递 传递单个参数 服务提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

国产麒麟操作系统日常操作--系统管理

国产麒麟操作系统日常操作–系统管理 一、uname命令–显示系统内核信息 uname命令来自英文词组UNIX name的缩写&#xff0c;其功能是查看系统主机名、内核及硬件架构等信息。 1.1 语法格式 参数功能-a ,-- all输出系统所有信息-s, --kernel-name输出内核名称-n, --nodename…

C51串口初始化及波特率设置

/*** brief 串口初始化&#xff0c;4800bps12.000MHz* param 无* retval 无*/ void UART_Init() {SCON0x40;PCON | 0x80;TMOD & 0x0F; //设置定时器模式TMOD | 0x20; //设置定时器模式TL1 0xF3; //设定定时初值TH1 0xF3; //设定定时器重装值ET1 0; //禁止定时器1…

2025年建筑行业安全员证报考条件

建筑安全员报考相关信息如下&#xff1a; 报考条件 年龄&#xff1a;年满 18 周岁&#xff0c;一般不超过 60 周岁&#xff0c;法定代表人除外。 学历&#xff1a; 安全员 A 证&#xff1a;建筑施工企业主要负责人应为大专以上学历&#xff0c;除企业法人外&#xff0c;其他…

C++设计模式中的单例模式:从原理、应用、实践指南与常见问题和解决方案深度解析

一、单例模式的核心原理 1.1 设计思想与定义 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;其核心目标是确保一个类仅有一个实例存在&#xff0c;并提供该实例的全局访问入口。单例模式就像公司里唯一的总经理——无论哪个部门需要决策…

【性能测试】Jmeter详细操作-小白使用手册(2)

本篇文章主要介绍Jmeter中如何使用 JSON断言、同步定时器、事务控制器、CSV数据文件设置、HTTP Cookie管理器 目录 一&#xff1a;JSON断言 1&#xff1a;正确结果展示 2&#xff1a;错误结果展示 3&#xff1a;JSON配置 &#xff08;1&#xff09;Additionally assert …

程序设计语言基础知识概述

程序设计语言是用于书写计算机程序的符号语言&#xff0c;在计算机领域中扮演着关键角色。 一、语言发展与分类 从1957 年的FORTRAN开始&#xff0c;程序设计语言不断演化。语言可分为低级语言和高级语言。前者包括机器语言和汇编语言&#xff0c;与机器指令接近&#xff0c;…