当前位置:首页 > FPGA > 正文内容

Verilog IIC器件枚举工具 SI5341 SI5394等器件也可使用

chanra1n4天前FPGA44

程序如下:

`timescale 1ns / 1ps

module i2c_address_scanner (
    input  wire SYSCLK2_P,        // LVDS差分时钟正端
    input  wire SYSCLK2_N,        // LVDS差分时钟负端
    output wire SI_RSTBB,          // Si5394复位(低有效)
    output wire I2C_SI5394_SCL,   // I2C时钟
    inout  wire I2C_SI5394_SDA,   // I2C数据(双向)
    output reg [7:0] LED          // 扫描结果指示
);

// 内部时钟信号(差分转单端)
wire clk;
IBUFDS #(
    .DIFF_TERM("FALSE"),
    .IBUF_LOW_PWR("TRUE"),
    .IOSTANDARD("LVDS")
) clk_ibufds (
    .O(clk),
    .I(SYSCLK2_P),
    .IB(SYSCLK2_N)
);

// 参数定义
localparam CLK_FREQ      = 100_000_000;   // 100 MHz
localparam I2C_FREQ      = 100_000;       // I2C时钟频率 (100 kHz)
localparam DIVIDER_I2C   = CLK_FREQ / (2 * I2C_FREQ) - 1;
localparam COUNTER_ADDR  = 500_000;       // 500ms地址切换周期

// 状态机定义
typedef enum logic [2:0] {
    IDLE,           // 空闲状态
    START,          // 发送起始条件
    SEND_ADDR,      // 发送设备地址
    CHECK_ACK,      // 检查ACK响应
    STOP,           // 发送停止条件
    NEXT_ADDR       // 准备下一个地址
} state_t;

// 状态寄存器
reg [2:0] state = IDLE;
reg [2:0] next_state = IDLE;

// 定时控制
reg [31:0] timer_count = 0;
reg addr_switch_pulse = 0;

// I2C控制信号
reg [15:0] i2c_counter = 0;
reg i2c_clk = 1;
reg sda_out = 1;
reg sda_oe = 0;
wire sda_in = I2C_SI5394_SDA;

// 地址扫描控制
reg [6:0] current_addr = 7'h00;  // 当前尝试的地址(7位)
reg [7:0] addr_response = 8'h00; // 地址响应位图
reg [3:0] bit_count = 0;
reg found = 0;
reg [7:0] found_count = 0;

// I2C时钟边沿检测
reg i2c_clk_prev = 0;
wire i2c_clk_rising = (i2c_clk_prev == 0 && i2c_clk == 1);
wire i2c_clk_falling = (i2c_clk_prev == 1 && i2c_clk == 0);

// 设备地址显示
always @(posedge clk) begin
    LED <= {found, current_addr};
end

// 地址切换定时器(0.5秒)
always @(posedge clk) begin
    if (timer_count >= COUNTER_ADDR) begin
        timer_count <= 0;
        addr_switch_pulse <= 1;
    end else begin
        timer_count <= timer_count + 1;
        addr_switch_pulse <= 0;
    end
end

// I2C时钟生成(100 kHz)
always @(posedge clk) begin
    i2c_clk_prev <= i2c_clk;
    
    if (i2c_counter >= DIVIDER_I2C) begin
        i2c_counter <= 0;
        i2c_clk <= ~i2c_clk;
    end else begin
        i2c_counter <= i2c_counter + 1;
    end
end

// I2C总线控制
assign I2C_SI5394_SCL = (state != IDLE) ? i2c_clk : 1'b1;
assign I2C_SI5394_SDA = sda_oe ? sda_out : 1'bz;

// ILA信号
wire [7:0] current_addr_8bit = {1'b0, current_addr};
wire ack_detected = (state == CHECK_ACK && i2c_clk_rising && sda_in == 0);
wire [7:0] response_map = addr_response;

// 主状态机
always @(posedge clk) begin
    state <= next_state;
    
    case (state)
        IDLE: begin
            sda_oe <= 0;
            sda_out <= 1;
            found <= 0;
            if (addr_switch_pulse) begin
                next_state <= START;
                bit_count <= 0;
            end
        end
        
        START: begin
            sda_oe <= 1;
            
            // 确保START状态持续足够时间
            if (i2c_clk_falling) begin
                sda_out <= 1; // SCL高时SDA高
            end
            if (i2c_clk_rising) begin
                sda_out <= 0; // SCL高时拉低SDA(起始条件)
                next_state <= SEND_ADDR;
            end
        end
        
        SEND_ADDR: begin
            sda_oe <= 1;
            
            if (i2c_clk_falling) begin
                if (bit_count < 8) begin
                    // 发送7位地址 + R/W位(0=写)
                    if (bit_count < 7) begin
                        sda_out <= current_addr[6 - bit_count];
                    end else begin
                        sda_out <= 1'b0; // 写命令
                    end
                    bit_count <= bit_count + 1;
                end
                else if (bit_count == 8) begin
                    sda_oe <= 0; // 释放SDA用于ACK检测
                    next_state <= CHECK_ACK;
                end
            end
        end
        
        CHECK_ACK: begin
            sda_oe <= 0; // 主机释放SDA
            
            if (i2c_clk_rising) begin
                if (sda_in == 0) begin // ACK detected
                    found <= 1;
                    addr_response <= addr_response | (1 << current_addr);
                    found_count <= found_count + 1;
                end
                next_state <= STOP;
            end
        end
        
        STOP: begin
            sda_oe <= 1;
            
            if (i2c_clk_falling) begin
                sda_out <= 0; // SCL低时SDA低
            end
            if (i2c_clk_rising) begin
                sda_out <= 1; // SCL高时SDA高(停止条件)
                next_state <= NEXT_ADDR;
            end
        end
        
        NEXT_ADDR: begin
            // 移动到下一个地址
            if (current_addr == 7'h7F) begin
                current_addr <= 7'h00;
            end else begin
                current_addr <= current_addr + 1;
            end
            next_state <= IDLE;
        end
        
        default: next_state <= IDLE;
    endcase
end

// 复位信号保持无效
assign SI_RSTBB = 1'b1;

// ILA实例化
ila_inst ila (
    .clk(clk),                   // 采样时钟
    .probe0(I2C_SI5394_SCL),     // I2C SCL
    .probe1(I2C_SI5394_SDA),     // I2C SDA
    .probe2(state),              // 状态机状态(3位)
    .probe3(current_addr_8bit),  // 当前扫描地址(8位)
    .probe4({7'b0, ack_detected}), // ACK检测信号
    .probe5(response_map),       // 地址响应位图(8位)
    .probe6({7'b0, found}),      // 当前地址发现标志
    .probe7(found_count)         // 发现设备计数
);

endmodule

运行结果如图所示:

image.png

能够找到器件地址为0x68

扫描二维码推送至手机访问。

版权声明:本文由我的FPGA发布,如需转载请注明出处。

本文链接:https://world.myfpga.cn/index.php/post/460.html

分享给朋友:

“Verilog IIC器件枚举工具 SI5341 SI5394等器件也可使用” 的相关文章

ALGO C4MB V11引脚参照表(持续更新)

ALGO C4MB V11引脚参照表(持续更新)

功能:常用引脚CLKPIN_E1LED0PIN_G15LED1PIN_F16LED2PIN_F15LED3PIN_D16KEY1PIN_E15KEY2PIN_E16KEY3PIN_M15KEY4PIN_M16RXDPIN_M2TXDPIN_G1功能:VGA引脚VGA_BLUE[0]PIN_C15VG...

基础实验十三,DS18B20温度传感器

基础实验十三,DS18B20温度传感器

//==========================================================================// Author     : ChanRa1n// Description: Training for Intel FPGA/...

Xilinx FIFO和ILA学习

Xilinx FIFO和ILA学习

`timescale 1ns / 1ps//-------------------------------------------------------//Filename       ﹕ FIFO_TOP.v//Author      ...

CDC 单脉冲信号处理

CDC 单脉冲信号处理

代码中的Sys_clk其实是没有用到的,项目文件:cdc_single.zip//------------------------------------------------------// File Name        : cdc.v// Autho...