基于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
相关推荐
国科安芯2 小时前
【AS32X601驱动系列教程】SMU_系统时钟详解
单片机·嵌入式硬件·fpga开发
简简单单做算法12 小时前
基于FPGA的二叉决策树cart算法verilog实现,训练环节采用MATLAB仿真
算法·决策树·fpga开发·cart算法·二叉决策树
无情的88612 小时前
FPGA中的“BPI“指什么
fpga开发
猫头虎15 小时前
什么是 WPF 技术?什么是 WPF 样式?下载、安装、配置、基本语法简介教程
驱动开发·fpga开发·硬件架构·wpf·硬件工程·dsp开发·材料工程
hahaha601619 小时前
ARINC818_FILE
fpga开发
上海易硅智能科技局有限公司1 天前
AG32VH 系列应用指南
单片机·嵌入式硬件·fpga开发·agm芯片
芯有所享1 天前
【芯片设计中的跨时钟域信号处理:攻克亚稳态的终极指南】
经验分享·fpga开发·信号处理
hahaha60161 天前
视频画质等级
fpga开发
9527华安2 天前
紫光同创FPGA实现视频采集转USB2.0输出,基于CY7C68013芯片,提供PDS工程源码和技术支持和QT上位机
qt·fpga开发·音视频·紫光同创·pds·cy7c68013·usb2.0