FPGA驱动OLED Verilog代码 (一)------ SPI写模块

一、概述:

        我本身没有很仔细的去学习SPI的时序,而是参照了之前STM32驱动OLED时模拟的时序来写的,其中写一个字节的时序如下

/*************************************************************************/
/*函数功能: 通过SPIO软件模拟SPI通信协议,向模块(SSD1306)写入一个字节                                  */
/*入口参数:																															 */	
/*data:要写入的数据/命令																		 */				
/*cmd :数据/命令标志 0,表示命令;1,表示数据;                   */
/*************************************************************************/
void SPI_WriteByte(unsigned char data,unsigned char cmd)
{
	unsigned char i=0;
	OLED_DC =cmd;
	OLED_CLK=0;
	for(i=0;i<8;i++)
	{
		OLED_CLK=0;
		if(data&0x80)OLED_MOSI=1; //从高位到低位
		else OLED_MOSI=0;
		OLED_CLK=1;
		data<<=1;
	}
	OLED_CLK=1;
	OLED_DC=1;
}

二、Verilog代码编写

参考上述的写时序,使用Verilog代码去实现

module spi_writebyte(
	input clk,			//时钟信号 1m的时钟
	input rst_n,		//复位信号 按键复位
	input ena_write,	//spi写使能信号
	input [7:0]data,	//spi写的数据
	output reg sclk,	//oled的时钟信号(d0)
	output reg mosi,	//oled的数据信号(d1)
	output write_done //spi写完成信号
);

parameter S0=0,S1=1,S2=2,Done=3;
reg[1:0] state,next_state;
reg[3:0] cnt;		//写数据的位计数器

//状态机下一个状态确认
always @(*) begin
	if(!rst_n) begin
		next_state <= 2'd0;
	end
	else begin
		case(state)
			S0: //等待写使能信号
				next_state = ena_write ? S1 : S0;
			
			S1: 
				next_state = S2;
			
			S2: //从s1到s2的位置cnt才加1所以需要cnt到8再到下一个状态
				next_state = (cnt == 4'd8) ? Done : S1;
			
			Done://这个状态主要用来产生done信号输出
				next_state = S0;
			
		endcase
	end
end

//赋值和状态转换分开
//解决reg输出Latch的问题
always @(posedge clk,negedge rst_n) begin
	if(!rst_n) begin
		sclk = 1'b1;
		mosi = 1'b0;
	end
	else begin
		case(state)
			S0: begin//等待写使能信号
				sclk = 1'b1;
				mosi = 1'b0;
			end
			S1: begin
				sclk = 1'b0;
				mosi = data[3'd7-cnt] ? 1'b1 : 1'b0;
			end
			S2: begin//从s1到s2的位置cnt才加1所以需要cnt到8再到下一个状态
				sclk = 1'b1;
			end
		endcase
	end
end

//状态流转
always @(posedge clk,negedge rst_n) begin
	if(~rst_n)
		state <= S0;
	else
		state <= next_state;
end

//计数器计数
always @(posedge clk,negedge rst_n) begin
	if(~rst_n) begin
		cnt <= 4'd0;
	end
	else begin
		if(state == S1)
			cnt <= cnt + 1'b1;
		else if(state == S0)
			cnt <= 4'd0;
		else
			cnt <= cnt;
	end
end

assign write_done = (state==Done);//done信号输出
	
endmodule



测试用的testbench

`timescale 1ns/1ns //仿真单位为1ns,精度为1ns

module spi_writebyte_tb ( );

    //输出用wire
    //输入用reg
	reg clk;
	reg ena;
	reg rst;
	reg [7:0]data;
	wire sclk;
	wire mosi;
	wire done;
	
    //实例化模块
	spi_writebyte spi_writebyte_inst(
		.clk(clk),
		.ena_write(ena),
		.rst_n(rst),
		.data(data),
		.sclk(sclk),
		.mosi(mosi),
		.write_done(done)
	);
	
    //赋初始值
	initial begin
		#0 	clk = 0;//clk初始为0
				data = 8'b11010011;
				ena = 0;
				rst = 0;//先复位
				
		#20	ena = 1;//使能写
			rst = 1;//停止复位
	end
	
	always #5 clk = ~clk;//每5个时钟单位 clk取反一次
		
endmodule

仿真结果

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值