基于FPGA的IIC通讯-SLAVE接收篇


前言

上一篇我们讲解了IIC的MASTER控制读写过程,今天我们讲一下IIC的SLAVE接收和回读的篇章,今天先开始介绍IIC的从机接收写指令的过程。

一、IIC从机接收

如下图示:
IIC
从机接收可以理解为是主机发送的逆过程,识别开始信号,主从地址握手,识别寄存器,获取寄存器值和数据值,最终完成数据接收和控制。

二、代码内容

在这里插module iic_slave #
(
   parameter               BYTE = 4             ,
   parameter               DWID = 32            ,
   parameter               UCNT = 25
)
(
   input                   clk_sys              ,
   input                   rst_sys              ,
   // 
   input       [6:0]       slave_addr           ,
   input                   contin_mode          ,
   output reg              iic_ena              ,
   output reg  [7:0]       iic_adr              ,
   output reg  [DWID-1:0]  iic_dat              ,
   //
   input                   i2c_scl_m_i          ,
   output                  i2c_scl_m_o          ,
   output                  i2c_scl_m_t          ,
   input                   i2c_sda_m_i          ,
   output                  i2c_sda_m_o          ,
   output                  i2c_sda_m_t
);

// ********************************************************
// localparam
// ********************************************************
localparam  IDLE = 4'd0 ;
localparam  SLAV = 4'd1 ;
localparam  REGS = 4'd2 ;
localparam  MODE = 4'd3 ;
localparam  CMWRTIE  = 4'd4 ;
localparam  CMREAD   = 4'd5 ;
localparam  OMWRITER = 4'd6 ;
localparam  OMREAD   = 4'd7 ;
localparam  STOP = 4'd8 ;
// ********************************************************
// signal
// ********************************************************
reg      [3:0]             cstate = IDLE        ;
reg      [3:0]             nstate = IDLE        ;
   
wire                       start_pedge          ;
wire                       start_nedge          ;
wire                       stop_pedge           ;
wire                       stop_nedge           ;
reg                        read_start = 0       ;
reg                        write_read = 0       ;

wire                       scl_pedge            ;
wire                       scl_nedge            ;

reg      [7:0]             cnt_div = 0          ;
reg      [15:0]            cnt_us = 0           ;
reg      [15:0]            reg_us = 0           ;
reg      [7:0]             cnt_scl = 0          ;
reg      [7:0]             cnt_sda = 0          ;
reg      [7:0]             cnt_tags = 0         ;

reg      [6:0]             iic_slave = 0        ;
reg      [7:0]             reg_slave = 0        ;
reg      [7:0]             reg_regsi = 0        ;
reg      [7:0]             reg_data  = 0        ;
reg                        reg_stop  = 0        ;

reg      [3:0]             shift_cnt = 0        ;
reg      [3:0]             shift_reg = 0        ;
reg      [5:0]             shift_dat = 0        ;
reg                        readback = 0         ;

reg      [31:0]            data_value           ;
reg                        reg_sda_o = 1        ;
wire                       dly_sda_o            ;
// ********************************************************
// process
// ********************************************************
always @ ( posedge clk_sys )
begin
   if( rst_sys )
      cstate = IDLE ;
   else
      cstate = nstate ;
end

always @ ( * )
begin
   case ( cstate )
      IDLE : begin
         if( read_start )
            nstate = SLAV ;
         else 
            nstate = IDLE ;
      end
      SLAV : begin
         if(( slave_addr == iic_slave ) && readback )
            nstate = REGS ;
         else 
            nstate = SLAV ;
      end
      REGS : begin
         if( readback )
            nstate = MODE ;
         else
            nstate = REGS ;
      end
      MODE : begin
         if( contin_mode && write_read == 0 )
            nstate = CMWRTIE ;
         else if( contin_mode && write_read == 1 )
            nstate = CMREAD ;
         else if( contin_mode == 0 && write_read == 0 )
            nstate = OMWRITER ;
         else if( contin_mode == 0 && write_read == 1 )
            nstate = OMREAD ;
         else
            nstate = MODE ;
      end
      CMWRTIE : begin
         if( readback && cnt_tags == BYTE - 1 )
            nstate = STOP ;
         else 
            nstate = CMWRTIE ;
      end
      OMWRITER : begin
         if( readback )
            nstate = STOP ;
         else
            nstate = OMWRITER ;
      end
      STOP : begin
         if( stop_nedge )
            nstate = IDLE ;
         else 
            nstate = STOP ;
      end
      default : nstate = IDLE ;
   endcase
end

// ========================================================
// TIME
// ========================================================
always @ ( posedge clk_sys ) // 1s == 25M    1us == 25次
begin
   if( rst_sys )
      cnt_div <= 0 ;
   else if( cnt_div == UCNT - 1 )
      cnt_div <= 0 ;
   else 
      cnt_div <= cnt_div + 1 ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate == IDLE )
      cnt_us <= 0 ;
   else if( cnt_div == UCNT - 1 )
      cnt_us <= cnt_us + 1 ;
   else ;
end

// ========================================================
// READBACK
// ========================================================
always @ ( posedge clk_sys )
begin
   if( rst_sys )
      cnt_scl <= 0 ;
   else if( i2c_scl_m_i && cstate == IDLE && cnt_div == UCNT - 1 )
      cnt_scl <= cnt_scl + ~&cnt_scl ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      cnt_sda <= 0 ;
   else if( i2c_sda_m_i && cstate == IDLE && cnt_div == UCNT - 1 )
      cnt_sda <= cnt_sda + ~&cnt_sda ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      readback <= 0 ;
   else if( i2c_sda_m_o == 1'b0 && i2c_sda_m_t == 1'b0 && scl_pedge )
      readback <= 1 ;
   else 
      readback <= 0 ;
end

// ========================================================
// RECV
// ========================================================
always @ ( posedge clk_sys )
begin
   if( rst_sys )
      read_start <= 0 ;
   else if( cstate == IDLE && start_nedge )
      read_start <= 1 ;
   else
      read_start <= 0 ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      reg_slave <= 0 ;
   else if( cstate == SLAV && scl_pedge )
      reg_slave <= { reg_slave[6:0],i2c_sda_m_i };
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate != SLAV)
      shift_cnt <= 0 ;
   else if( cstate == SLAV && scl_pedge )
      shift_cnt <= shift_cnt + ~&shift_cnt ;
   else ;   
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      iic_slave <= 0 ;
   else if( cstate == SLAV && shift_cnt == 7 )
      iic_slave <= reg_slave ;
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate == IDLE )
      write_read <= 0 ;
   else if( cstate == SLAV && shift_cnt == 8 && scl_pedge )
   begin
      if( i2c_sda_m_i == 0 )
         write_read <= 0 ;
      else if( i2c_sda_m_i == 1 )
         write_read <= 1 ;
      else ;
   end
end
// ========================================================
// REG ADDR
// ========================================================
always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate != REGS )
      shift_reg <= 0 ;
   else if( cstate == REGS && scl_pedge )
      shift_reg <= shift_reg + ~&shift_reg ;
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      reg_regsi <= 0 ;
   else if( cstate == REGS && scl_pedge && shift_reg < 8 )
      reg_regsi <= {reg_regsi[6:0],i2c_sda_m_i};
   else ;
end

// ========================================================
//
// ========================================================
always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate == IDLE || readback )
      shift_dat <= 0 ;
   else if((cstate == OMWRITER || cstate == CMWRTIE ) && scl_pedge )
      shift_dat <= shift_dat + ~&shift_dat ;
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      reg_data <= 0 ;
   else if((cstate == CMWRTIE || cstate == OMWRITER )&& scl_pedge )
      reg_data <= {reg_data[6:0],i2c_sda_m_i };
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys || cstate == IDLE )
      cnt_tags <= 0 ;
   else if( cstate == CMWRTIE && readback )
      cnt_tags <= cnt_tags + 1 ;
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      data_value <= 0 ;
   else if( cstate == CMWRTIE && shift_dat == 8 && scl_pedge )
      data_value <= {data_value[23:0],reg_data};
   else ;
end

// ========================================================
//
// ========================================================

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      iic_ena <= 0 ;
   else if( cstate == STOP && scl_pedge )
      iic_ena <= 1 ;
   else
      iic_ena <= 0 ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      iic_adr <= 0 ;
   else if( cstate == STOP && scl_pedge )
      iic_adr <= reg_regsi ;
   else ;
end

always @ ( posedge clk_sys )
begin
   if( rst_sys )
      iic_dat <= 0 ;
   else if( cstate == STOP && scl_pedge && contin_mode == 0 )
      iic_dat <= reg_data ;
   else if( cstate == STOP && scl_pedge && contin_mode == 1 )
      iic_dat <= data_value ;
end

// ========================================================
//
// ========================================================
always @ ( posedge clk_sys )
begin
   if( cstate == STOP && scl_pedge )
      reg_stop <= 1 ;
   else if( cstate == STOP && start_pedge )
      reg_stop <= 0 ;
   else ;
end
// ========================================================
//
// ========================================================
always @ ( posedge clk_sys )
begin
   if( rst_sys )
      reg_sda_o <= 1 ;
   else if( cstate == SLAV && shift_cnt == 8 && scl_nedge )
      reg_sda_o <= 0 ;
   else if( cstate == REGS && shift_reg == 0 && scl_nedge )
      reg_sda_o <= 1 ;
   else if( cstate == REGS && shift_reg == 8 && scl_nedge )
      reg_sda_o <= 0 ;
   else if( cstate == REGS && shift_reg == 9 && scl_nedge )
      reg_sda_o <= 1 ;
   else if( cstate == OMWRITER && shift_dat == 0 && scl_nedge )
      reg_sda_o <= 1 ;
   else if((cstate == OMWRITER || cstate == CMWRTIE ) && shift_dat == 8 && scl_nedge )
      reg_sda_o <= 0 ;
   else if( cstate == OMWRITER && shift_dat == 9 && scl_nedge )
      reg_sda_o <= 1 ;
   else if( cstate == CMWRTIE && shift_dat == 0 && scl_nedge )
      reg_sda_o <= 1 ;
   else if((cstate == STOP && scl_nedge )|| cstate == IDLE )
      reg_sda_o <= 1 ;
   else ;
end

assign i2c_sda_m_o = reg_sda_o ;
assign i2c_sda_m_t = reg_sda_o ; 
// ========================================================
//
// ========================================================

edge_detect u0_edge_detect
(
   //input
   .clk                          ( clk_sys               ),
   .sig_in                       ( i2c_sda_m_i           ),
   //output
   .p_edge                       ( start_pedge           ),
   .n_edge                       ( start_nedge           )
);

edge_detect u1_edge_detect
(
   //input
   .clk                          ( clk_sys               ),
   .sig_in                       ( i2c_scl_m_i           ),
   //output
   .p_edge                       ( scl_pedge             ),
   .n_edge                       ( scl_nedge             )
);

edge_detect u2_edge_detect
(
   //input
   .clk                          ( clk_sys               ),
   .sig_in                       ( reg_stop              ),
   //output
   .p_edge                       ( stop_pedge            ),
   .n_edge                       ( stop_nedge            )
);

delay_base_reg #
(
   .DATA_WIDTH                   ( 1                     ),  
   .DELAY_TAPS                   ( 2                     )   
)u_delay_base_reg
(
   //input
   .clk                          ( clk_sys               ),
   .wrenin                       ( 1'b1                  ),
   .datain                       ( reg_sda_o             ),

   //output
   .wrenout                      (                       ),
   .dataout                      ( dly_sda_o             )
);


endmodule入代码片

调试总结

总结
由图可看知,下发的IIC与解析出的IIC一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值