基于FPGA的IIC多通道选择器(IIC Switch/Bridge)

基于FPGA的IIC多通道选择器(IIC Switch/Bridge)

1,背景

在项目中,一个FPGA芯片上接了一路IIC Master,至少一路IIC Slave,当IIC Master想要直接访问IIC slave的时候,在FPGA中并不能直接将SCL和SDA端口直接连接,原因是SDA是inout的端口(SCL由主机提供,可以作为单独的input或output),不支持直接相连,否则编译器会报错。为解决这个小尴尬,简单写了一个verilog的IIC switch模块,在此记录一下。使用该模块可以轻松将IIC链路通过FPGA连接,实现通信。

2,系统框图

使用 iic_switch.v 模块,可在FPGA中选择MCU的IIC接到设备端的那一路IIC端口。

3,完整模块代码

javascript 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: QSJ
// 
// Create Date: 2025/05/21 9:12:00
// Design Name: 
// Module Name: iic_switch
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module iic_switch(

    input         	   clk            // 100MHz
   ,input         	   rst_n          
   
   ,input wire [3:0]   iv_channel_sel
   
   ,input         	    i_master_scl        
   ,inout         	   io_master_sda   
   
   ,output reg         o_slave_0_scl      
   ,inout              io_slave_0_sda     
   ,output reg          o_slave_1_scl      
   ,inout              io_slave_1_sda     
   ,output reg          o_slave_2_scl      
   ,inout              io_slave_2_sda     
   ,output reg          o_slave_3_scl      
   ,inout              io_slave_3_sda     
   ,output reg          o_slave_4_scl      
   ,inout              io_slave_4_sda     
   ,output reg          o_slave_5_scl      
   ,inout              io_slave_5_sda     
   ,output reg          o_slave_6_scl      
   ,inout              io_slave_6_sda     
   ,output reg          o_slave_7_scl      
   ,inout              io_slave_7_sda     
);


reg master_scl_n;
reg master_sda_n;
reg scl_rising  ;
reg scl_falling ;
reg sda_rsiing  ;
reg sda_falling ;

always @(posedge clk)begin
    if(!rst_n)begin
        master_scl_n   <= 1'b1;
        master_sda_n   <= 1'b1;
    end else begin
        master_scl_n   <= i_master_scl;
        master_sda_n   <= io_master_sda;
		
		scl_rising  <= (master_scl_n!=i_master_scl) & (master_scl_n==0);
		scl_falling <= (master_scl_n!=i_master_scl) & (master_scl_n==1); 
		sda_rsiing  <= (master_sda_n!=io_master_sda) & (master_sda_n==0); 
		sda_falling <= (master_sda_n!=io_master_sda) & (master_sda_n==1); 
		
    end
end


reg [7:0] bit_cnt     ;
reg       first_start ;
reg       iic_start   ;
reg       iic_stop    ;

always @(posedge clk)begin
    if(!rst_n)begin
        bit_cnt        <=  'd0;
        first_start    <=  'b0;
        iic_start      <=  'b0;
        iic_stop       <=  'b0;
    end else begin
		if((i_master_scl==1) & sda_falling)begin //IIC Start
			bit_cnt        <= 0;
            first_start    <=  'b1;
            iic_start      <=  'b1;
            iic_stop       <=  'b0;
		end else if((i_master_scl==1) & sda_rsiing)begin //IIC Stop
			bit_cnt        <= 0;
            first_start    <=  'b0;
            iic_start      <=  'b0;
            iic_stop       <=  'b1;
		end else if(bit_cnt==10)begin
			bit_cnt        <= 1;
            first_start    <=  'b0;
            iic_start      <=  'b0;
            iic_stop       <=  'b0;
		end else begin
			bit_cnt        <= bit_cnt + scl_falling;
            first_start    <=  first_start;
            iic_start      <=  'b0;
            iic_stop       <=  'b0;
		end 
    end
end

reg rw_bit;
reg ack_bit_vld;
reg ack_bit_vld_n;
wire ack_bit_vld_falling = (ack_bit_vld_n!=ack_bit_vld) & (ack_bit_vld_n==1); 
always @(posedge clk)begin
    if(!rst_n)begin
        ack_bit_vld         <= 1'b0;
        ack_bit_vld_n       <= 1'b0;
    end else begin
        ack_bit_vld         <= bit_cnt==9;
        ack_bit_vld_n       <= ack_bit_vld;
    end
end

reg rw_bit_p;
reg master_ack;
always @(posedge clk)begin
    if(!rst_n)begin
        master_ack  <= 1'b0;
    end else begin
        if(rw_bit_p)begin
            if(ack_bit_vld_n & scl_rising)begin
                master_ack        <= master_sda_n;
            end else begin
                master_ack        <= master_ack;
            end 
		end else begin
			master_ack        <= 0;
		end 
    end
end


reg bit_vld;
always @(posedge clk)begin
    if(!rst_n)begin
        bit_vld   <= 'b0;
        rw_bit    <= 'b0;
        rw_bit_p  <= 'b0;
    end else begin
        bit_vld   <= scl_rising;
        rw_bit_p  <= ((bit_cnt==8) & bit_vld & first_start) ? io_master_sda : iic_stop ? 1'b0 : rw_bit_p;
        rw_bit    <= ack_bit_vld_falling ? master_ack ? 1'b0 : rw_bit_p  : rw_bit;
     end
 end


reg master_sda_oe;
always @(posedge clk)begin
    if(!rst_n)begin
        master_sda_oe     <= 1'b0;
    end else begin
		master_sda_oe     <= rw_bit ? ~ack_bit_vld_n :  ack_bit_vld_n;
    end
end
wire slave_sda_oe = ~master_sda_oe;

assign io_slave_0_sda = iv_channel_sel==0 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_1_sda = iv_channel_sel==1 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_2_sda = iv_channel_sel==2 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_3_sda = iv_channel_sel==3 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_4_sda = iv_channel_sel==4 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_5_sda = iv_channel_sel==5 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_6_sda = iv_channel_sel==6 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;
assign io_slave_7_sda = iv_channel_sel==7 ? slave_sda_oe ? io_master_sda : 1'bz : 1'bz;

assign io_master_sda  =  master_sda_oe ? 
						iv_channel_sel==0 ? io_slave_0_sda : 
						iv_channel_sel==1 ? io_slave_1_sda : 
						iv_channel_sel==2 ? io_slave_2_sda : 
						iv_channel_sel==3 ? io_slave_3_sda : 
						iv_channel_sel==4 ? io_slave_4_sda : 
						iv_channel_sel==5 ? io_slave_5_sda : 
						iv_channel_sel==6 ? io_slave_6_sda : 
						iv_channel_sel==7 ? io_slave_7_sda : 1'bz
						: 1'bz;


always @(*)begin
	case(iv_channel_sel)
		0:begin
			o_slave_0_scl = i_master_scl;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		1:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = i_master_scl;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		2:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = i_master_scl;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		3:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = i_master_scl;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		4:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = i_master_scl;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		5:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = i_master_scl;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz;
		end
		6:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = i_master_scl;
			o_slave_7_scl = 1'bz;
		end
		7:begin
			o_slave_0_scl = 1'bz;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = i_master_scl;
		end
		default:begin 
			o_slave_0_scl = i_master_scl;
			o_slave_1_scl = 1'bz;
			o_slave_2_scl = 1'bz;
			o_slave_3_scl = 1'bz;
			o_slave_4_scl = 1'bz;
			o_slave_5_scl = 1'bz;
			o_slave_6_scl = 1'bz;
			o_slave_7_scl = 1'bz; end
	endcase
	
end

endmodule
相关推荐
文火冰糖的硅基工坊3 小时前
[硬件电路-150]:数字电路 - 数字电路与模拟电路的异同
嵌入式硬件·fpga开发·电路·运放·跨学科融合
m0_575046346 小时前
Verilog 仿真问题:打拍失败
fpga开发·fpga打拍失败
做一个优雅的美男子11 小时前
FPGA设计思想与验证方法学系列学习笔记003
笔记·fpga开发
晓晓暮雨潇潇12 小时前
Diamond基础1:认识Lattice器件
fpga开发·diamond·latticeecp3
ChipCamp1 天前
Chisel芯片开发入门系列 -- 18. CPU芯片开发和解释8(流水线架构的代码级理解)
开发语言·青少年编程·fpga开发·scala·dsp开发·risc-v·chisel
I'm a winner1 天前
基于 Ubuntu 的 Linux 系统中 Vivado 2020.1 下载安装教程
linux·ubuntu·fpga开发
9527华安1 天前
FPGA实现Aurora 8B10B数据回环传输,基于GTP高速收发器,提供6套工程源码和技术支持
fpga开发·aurora·gtp·高速收发器·sfp·8b10b
秋风战士1 天前
通信算法之298: verilog语法generate和for介绍
fpga开发
hi942 天前
HBM Basic(VCU128)
fpga开发·hbm·高带宽内存
ARM+FPGA+AI工业主板定制专家2 天前
基于ARM+FPGA多通道超声信号采集与传输系统设计
linux·人工智能·fpga开发·rk3588·rk3568·codesys