SMBus和I2C通信协议主机的Verilog实现

SMBus和I2C通信协议,verilog代码,SCL时钟频率50kHz。

SMBCLK对应SCL,IO_SDA对应SDA。

smbus_2.v

`timescale 1ns / 1ps
//
// Company: 
// Engineer: Mark Mo Swift
// 
// Create Date: 2022/10/24 21:25:07
// Design Name: 
// Module Name: smbus_2
// Project Name: IOBus
// Target Devices: 
// Tool Versions: Vivado 2018.2
// Description: 
// 
// Dependencies: crc_8.v
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module smbus_2
(
input sys_clk,                  //系统时钟500kHZ(2us)
input sys_rst_n,                //0硬件复位

output SMBCLK,                  //SMBus工作时钟50KHZ   
inout IO_SDA,                   //SMBus数据

input SMBus_en,					//SMBus使能 1使能
input rd_or_wr,					//读写标志:读1,写0	
input [6:0] device_addr,        //SMBus器件地址
input [15:0] SMBus_reg_addr,    //寄存器地址
input [15:0] SMBus_reg_data,    //寄存器数据

output reg [15:0] read_data,    //接收数据
output reg SMBus_done = 0       //SMBus完成标志  0完成
);
        
//---------------------------------------------
//分频部分
reg [2:0] cnt;              // cnt=0:SMBCLK上升沿,cnt=1:SMBCLK高电平中间,cnt=2:SMBCLK下降沿,cnt=3:SMBCLK低电平中间
reg [8:0] cnt_delay;        //100循环计数,产生iic所需要的时钟
reg cnt_pulse = 1;          //0 pulse
wire SMBCLK_en;             //低电平有效
reg SCL_org;                //不随外界影响的SCL方波
reg IDLE_con;                //处于IDLE状态,为高

always @ (posedge sys_clk or negedge sys_rst_n)
    if( !sys_rst_n ) cnt_delay <= 9'd0;
    else if( !cnt_pulse ) cnt_delay <= cnt_delay;
    else if( cnt_delay == 9'd99 ) cnt_delay <= 9'd0;    //计数到10us为SMBCLK的周期,即100KHz
    else cnt_delay <= cnt_delay + 1'b1;    //时钟计数

always @ (posedge sys_clk or negedge sys_rst_n) begin
        if( !sys_rst_n ) cnt <= 3'd5;
        else begin
            case ( cnt_delay )
                9'd24:    cnt <= 3'd1;    //cnt=1:SMBCLK高电平中间,用于数据采样
                9'd49:    cnt <= 3'd2;    //cnt=2:SMBCLK下降沿
                9'd74:    cnt <= 3'd3;    //cnt=3:SMBCLK低电平中间,用于数据变化
                9'd99:    cnt <= 3'd0;    //cnt=0:SMBCLK上升沿
                default: cnt <= 3'd5;
                endcase
            end                                       
      end

`define SMBCLK_LOW_MID    (cnt_delay == 9'd76)
`define SMBCLK_POS        (cnt==3'd0)        //cnt=0:SMBCLK上升沿
`define SMBCLK_HIG_MID    (cnt==3'd1)        //cnt=1:SMBCLK高电平中间,用于数据采样
`define SMBCLK_NEG        (cnt==3'd2)        //cnt=2:SMBCLK下降沿
`define SMBCLK_LOW_END    (cnt==3'd3)        //cnt=3:SMBCLK低电平中间,用于数据变化

assign SMBCLK_en = (~SMBus_en) | IDLE_con;       //处于不使能 或 IDLE状态 SCL不应当输出
assign SMBCLK = SCL_org | SMBCLK_en;

//产生SMBus所需要的时钟
always @ (posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n) SCL_org <= 1'b0;
    else if(cnt_delay == 9'd01) SCL_org <= 1'b1;
    else if(cnt==3'd0) SCL_org <= 1'b1;    //SMBCLK信号上升沿
    else if(cnt==3'd2) SCL_org <= 1'b0;    //SMBCLK信号下降沿
    else SCL_org <= SMBCLK;
    
//---------------------------------------------
        //读、写时序
parameter     IDLE      = 4'h0;         //空闲状态
parameter     START1    = 4'h1;         //Start状态
parameter     DEV_ADDR  = 4'h2;         //送slave address器件地址
parameter     ACK1      = 4'h3;         //第一次读外设发送的ACK
parameter     COMMAND   = 4'h4;         //写命令command
parameter     ACK2_1    = 4'h5;
parameter     MEM_ADDR_2= 4'h6;         //写数据
parameter     START2    = 4'h7;         //第二次Start状态:仅限读
parameter     DEV_ADDR_2= 4'h8;         //第二次送slave address器件地址
parameter     ACK2_2    = 4'h9;         //读操作的ACK代码
parameter     TRANS_PROC= 4'hA;         //传送数据:读或者写
parameter     ACK3      = 4'hB;         //主机读数据 发ACK
parameter     ACK4      = 4'hC;         //主机写数据 收ACK
parameter     STOP1     = 4'hD;
parameter     STOP2     = 4'hE;

reg[7:0] BUFF_REG = 8'b0000_0000;		//SMBus上传输的数据寄存器,缓存作用
reg[3:0] SMBus_State;                   //状态寄存器
reg[3:0] SMBus_State_Turn;
reg IO_SDA_REG;                         //输出数据寄存器
reg IO_SDA_DIR;                         //输出数据IO_SDA信号inout方向控制位,1'b0为input.1'b1为output	   
reg[3:0] num;                           // 计数作用   
wire IN_SDA;                            //记录IO_SDA输入数据
reg [4:0]dataNum = 4'h0;
reg [7:0]pecIn;
reg [7:0]pecOut;
wire[7:0]crc_o;
reg [7:0]read_data_buf;                 //即将存入read_data的数据
    
assign IO_SDA = IO_SDA_DIR ? IO_SDA_REG : 1'bz;
assign IN_SDA = IO_SDA;

always @ (posedge sys_clk or negedge sys_rst_n) begin
	if(!sys_rst_n) begin
        SMBus_State <= IDLE;                        //状态寄存器
        num <= 4'd0;
        
        IO_SDA_DIR <= 1'b0;                         //输出数据IO_SDA信号inout方向控制位  1'b0为input
        IO_SDA_REG <= 1'b1;                         //输出数据寄存器,IO_SDA线保持高电平		
        read_data <= 8'b0000_0000;                  //接收数据
        SMBus_done <= 1'b0;                         //IIC完成标志 未完成
        cnt_pulse <= 1;
		end
	else
		case (SMBus_State)
			IDLE:	begin                              //空闲状态
                IDLE_con <= 1;
                IO_SDA_DIR <= 1'b0;					    //数据线IO_SDA为input
                IO_SDA_REG <= 1'b1;                     //IO_SDA拉高电平
                num <= 4'd0;
                if(`SMBCLK_LOW_END && SMBus_en) begin   //SMBus_en==1,开始操作								
                    BUFF_REG <= {device_addr,1'b0};     //从设备地址(1'b0 写操作 1'b1读操作)
                    SMBus_State <= START1;
                    IDLE_con <= 0;
                    SMBus_done <= 1'b0;                 //smbus clear完成标志 未完成
                    end
                else SMBus_State <= IDLE;				//没有任何键被按下
                end
			
			START1: begin                               //Start状态
					if(`SMBCLK_HIG_MID) begin           //`SMBCLK_HIG_MID == 1, SMBCLK为高电平期间
                        IO_SDA_DIR <= 1'b1;             //数据线IO_SDA为output
                        IO_SDA_REG <= 1'b0;             //IO_SDA_REG输出数据寄存器,拉低数据线IO_SDA,产生起始位信号
                        num <= 4'd0;		            //num计数清零
						end
					else if(`SMBCLK_LOW_END) begin
					   SMBus_State <= DEV_ADDR;
					   end
					else SMBus_State <= START1; //等待SMBCLK高电平中间位置到来
				end
            
            DEV_ADDR:   begin
                if(`SMBCLK_LOW_MID) begin
                    if(num == 4'd7) begin 
                        IO_SDA_REG <= BUFF_REG[0];
                        end
                    else begin
                        IO_SDA_DIR <= 1'b1;                                                                
                        case (num)
                            4'd0: IO_SDA_REG <= BUFF_REG[7];//BUFF_REG此时存的从设备地址,SMBus先传MSB
                            4'd1: IO_SDA_REG <= BUFF_REG[6];
                            4'd2: IO_SDA_REG <= BUFF_REG[5];
                            4'd3: IO_SDA_REG <= BUFF_REG[4];
                            4'd4: IO_SDA_REG <= BUFF_REG[3];
                            4'd5: IO_SDA_REG <= BUFF_REG[2];
                            4'd6: IO_SDA_REG <= BUFF_REG[1];                                   
                            default: IO_SDA_REG <= 8'b0000_0000 ;
                        endcase
                        
                        end
                    end
                else if(`SMBCLK_HIG_MID) num <= num + 4'b1;
                else if(`SMBCLK_LOW_END && (num == 8)) begin
                    num = 0;
                    SMBus_State <= ACK1;
                   
                   end
                else SMBus_State <= DEV_ADDR;
                end
			
			ACK1:	begin//*******
                    if(`SMBCLK_LOW_MID) begin               //SMBCLK低电平,此即ACK1开始时的低电平
                        IO_SDA_DIR <= 1'b0;                 //IO_SDA置为高阻态(input)
                        IO_SDA_REG <= 1'b0;                 
                        BUFF_REG <= SMBus_reg_addr[15:8];   // 高八位寄存器地址        
                        end
                    else if(`SMBCLK_HIG_MID) begin          //SMBCLK高电平
                        if(IN_SDA) begin
                            SMBus_State_Turn <= IDLE;
                            IO_SDA_REG <= 1'b1;
                            end
                        else begin                          //从机返回了ACK
                            SMBus_State_Turn <= COMMAND;
                            BUFF_REG <= SMBus_reg_addr[15:8];       // 高八位寄存器地址
                            end
                        end
                    else if(`SMBCLK_LOW_END) begin
                        IO_SDA_DIR = 1'b1;                          //IO_SDA置为通态(output)
                        SMBus_State <= SMBus_State_Turn;            //响应信号
                        end
                    else SMBus_State <= ACK1;                       //等待从机响应
                    end
            
            COMMAND:    begin
                if(`SMBCLK_LOW_MID) begin
                    if(num == 4'd7) begin  
                        IO_SDA_REG <= BUFF_REG[0];     
                        num <= 4'd0;                                //num计数清零
                        end
                    else begin
                        IO_SDA_DIR <= 1'b1;                         //IO_SDA作为output
                        case (num)
                                4'd0: IO_SDA_REG <= BUFF_REG[7];    // 高八位寄存器地址
                                4'd1: IO_SDA_REG <= BUFF_REG[6];
                                4'd2: IO_SDA_REG <= BUFF_REG[5];
                                4'd3: IO_SDA_REG <= BUFF_REG[4];
                                4'd4: IO_SDA_REG <= BUFF_REG[3];
                                4'd5: IO_SDA_REG <= BUFF_REG[2];
                                4'd6: IO_SDA_REG <= BUFF_REG[1];                                           
                                default: IO_SDA_REG <= 8'b0000_0000 ;
                            endcase  
                        num <= num + 1'b1;      
                        SMBus_State <= COMMAND;                    
                        end
                    end
                else if(`SMBCLK_LOW_END && (num == 0)) begin
                    SMBus_State <= ACK2_1;
                    end
                else SMBus_State <= COMMAND;                
                end    
            
            ACK2_1:	begin
                if(`SMBCLK_LOW_MID) begin
                    IO_SDA_DIR <= 1'b0;                 //IO_SDA置为高阻态(input)
                    IO_SDA_REG <= 1'b0;                 //返回ACK
                    BUFF_REG <= SMBus_reg_addr[15:8];   // 1地址        
                    end
                
                else if(`SMBCLK_HIG_MID) begin          //SMBCLK高电平*******
                    if(IN_SDA) begin
                        SMBus_State <= IDLE;
                        IO_SDA_REG <= 1'b1;
                        end
                    else begin                          //从机返回ACK
                        if(rd_or_wr) SMBus_State_Turn <= MEM_ADDR_2; //rd_or_wr == 1 读
                        else begin                      //rd_or_wr == 0 写
                            SMBus_State_Turn <= TRANS_PROC;
                            pecOut <= crc_o;            //装载校验数据包
                            dataNum <= 4'h0;
                            BUFF_REG <= SMBus_reg_data[7:0];// 低八位寄存器数据
                            end
                        end
                    end
                    
                else if(`SMBCLK_LOW_END) begin
                    IO_SDA_DIR = ~rd_or_wr;              //1'b0 写操作 需要发送数据 1'b1读操作 需要重新开始
                    SMBus_State <= SMBus_State_Turn;     //状态转移
                    end
                else SMBus_State <= ACK2_1;              //等待从机响应
                end    
            

            MEM_ADDR_2: begin                              //空闲状态
                IDLE_con <= 1;
                IO_SDA_DIR <= 1'b0;					//数据线IO_SDA为input
                IO_SDA_REG <= 1'b1;                 //IO_SDA拉高电平
                SMBus_done <= 1'b0;                 //smbus clear完成标志
                num <= 4'd0;
                if(`SMBCLK_LOW_END && SMBus_en) begin //SMBus_en==1,开始操作								
                    //BUFF_REG <= {device_addr,1'b1};	//从设备地址(1'b0 写操作 1'b1读操作)
                    SMBus_State <= START2;
                    IDLE_con <= 0;
                    end
                else SMBus_State <= MEM_ADDR_2;				//没有任何键被按下
                end
            

            START2: begin //第二次Start状态
                if(`SMBCLK_LOW_MID) IO_SDA_REG <= 1'b1;
                if(`SMBCLK_HIG_MID) begin           //`SMBCLK_HIG_MID == 1, SMBCLK为高电平期间
                    IO_SDA_DIR <= 1'b1;             //数据线IO_SDA为output
                    IO_SDA_REG <= 1'b0;             //IO_SDA_REG输出数据寄存器,拉低数据线IO_SDA,产生起始位信号
                    //SMBus_State <= DEV_ADDR_2;
                    num <= 4'd0;                    //num计数清零
                    BUFF_REG <= {device_addr,1'b1};	//从设备地址(1'b0 写操作 1'b1读操作)
                    end
                else if(`SMBCLK_LOW_END) begin
                    SMBus_State <= DEV_ADDR_2;      //从机响应信号
                    end
                else SMBus_State <= START2;         //等待SMBCLK高电平中间位置到来
                end
                
            DEV_ADDR_2: begin
                if(`SMBCLK_LOW_MID) begin
                    if(num == 4'd7) begin 
                        IO_SDA_REG <= BUFF_REG[0];  //读操作
                        //num <= 4'd0;                //num计数清零                                   
                        //SMBus_State <= ACK2_2;
                        end
                    else begin
                        IO_SDA_DIR <= 1'b1;         //IO_SDA置为通态(input)                                                                
                        case (num)
                            4'd0: IO_SDA_REG <= BUFF_REG[7];//BUFF_REG此时存的从设备地址,SMBus先传MSB
                            4'd1: IO_SDA_REG <= BUFF_REG[6];
                            4'd2: IO_SDA_REG <= BUFF_REG[5];
                            4'd3: IO_SDA_REG <= BUFF_REG[4];
                            4'd4: IO_SDA_REG <= BUFF_REG[3];
                            4'd5: IO_SDA_REG <= BUFF_REG[2];
                            4'd6: IO_SDA_REG <= BUFF_REG[1];                                   
                            default: IO_SDA_REG <= 8'b0000_0000 ;
                        endcase
                        //num <= num + 1'b1;                                    
                        end
                    end
                else if(`SMBCLK_HIG_MID) num <= num + 4'b1;
                else if(`SMBCLK_LOW_END && (num == 8)) begin
                    num <= 0;
                    SMBus_State <= ACK2_2;    //从机响应信号
                    end
                else SMBus_State <= DEV_ADDR_2;
                end
                
            ACK2_2: begin//*******
                if(`SMBCLK_LOW_MID) begin               //从机响应信号
                    IO_SDA_DIR <= 1'b0;                 //IO_SDA置为高阻态(input)
                    IO_SDA_REG <= 1'b0;                 //返回ACK
                    //SMBus_State <= SMBus_State_Turn;
                    BUFF_REG <= {device_addr,1'b1};    //送器件地址(读操作),特定地址读需要执行该步骤以下操作
                    end
                    
                else if(`SMBCLK_HIG_MID) begin          //SMBCLK高电平*******
                    if(IN_SDA) begin
                        //SMBus_State_Turn <= IDLE;
                        SMBus_State <= IDLE;
                        IO_SDA_REG <= 1'b1;
                        end
                    else begin                          //从机返回ACK
                        SMBus_State_Turn <= TRANS_PROC;
                        dataNum <= 4'h0;
                        end
                    end
                    
                else if(`SMBCLK_LOW_END) begin
                    IO_SDA_DIR = ~rd_or_wr;               //IO_SDA置为通态(output)
                    SMBus_State <= SMBus_State_Turn;     //状态转移
                    end
                    
                else SMBus_State <= ACK2_2;    //等待从机响应
                end
            
            TRANS_PROC: begin
                if(rd_or_wr) begin     //读操作
                    if(num <= 4'd7) begin                        
                        if(`SMBCLK_LOW_MID) begin
                            SMBus_State <= TRANS_PROC;
                            IO_SDA_DIR <= 1'b0;       //IO_SDA置为高阻态(input)
                            end
                        else if(`SMBCLK_HIG_MID) begin
                            case (num)
                                4'd0: read_data_buf[7] <= IN_SDA;//assign IO_SDA = IO_SDA_DIR ? IO_SDA_REG:1'bz;
                                4'd1: read_data_buf[6] <= IN_SDA;
                                4'd2: read_data_buf[5] <= IN_SDA; 
                                4'd3: read_data_buf[4] <= IN_SDA; 
                                4'd4: read_data_buf[3] <= IN_SDA; 
                                4'd5: read_data_buf[2] <= IN_SDA; 
                                4'd6: read_data_buf[1] <= IN_SDA; 
                                4'd7: read_data_buf[0] <= IN_SDA; 
                                default: IO_SDA_REG <= 8'b0000_0000;
                            endcase
                            num <= num + 1'b1;
                            end
                        else SMBus_State <= TRANS_PROC;
                        end

                    else if(`SMBCLK_LOW_END && num == 4'd8) begin
                        num <= 4'd0;
                        SMBus_State <= ACK4;    //状态转移
                        end
                    else SMBus_State <= TRANS_PROC;
                    end
                    
                else  begin    //写操作                            
                    if(num <= 4'd7) begin
                        SMBus_State <= TRANS_PROC;
                        if(`SMBCLK_LOW_MID) begin  
                            IO_SDA_DIR <= 1'b1;     //数据线IO_SDA作为output
                            case (num)
                                4'd0: IO_SDA_REG <= BUFF_REG[7];
                                4'd1: IO_SDA_REG <= BUFF_REG[6];
                                4'd2: IO_SDA_REG <= BUFF_REG[5];
                                4'd3: IO_SDA_REG <= BUFF_REG[4];
                                4'd4: IO_SDA_REG <= BUFF_REG[3];
                                4'd5: IO_SDA_REG <= BUFF_REG[2];
                                4'd6: IO_SDA_REG <= BUFF_REG[1];
                                4'd7: IO_SDA_REG <= BUFF_REG[0]; 
                                default: IO_SDA_REG <= 8'b0000_0000;
                                endcase    
                            num <= num + 1'b1;                                
                            end
                        end

                    else if(`SMBCLK_LOW_END) begin
                        num <= 4'd0;
                        SMBus_State <= ACK4;    //状态转移
                        end
                    else SMBus_State <= TRANS_PROC;
                    end
                end
                        
            ACK4: begin
                if(`SMBCLK_LOW_MID) begin
                    IO_SDA_DIR <= rd_or_wr;             //1'b0 写操作 收ACK 1'b1读操作 发ACK
                    IO_SDA_REG <= 1'b0;
                    case(dataNum)
                        4'h0: begin
                            read_data[7:0] <= read_data_buf;
                            BUFF_REG <= SMBus_reg_data[15:8];
                            SMBus_State_Turn <= TRANS_PROC;
                        end
                        4'h1:begin
                            read_data[15:8] <= read_data_buf;
                            BUFF_REG <= pecOut;
                            SMBus_State_Turn <= TRANS_PROC;
                        end
                        4'h2:begin
                            pecIn <= read_data_buf;
                            SMBus_State_Turn <= STOP1;
                            dataNum <= 4'hF;
                        end
                        default: dataNum <= 4'hF;
                    endcase
                    dataNum <= dataNum + 4'h1;
                    end
                else if(`SMBCLK_LOW_END) begin
                    IO_SDA_DIR <= ~rd_or_wr;                  //1'b0 写操作 1'b1读操作
                    SMBus_State <= SMBus_State_Turn;
                    end
                else SMBus_State <= ACK4;
                end

            STOP1: begin
                if(`SMBCLK_LOW_MID) IO_SDA_DIR <= 1'b1;
                else if(`SMBCLK_HIG_MID) IO_SDA_REG <= 1'b1;//SMBCLK为高时,IO_SDA产生上升沿(结束信号)
                else if(`SMBCLK_LOW_END) SMBus_State <= STOP2;
                else SMBus_State <= STOP1;
                end
            
            STOP2: begin    //
                    if(`SMBCLK_LOW_MID) begin
                        IO_SDA_DIR <= 1'b0;                                         
                        SMBus_done <= 1'b1;
                        #20_0000 SMBus_State <= IDLE;
                        end
                    else SMBus_State <= STOP2;
                    end
            
            default: SMBus_State <= IDLE;
            
            endcase
    end
    
crc_8 pec
(
.clk(sys_clk),
.din0({device_addr,1'b0}),
.din1(SMBus_reg_addr[15:8]),
.din2(SMBus_reg_data[7:0]),
.din3(SMBus_reg_data[15:8]),
.crc_o(crc_o)
);

endmodule

crc_8.v

`timescale 1ns / 1ps
//
// Company: 
// Engineer: Mark Mo Swift
// 
// Create Date: 2022/11/04 20:31:08
// Design Name: 
// Module Name: crc_8
// Project Name: IOBus
// Target Devices: 
// Tool Versions: Vivado 2018.2
// Description: 
// 
// Dependencies: Null
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module crc_8
(
    input wire clk,
    (* MARK_DEBUG="true" *)input wire [7:0] din0,
    (* MARK_DEBUG="true" *)input wire [7:0] din1,
                            input wire [7:0] din2,
                            input wire [7:0] din3,
    (* MARK_DEBUG="true" *)output wire [7:0] crc_o
);
    parameter [7:0] poly = 8'b0000_0111;
    (* MARK_DEBUG="true" *)reg [3:0] crc_cnt;
    //除数为1_0000_0111,第一位为1。
    //因为我们需要的余数,最高为8位,所以实际上最高位我们用不到。于是为节省资源,可在运算时将整个数组向前移动一位。并且在存储除数时,可忽略第一位1。
    //运算时我们先判断被除数最高位是否为1,若为1,剩下8位进行亦或操作后,将其填入寄存器前8位。若为0,则将被除数直接落下,填入寄存器前8位。
    (* MARK_DEBUG="true" *)reg [15:0] din_temp;//寄存器,存储din值进行处理
    (* MARK_DEBUG="true" *)reg [1:0] times;
//    reg crc_en;//运算使能信号,当该信号使能时,将din_temp向左移动一格,将其与poly进行"模2除法"
    
    initial
        begin
            crc_cnt [3:0] = 4'd0;
            times = 0;
        end
        
    (* MARK_DEBUG="true" *)wire crc_en;    
    assign crc_en = ~crc_cnt[3];
    
    //一般一个语言块中只给一个变量赋值
    always@(posedge clk)
        if(crc_en == 1 && times < 2)
            begin
                if(crc_cnt [3] == 0 && crc_cnt [2] == 0 && crc_cnt [1] == 0 && crc_cnt [0] == 0)
                    begin
                        case(times)
                            0:din_temp = {din0,8'b0000_0000};
                            1:din_temp = {crc_o^din1,8'b0000_0000};
                            2:din_temp = {crc_o^din2,8'b0000_0000};
                            3:din_temp = {crc_o^din3,8'b0000_0000};
                        endcase
                    end
                       
                if(crc_cnt < 8)
                    begin
                        repeat(8)
                             begin
                                  din_temp[15:8] <= din_temp[15] ? din_temp[14:7]^poly : din_temp[14:7];//实际上,这步我们做了运算与移动操作
                                  din_temp[7:0] <= {din_temp[6:0],1'b0};//最后位补0
                             end
                    end
            end
      
     //计数器模块
     always@(posedge clk)
        begin
          case(crc_cnt)
               0:crc_cnt = crc_cnt + 1'b1;
               1:crc_cnt = crc_cnt + 1'b1;
               2:crc_cnt = crc_cnt + 1'b1;
               3:crc_cnt = crc_cnt + 1'b1;
               4:crc_cnt = crc_cnt + 1'b1;
               5:crc_cnt = crc_cnt + 1'b1;
               6:crc_cnt = crc_cnt + 1'b1;
               7:crc_cnt = crc_cnt + 1'b1;
               8:crc_cnt = 0;
          endcase
        end           
                        
           always@(posedge clk)
                begin
                    if(crc_cnt == 8)
                        begin
                            case(times)
                                0:times = 1;
                                1:times = 2;
                                2:times = 3;
                                3:times = 4;
                            endcase
                        end
                end
            
        assign crc_o = din_temp[15:8];
         
endmodule

已经在MLX90614DCI(GY-906-DCI)红外线温度传感器上实验成功,CRC-8算法没有做额外的测试。读数据时,该传感器传回的数据为2bit的温度数据和1bit的CRC-8校验码。写数据时,传出的同样为2bit数据和1bit的CRC-8校验码。如果要对传送的数据量进行修改,请修改smbus_2.v文件的358-446行TRANS_PROC状态和ACK4状态。

感谢博主@unique小酒馆的博客基于SUMBus或I2C通信协议,使用vivado2017 modsim,循环执行写操作_unique小酒馆的博客-CSDN博客以我对SMBus肤浅的见解,他的这篇博客有一定的问题,与传感器通信的时候也没有成功。但是他的算法框架很优秀,所以我在他的基础上进行了修改和验证,采取了相似的结构和命名风格。他提供了一份仿真文件,不出意外的话与我的代码兼容,大家有疑问的话可以用于测试写数据功能。

如果我的代码有错误,欢迎大家批评指正。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值