当前位置:   article > 正文

FPGA实现SPI协议_zynq7035 fpga实现spi通信

zynq7035 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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

第五步:写出计数器代码(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)

然后就填填空啦!!!!!!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
`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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/829511
推荐阅读
相关标签
  

闽ICP备14008679号