当前位置: 首页 > news >正文

FPGA实现SPI协议

SPI接口

1 简单的设计模块1

在这里插入图片描述
首先简单的想一下这个模块应该怎么设计。
拿到这个小题目你的思路是怎么样的呢?很多时候靠经验设计,并没有一个顺序的思路。

在这里插入图片描述
六步法:
第一步:输入输出波形的画出
在这里插入图片描述

第二步:画出计数器结构(搞清楚数的是什么东西)
在这里插入图片描述
cnt表示上一个时钟数到的结果。数x下,通用表达式:add_cnt&&cnt==x-1;

第三步:确认计数器加1条件(数什么)和结束条件(数多少个),注意先考虑加1,在考虑结束条件;
我们计数器cnt数的是什么呢?dout==1的时钟个数,cnt要数10个(10是功能要求来的)

第四步:确认其他信号的变化条件(dout 变化点,即0变1,1为0的条件)
dout由0变1 的条件是什么?是en1;
dout由1变0的条件是? dout
1的时钟个数为10

cnt add_cnt:dout ==1
cnt 数多少:10// 计数器模板
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		cnt <= 0;
	end
	else if(add_cnt) begin
		if(end_cnt)
			cnt <= 0;
		else
			cnt <= cnt + 1;
	end
end

assign add_cnt = dout == 1;   // 加1的条件
assign end_cnt = add_cnt && cnt == 10-1;  // 数10下



dout == 1 : en == 1
dout == 0 : 数到10个

always@(posedge clk or negedge rst_n) begin
	if(rst_n==1'b0) begin
		dout <= 0;
	end
	else if(en == 1) begin     // dout什么时候拉高
		dout <= 1;
	end
	else if (end_cnt) begin  //(add_cnt && cnt == 10-1) begin    // 数10下之后dout拉低
		dout <= 0;
	end
end

第五步:写出计数器代码(always除了名字外不能改变,加1条件即是要数什么东西,结束条件要记住格式后)

2 简单模块设计2

在这里插入图片描述
对于这种状态还是数cnt, 可以这种思考。
在这里插入图片描述
也可以这样计数。这是正确的计数方式
在这里插入图片描述
第一步:画出输入输出波形
第二步:画出计数器结构

cnt0的加1条件: flag == 1 ,加一个信号把flag
cnt0 要数多少:3个

cnt1的加1条件:end_cnt0  // 
cnt1 要数多少个:3个

flag >1: en == 1
flag >0: end_cnt1

dout>1: add_cnt0 && cnt0 == 1-1 // 当cnt0 数一个的时候拉高
dout>0: end_cnt0 (add_cnt0 && cnt0 == 3-1)

然后就填填空啦!!!!!!

3 SPI通信协议

3.1 SPI通信协议原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CS 选择工作模式
DIN选择通道地址
DOUT 输出给FPGA

在这里插入图片描述

在这里插入图片描述

module SPI(
	input clk,
	input rst_n,
	input start,
	input [2:0]channel,

	//  ADC128s022
	input DOUT,
	output reg SCLK,
	output reg DIN,
	output reg CS_N,
	
	output reg done,
	output [11:0] data.
	

);

	reg en;
	reg [2:0] r_channel;
	// r_channel 使channel的信号稳定
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			r_channel <= 'd0;
		else if(start)
			r_channel <= channel;
		else
			r_channel <= r_channel;
	end

	// 转换使能信号
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			en <= 1'b0;
		else if(start)
			en <= 1'b1;
		else if(done)
			en <= 1'b0;
		else
			en <= en;
	end

	reg [4:0] cnt;
	reg cnt_flag;
	reg [5:0]SCLK_CNT;
	
	// cnt 的变化
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			cnt <= 'd0;
		else if(en) begin
			if(cnt == 'd10)
				cnt <= 'd0;
			else
				cnt <= cnt + 1'b1;
		end
		else
			cnt <= 'd0;
	end

	// cnt flag 
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			cnt_flag <= 1'b0;
		else if(cnt == 'd10)
			cnt_flag <= 1'b1;
		else
			cnt_flag <= 1'b0;
	end

	//  sclk_cnt
	always@	(posedge clk or negedge rst_n) begin
		if(!rst_n)
			sclk_CNT <= 'd0;
		else if(en) begin
			if(SCLK_CNT == 'd33)
				SCLK_CNT <= 'd0;
			else if(cnt_flag)
				SCLK_CNT <= SCLK + 1'b1;
			else
				SCLK_CNT <= SCLK_CNT;
		end
		else
			SCLK_CNT <= 'd0;
	end
	
	reg [11:0] r_data;
	// ============================================
	always@(posedge clk negedge rst_n) begin
		if(!rst_n) begin
			SCLK <= 1'b1;
			CS_N <= 1'b1;
			DIN <= 1'b1;
		end
		else if(en) begin
			case(SCLK_CNT)
				6'd0:begin CS_N <= 1'b0; end
				6'd1:begin SCLK <= 1'b0;DIN <= 1'b0; end
				6'd2:begin SCLK <= 1'b1; end
				6'd3:begin SCLK <= 1'b0; end
				6'd4:begin SCLK <= 1'b1; end
				6'd5:begin SCLK <= 1'b0; DIN <= r_channel[2];end
				6'd6:begin SCLK <= 1'b1; end
				6'd7:begin SCLK <= 1'b0; DIN <= r_channel[1];end
				6'd8:begin SCLK <= 1'b1; end
				6'd9:begin SCLK <= 1'b0; DIN <= r_channel[0];end
				6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6d'22,6d'24,6'd26,6'd28,6'd30,6'd32:
				begin SCLK <= 1'b1; r_data <= {r_data[10:0], DOUT}; end
				6'd11,6'd13,6'd15,6'd17,6'd19,6'd21,6d'23,6d'25,6'd27,6'd29,6'd31,6'd33:
				begin SCLK <= 1'b0;end
				6'd33:begin CS_N <= 1'b1;end
				default: begin CS_N <= 1'b1;end				
				
				
			endcase
		end
		else begin
			SCLK <= 1'b1;
			CS_N <= 1'b1;
			DIN <= 1'b1;			
		end

	end

	//   done 信号
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			done <= 1'b0;
		else if(SCLK_CNT == 'd33)
			done <= 1'b1;
		else
			done <= 1'b0;
	end

	//  data 信号
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n)
			data <= 'd0;
		else if(SCLK_CNT == 'd33)
			data <= r_data;
		else
			data <= data;
	end


endmodule
`timescale 1ns/1ns
module SPI_tb;

	reg clk;
	reg rst_n;
	reg start;
	reg [2:0] channel;

	wire SCLK;
	DIN;
	CS_N;
	DOUT;
	
	wire done;
	wire [11:0]data;
	
	SPI SPI_inst(
		.clk(clk),
		.rst_n(rst_n),
		.start(start),
		.channel(channel),

		.SCLK(SCLK),
		.DIN(DIN),
		.CS_N(CS_N),
		.DOUT(DOUT),
		.done(done),
		.data(data)

	);
	
	initial clk = 1'b1;
	alwayss#10 clk = ~clk;
	initial begin
		rst_n = 1'b0;
		channel = 'd0;
		start = 1'b0;
		DOUT = 1'b0;
	
		
	end

	endmodule

3.1 SPI原理2

SPI是微控制器和外围IC 如传感器 adc 和dac 移位寄存器、SRAM等。之间使用最广泛的接口之一。SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿同步。主机和从机可以同时传输数据。SPI接口可以是三线式或四线。

在这里插入图片描述
CS 低电平有效
SPI的环形数据收发模式,SPI在收发数据的原理很简单,就是两个移位寄存器,待发送的数据首先写入din_buf 中缓存,需要发送的时候输入进data_shift 中,通过移位的方式发送高位数据,同时接受到的数据存入低位,写满时存入到dout_buf 中,再由dout_buf 写入内部总线。
在这里插入图片描述
代码放到:https://download.csdn.net/download/qq_30093417/86757879

相关文章:

  • 2022年金砖国家职业技能大赛(决赛)网络空间安全赛项 | 浙江赛区选拔赛 任务书
  • 第8章 聚合函数
  • Turbot4机器人入门教程-应用-读取图片文件并发布图像话题
  • Redis的性能优化一些方案
  • 你可能不知道的CSS特征查询
  • 【pygame】之小球基础
  • C++ Reference: Standard C++ Library reference: C Library: cstdarg: va_arg
  • Eclipse技巧(一):快速定位文件的层级位置 | 快速查找文件在工程根目录的位置
  • 汇编笔记[04][内存寻址方式]
  • 开发行业门槛越来越高,Android 开发者的未来之路到底在哪里?
  • Java如何为函数定义一个可变长度的参数呢?
  • 【数字设计】哲库科技_2023届_笔试面试题目分享
  • Java中this关键字的相关说明
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • ARM 指令流水线
  • 深入了解以太坊
  • [译] React v16.8: 含有Hooks的版本
  • create-react-app项目添加less配置
  • CSS3 变换
  • ES6简单总结(搭配简单的讲解和小案例)
  • flask接收请求并推入栈
  • Java读取Properties文件的六种方法
  • JDK 6和JDK 7中的substring()方法
  • Markdown 语法简单说明
  • Python 基础起步 (十) 什么叫函数?
  • spring + angular 实现导出excel
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 服务器之间,相同帐号,实现免密钥登录
  • 记一次用 NodeJs 实现模拟登录的思路
  • 聊聊redis的数据结构的应用
  • 你真的知道 == 和 equals 的区别吗?
  • 前端技术周刊 2019-02-11 Serverless
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 小程序开发中的那些坑
  •  一套莫尔斯电报听写、翻译系统
  • #Z2294. 打印树的直径
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (LeetCode C++)盛最多水的容器
  • (八)Spring源码解析:Spring MVC
  • (六)vue-router+UI组件库
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (强烈推荐)移动端音视频从零到上手(上)
  • (三)mysql_MYSQL(三)
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (学习日记)2024.02.29:UCOSIII第二节
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • ... 是什么 ?... 有什么用处?
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .md即markdown文件的基本常用编写语法
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net开发引用程序集提示没有强名称的解决办法