IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> MCU_DESIGN_05MUC外设APB_IIC -> 正文阅读

[嵌入式]MCU_DESIGN_05MUC外设APB_IIC

1.APB_IIC架构

①由APB配置级寄存器,在通过byte和bit模块送到iic的SDA上

②这里数据的寄存移位只用到了一个模块,而UART用到了两个buf和移位,主要的原因就是iic属于半双工的传输,一次只能往一个方向传,而UART可以同时双向传输

在这里插入图片描述

③三态门总线结构,右边SCL、SDA接有上拉的电阻,使能路通路后,SCL取out的值

在这里插入图片描述

④IIC时序:
在这里插入图片描述

2.寄存器介绍

在这里插入图片描述
① Prescale : 5倍SCL关系

在这里插入图片描述

②Control register:使能、中断

在这里插入图片描述
③Transmit register:传输地址或者数据格式不一样,传数据的时候,[0]作为LSB,传地址的时候,[0]作为读写控制bit

在这里插入图片描述
④cmd_rigister

[7] 开始
[6] 结束
[5] 读
[4] 写
[3] 响应out
[0] 响应in

⑤Status register
[7]:rx的ack相应位
[6]:iic的busy信号位
[5]:传输数据仲裁
[4:2]:没用到
[1]:传输过程信号位
[0]:中断,一个字节传完会触发一次或者传输异常触发
在这里插入图片描述

3.RTL代码

在这里插入图片描述

3.1 i2c_master_top.v

①端口描述:APB的一些接口,以及IIC的SDA、SCL

module i2c_master_top
(
    input   wire        PCLKG,
    input   wire        PRESETn,
    
    input   wire        PSEL,
    input   wire [11:2] PADDR,
    input   wire        PENABLE,
    input   wire        PWRITE,
    input   wire [31:0] PWDATA,

    output  wire [31:0] PRDATA,
    output  wire        PREADY,
    output  wire        PSLVERR,
    output  reg         wb_inta_o,

    input               scl_pad_i,
    output  wire        scl_pad_o,
    output  wire        scl_padoen_o,

    input               sda_pad_i,
    output  wire        sda_pad_o,
    output  wire        sda_padoen_o

);

②内部信号:寄存器信号、地址信号、数据信号以及一些中断信号等

//internal sig

wire            wb_clk_i;
wire            arst_i;
wire [2:0]      wb_adr_i;
wire [7:0]      wb_dat_i;
wire [7:0]      wb_dat_o;
wire            wb_we_i;    //APB setup开始

reg [15:0]      prer;
reg [7:0]       ctr;
reg [7:0]       txr;
reg [7:0]       rxr;
reg [7:0]       cr;
reg [7:0]       sr;

wire            done;
wire            core_en;
wire            ien;

wire            irxack;
reg             rxack;
reg             tip;
reg             irq_flag;
wire            i2c_busy;
wire            i2c_al;//i2c bus arbitration lost
reg             al;//status reg arbitration lost bit

③重新定义了一下一些信号

assign      wb_clk_i = PCLKG;
assign      arst_i   = PRESETn;
assign      wb_adr_i = PADDR[4:2];
assign      wb_dat_i = PWDATA[7:0];
assign      wb_we_i  = PSEL & (!PENABLE) & PWRITE;

assign      PRDATA   = {{24{1'b0}},wb_dat_o};
assign      PREADY   = 1'b1;
assign      PSLVERR  = 1'b0;

wire rst_i = arst_i;
wire wb_wacc = wb_we_i;

④由地址决定寄存器:wb_dat_o 给到了PRDATA 的低8位

always@(posedge wb_clk_i)begin
    case (wb_adr_i)
        3'b000:wb_dat_o <= prer[7:0];
        3'b001:wb_dat_o <= prer[15:8];
        3'b010:wb_dat_o <= ctr;
        3'b011:wb_dat_o <= rxt;
        3'b100:wb_dat_o <= sr;
        3'b101:wb_dat_o <= txr;
        3'b110:wb_dat_o <= cr;
        3'b111:wb_dat_o <= 0;
    endcase
end

⑤寄存器取值:由输入地址,输入数据给不同的寄存器赋值

always @(posedge wb_clk_i or negedge rst_i)begin
    if(!rst_i)begin
        prer <= 16'hffff;
        ctr <= 8'h0;
        txr <= 8'h0;
    end
    else
        if(wb_wacc)
            case(wb_adr_i)
                3'b000:prer[7:0]  <= wb_dat_i;
                3'b001:prer[15:8] <= wb_dat_i;
                3'b010:ctr        <= wb_dat_i;
                3'b011:txr        <= wb_dat_i;
               default: ;
            endcase
end

always @(posedge wb_clk_i or negedge rst_i)begin
    if(!rst_i)
        cr <= 8'h0;
    else if(wb_wacc)begin
        if(core_en & (wb_adr_i == 3'b100))      //done 、i2c_al由i2c_master_byte_ctrl模块给出
            cr <= wb_dat_i;
        end
    else begin
        if(done | i2c_al)
            cr[7:4] <= 4'h0;
            cr[2:0] <= 3'b0;
         end
end
wire    sta = cr[7];
wire    sto = cr[6];
wire    rd  = cr[5];
wire    wr  = cr[4];
wire    ack = cr[3];
wire   iack = cr[0];

assign core_en = ctr[7];
assign ien     = ctr[6];

⑥例化i2c_master_byte_ctrl模块

i2c_master_byte_ctrl byte_controller
(
    .clk        (wb_clk_i),
    .nReset     (rst_i),
    .ena        (core_en),
    .clk_cnt    (prer),
    .start      (sta),
    .stop       (sto),
    .read       (rd),
    .write      (wr),
    .ack_in     (ack),
    .din        (txr),
    .cmd_ack    (done),
    .ack_out    (irxack),
    .dout       (rxr),
    .i2c_busy   (i2c_busy),
    .i2c_al     (i2c_al),
    .scl_i      (scl_pad_i),
    .scl_o      (scl_pad_o),
    .scl_oen    (scl_padoen_o),
    .sda_i      (sda_pad_i),
    .sda_o      (sda_pad_o),
    .sda_oen    (sda_padoen_o)
);

⑦Status register :先定义好每个位的作用,然后根据各个情况分布好功能

[7]:rx的ack响应位
[6]:iic的busy信号位
[5]:传输数据仲裁
[4:2]:没用到
[1]:传输过程信号位
[0]:中断,一个字节传完会触发一次或者传输异常触发

assign sr[7]    = rxack;
assign sr[6]    = i2c_busy;
assign sr[5]    = al;
assign sr[4:2]  = 3'h0;
assign sr[1]    = tip;
assign sr[0]    = irq_flag;

always @(posedge wb_clk_i or negedge rst_i)begin
    if(!rst_i)begin
        al <= 1'b0;
        rxack <= 1'b0;
        tip <= 1'b0;
        irq_flag <= 1'b0;
        end
    else begin
         al <= i2c_al | (al & !sta);
         rxack <= irxack;
         tip <= (rd | wr);
         irq_flag <= (done | i2c_al | irq_flag) & !iack;
        end
end

always @(posedge wb_clk_i or negedge rst_i)begin
    if(!rst_i)
        wb_inta_o <= 1'b0;
    else
        wb_inta_o <= irq_flag && ien;
end
endmodule

3.2 i2c_master_byte_ctrl.V

①端口描述:包括时钟命令使能、iic接口、命令信号、数据信号等

module i2c_master_byte_ctrl
(
    input           clk,
    input           nReset;
    input           ena;

    input [15:0]    clk_cnt;

    input           start;
    input           stop;
    input           read;
    input           write;
    input           ack_in;
    input [7:0 ]    din;

    output reg      cmd_ack;             
    output reg      ack_out;
    output          i2c_busy;
    output          i2c_al;
    output [7:0]    dout;

    input           scl_i;
    output          scl_o;
    output          scl_oen;

    input           sda_i;
    output          sda_o;
    output          sda_oen;
);

②全局状态机参数

//parameter
parameter [4:0] ST_IDEL     = 5'b00000;
parameter [4:0] ST_START    = 5'b00001;
parameter [4:0] ST_READ     = 5'b00010;
parameter [4:0] ST_WRITE    = 5'b00100;
parameter [4:0] ST_ACK      = 5'b01000;
parameter [4:0] ST_STOP     = 5'b10000;

parameter [3:0] I2C_CMD_NOP     = 4'b0000;
parameter [3:0] I2C_CMD_START   = 4'b0001;
parameter [3:0] I2C_CMD_STOP    = 4'b0010;
parameter [3:0] I2C_CMD_WRITE   = 4'b0100;
parameter [3:0] I2C_CMD_READ    = 4'b1000;

③内部信号:包括命令信号、tx、rx数据、移位寄存器等

//internal sig
reg [3:0]       core_cmd;
reg             core_txd;
wire            core_ack;
wire            core_rxd;

reg [7:0]       sr;//移位寄存器
reg             shift;//移位指示
reg             ld;//load指示

wire            go;
reg [2:0]       dcnt;
wire            cnt_done;

reg [4:0] c_state;

④例化i2c_master_bit_controller模块

//例化bit_controller
i2c_master_bit_controller bit_controller
(
    .clk            (clk),        
    .nReset         (nReset),
    .ena            (ena),
    .clk_cnt        (clk_cnt),
    .cmd            (core_cmd),
    .cmd_ack        (core_ack),
    .busy           (i2c_busy),
    .al             (i2c_al),
    .din            (core_txd),
    .dout           (core_rxd),
    .scl_i          (scl_i),
    .scl_o          (scl_o),
    .scl_oen        (scl_oen),
    .sda_i          (sda_i),
    .sda_o          (sda_o),
    .sda_oen        (sda_oen)

);

⑤起始信号go:当读写停止命令下,且无响应输出时,go拉高

assign go   = (read | write |stop) & !cmd_ack;

⑥移位寄存器sr设置

assign dout = sr;

always@(posedge clk or negedge nReset)begin
    if(!nReset)
        sr <= 8'h0;
    else if(ld)
        sr <= din;
    else if(shift)
        sr <= {sr[6:0],core_rxd};
end

always@(posedge clk or negedge nReset)begin
    if(!nReset)
        dcnt <= 3'h0;
    else if(ld)
        dcnt <= 3'h7;
    else if(shift)
        dcnt <= dcnt - 3'h1;
end

assign cnt_done = !(|dcnt);

⑦状态机:给出状态和当前命令

always@(posedge clk or negedge nReset)begin
    if(nReset)begin
        core_cmd <= I2C_CMD_NOP;
        core_txd <= 1'b0;
        shift    <= 1'b0;
        ld       <= 1'b0;
        cmd_ack  <= 1'b0;
        c_state  <= ST_IDEL;
        ack_out  <= 1'b0;
    end
    else if(i2c_al)begin
        core_cmd <= I2C_CMD_NOP;
        core_txd <= 1'b0;
        shift    <= 1'b0;
        ld       <= 1'b0;
        cmd_ack  <= 1'b0;
        c_state  <= ST_IDEL;
        ack_out  <= 1'b0;
    end
    else begin
        core_txd <= sr[7];
        shift    <= 1'b0;
        ld       <= 1'b0;
        cmd_ack  <= 1'b0;
        case(c_state)
            ST_IDEL:
                if(go)begin

                    if(start)begin
                        c_state     <= ST_START;
                        core_cmd    <= I2C_CMD_START; 
                    end

                    else if(read)begin
                        c_state     <= ST_READ;
                        core_cmd    <= I2C_CMD_READ;
                    end

                    else if(write)begin
                        c_state     <= ST_WRITE;
                        core_cmd    <= I2C_CMD_WRITE;
                    end

                    else begin
                        c_state     <= ST_STOP;
                        core_cmd    <= I2C_CMD_STOP;
                    end

                    ld <= 1'b1;
                end
            ST_START:
                if(core_ack)begin

                    if(read)begin
                        c_state     <= ST_READ;
                        core_cmd    <= I2C_CMD_READ;
                    end

                    else begin
                        c_state     <= ST_WRITE;
                        core_cmd    <= I2C_CMD_WRITE;
                    end
                    ld <= 1'b1;
                end
            ST_WRITE:
                if(core_ack)begin

                    if(cnt_done)begin
                        c_state     <= ST_ACK;
                        core_cmd    <= I2C_CMD_READ;
                    end
                    else begin
                        c_state     <= ST_WRITE;
                        core_cmd    <= I2C_CMD_WRITE;
                        shift       <= 1'b1;
                    end
                end                
            ST_READ:
                 if(core_ack)begin

                    if(cnt_done)begin
                        c_state     <= ST_ACK;
                        core_cmd    <= I2C_CMD_WRITE;
                    end
                    else begin
                        c_state     <= ST_READ;
                        core_cmd    <= I2C_CMD_READ;
                    end
                    shift       <= 1'b1;
                    core_txd    <= ack_in;
                end 
            ST_ACK:        
                if(core_ack)begin
                    if(stop)begin
                        c_state     <= ST_STOP;
                        core_cmd    <= I2C_CMD_STOP;
                    end
                    else begin
                        c_state     <= ST_IDEL;
                        core_cmd    <= I2C_CMD_NOP;
                        cmd_ack     <= 1'b1;
                    end
                    ack_out  <= core_rxd;
                    core_txd <= 1'b1;
                end
                else begin
                    core_txd <= ack_in;
                end
            ST_STOP:
                if(core_ack)begin
                         c_state     <= ST_IDEL;
                        core_cmd    <= I2C_CMD_NOP;
                        cmd_ack     <= 1'b1;
                end
        endcase
    end
end
endmodule

3.3 i2c_master_bit_ctrl.v

①端口描述:包括时钟复位命令、IIC接口等

module i2c_master_bit_ctrl (
    input             clk,      // system clock
   // input             rst,      // synchronous active high reset
    input             nReset,   // asynchronous active low reset
    input             ena,      // core enable signal

    input      [15:0] clk_cnt,  // clock prescale value

    input      [ 3:0] cmd,      // command (from byte controller)
    output reg        cmd_ack,  // command complete acknowledge
    output reg        busy,     // i2c bus busy
    output reg        al,       // i2c bus arbitration lost

    input             din,
    output reg        dout,

    input             scl_i,    // i2c clock line input
    output            scl_o,    // i2c clock line output
    output reg        scl_oen,  // i2c clock line output enable (active low)
    input             sda_i,    // i2c data line input
    output            sda_o,    // i2c data line output
    output reg        sda_oen   // i2c data line output enable (active low)
);

②全局参数:定义状态

parameter [3:0] I2C_CMD_NOP     = 4'b0000;
parameter [3:0] I2C_CMD_START   = 4'b0001;
parameter [3:0] I2C_CMD_STOP    = 4'b0010;
parameter [3:0] I2C_CMD_WRITE   = 4'b0100;
parameter [3:0] I2C_CMD_READ    = 4'b1000;

// nxt_state decoder
parameter [17:0] idle    = 18'b0_0000_0000_0000_0000;
parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;
parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;
parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;
parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;
parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;
parameter [17:0] stop_a  = 18'b0_0000_0000_0010_0000;
parameter [17:0] stop_b  = 18'b0_0000_0000_0100_0000;
parameter [17:0] stop_c  = 18'b0_0000_0000_1000_0000;
parameter [17:0] stop_d  = 18'b0_0000_0001_0000_0000;
parameter [17:0] rd_a    = 18'b0_0000_0010_0000_0000;
parameter [17:0] rd_b    = 18'b0_0000_0100_0000_0000;
parameter [17:0] rd_c    = 18'b0_0000_1000_0000_0000;
parameter [17:0] rd_d    = 18'b0_0001_0000_0000_0000;
parameter [17:0] wr_a    = 18'b0_0010_0000_0000_0000;
parameter [17:0] wr_b    = 18'b0_0100_0000_0000_0000;
parameter [17:0] wr_c    = 18'b0_1000_0000_0000_0000;
parameter [17:0] wr_d    = 18'b1_0000_0000_0000_0000;

③内部信号:这里多了一个延迟scl的使能和信号,当slave没有准备好时,可以通过把scl拉低进行等待

    reg [ 1:0] cSCL, cSDA;      // capture SCL and SDA
    reg [ 2:0] fSCL, fSDA;      // SCL and SDA filter inputs
    reg        sSCL, sSDA;      // filtered and synchronized SCL and SDA inputs
    reg        dSCL, dSDA;      // delayed versions of sSCL and sSDA
    reg        dscl_oen;        // delayed scl_oen
    reg        sda_chk;         // check SDA output (Multi-master arbitration)
    reg        clk_en;          // clock generation signals
    reg        slave_wait;      // slave inserts wait states
    reg [15:0] cnt;             // clock divider counter (synthesis)
    reg [13:0] filter_cnt;      // clock divider for filter
    
    // state machine variable
    reg [17:0] c_state; // synopsys enum_state
    reg sta_condition;
    reg sto_condition;
    reg cmd_stop;

④slave_wait的相关操作

    // whenever the slave is not ready it can delay the cycle by pulling SCL low
    // delay scl_oen
    always @(posedge clk)
      dscl_oen <= #1 scl_oen;

    // slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
    // slave_wait remains asserted until the slave releases SCL
    always @(posedge clk or negedge nReset)
      if (!nReset) slave_wait <= 1'b0;
      else         slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);

    // master drives SCL high, but another master pulls it low
    // master start counting down its low cycle now (clock synchronization)
    wire scl_sync   = dSCL & ~sSCL & scl_oen;

⑤时钟使能信号的产生:等待的时候不计数,使能为0

    // generate clk enable signal
    always @(posedge clk or negedge nReset)
      if (~nReset)
      begin
          cnt    <= #1 16'h0;
          clk_en <= #1 1'b1;
      end
      else if (rst || ~|cnt || !ena || scl_sync)
      begin
          cnt    <= #1 clk_cnt;
          clk_en <= #1 1'b1;
      end
      else if (slave_wait)
      begin
          cnt    <= #1 cnt;
          clk_en <= #1 1'b0;    
      end
      else
      begin
          cnt    <= #1 cnt - 16'h1;
          clk_en <= #1 1'b0;
      end

⑥总线状态捕获c:减少亚稳态风险

    // generate bus status controller

    // capture SDA and SCL
    // reduce metastability risk
    always @(posedge clk or negedge nReset)
      if (!nReset)
      begin
          cSCL <= #1 2'b00;
          cSDA <= #1 2'b00;
      end
      else if (rst)
      begin
          cSCL <= #1 2'b00;
          cSDA <= #1 2'b00;
      end
      else
      begin
          cSCL <= {cSCL[0],scl_i};
          cSDA <= {cSDA[0],sda_i};
      end

⑦滤波去毛刺f、同步化s、再做延迟d

    // filter SCL and SDA signals; (attempt to) remove glitches
    always @(posedge clk or negedge nReset)
      if      (!nReset     ) filter_cnt <= 14'h0;
      else if (rst || !ena ) filter_cnt <= 14'h0;
      else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency
      else                   filter_cnt <= filter_cnt -1;


    always @(posedge clk or negedge nReset)
      if (!nReset)
      begin
          fSCL <= 3'b111;
          fSDA <= 3'b111;
      end
      else if (rst)
      begin
          fSCL <= 3'b111;
          fSDA <= 3'b111;
      end
      else if (~|filter_cnt)
      begin
          fSCL <= {fSCL[1:0],cSCL[1]};
          fSDA <= {fSDA[1:0],cSDA[1]};
      end


    // generate filtered SCL and SDA signals
    always @(posedge clk or negedge nReset)
      if (~nReset)
      begin
          sSCL <= #1 1'b1;
          sSDA <= #1 1'b1;

          dSCL <= #1 1'b1;
          dSDA <= #1 1'b1;
      end
      else if (rst)
      begin
          sSCL <= #1 1'b1;
          sSDA <= #1 1'b1;

          dSCL <= #1 1'b1;
          dSDA <= #1 1'b1;
      end
      else
      begin
          sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);
          sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);

          dSCL <= #1 sSCL;
          dSDA <= #1 sSDA;
      end

⑧开始信号检测:当SCL为高,SDA下降沿时,IIC传输开始
busy :正在传输时,拉高busy

always @(posedge clk or negedge nReset)
  if (~nReset)
  begin
      sta_condition <= #1 1'b0;
      sto_condition <= #1 1'b0;
  end
  else if (rst)
  begin
      sta_condition <= #1 1'b0;
      sto_condition <= #1 1'b0;
  end
  else
  begin
      sta_condition <= #1 ~sSDA &  dSDA & sSCL;
      sto_condition <= #1  sSDA & ~dSDA & sSCL;
  end
// generate i2c bus busy signal
always @(posedge clk or negedge nReset)
  if      (!nReset) busy <= #1 1'b0;
  else if (rst    ) busy <= #1 1'b0;
  else              busy <= #1 (sta_condition | busy) & ~sto_condition;

⑨仲裁失败:主机SDA设置为高,I2C总线SDA为低,仲裁失败;没有请求时检测到停止信号,仲裁失败

// generate arbitration lost signal
// aribitration lost when:
// 1) master drives SDA high, but the i2c bus is low
// 2) stop detected while not requested

always @(posedge clk or negedge nReset)
  if (~nReset)
      cmd_stop <= #1 1'b0;
  else if (rst)
      cmd_stop <= #1 1'b0;
  else if (clk_en)
      cmd_stop <= #1 cmd == I2C_CMD_STOP;

always @(posedge clk or negedge nReset)
  if (~nReset)
      al <= #1 1'b0;
  else if (rst)
      al <= #1 1'b0;
  else
      al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);

⑩ 将SDA数据存起来:当SCL上升沿到来,存SDA数据

always @(posedge clk)
  if (sSCL & ~dSCL) 
  dout <= #1 sSDA;

?状态机:每个状态又分为5个小状态_abcde

每个状态分别对应:

下图均是 上SDA 下SCL
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

always @(posedge clk or negedge nReset)
  if (!nReset)
  begin
      c_state <= #1 idle;
      cmd_ack <= #1 1'b0;
      scl_oen <= #1 1'b1;
      sda_oen <= #1 1'b1;
      sda_chk <= #1 1'b0;
  end
  else if (rst | al)
  begin
      c_state <= #1 idle;
      cmd_ack <= #1 1'b0;
      scl_oen <= #1 1'b1;
      sda_oen <= #1 1'b1;
      sda_chk <= #1 1'b0;
  end
  else
  begin
      cmd_ack   <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle

      if (clk_en)
          case (c_state) // synopsys full_case parallel_case
                // idle state
                idle:
                begin
                    case (cmd) // synopsys full_case parallel_case
                         I2C_CMD_START: c_state <= #1 start_a;
                         I2C_CMD_STOP:  c_state <= #1 stop_a;
                         I2C_CMD_WRITE: c_state <= #1 wr_a;
                         I2C_CMD_READ:  c_state <= #1 rd_a;
                         default:        c_state <= #1 idle;
                    endcase

                    scl_oen <= #1 scl_oen; // keep SCL in same state
                    sda_oen <= #1 sda_oen; // keep SDA in same state
                    sda_chk <= #1 1'b0;    // don't check SDA output
                end

                // start
                start_a:
                begin
                    c_state <= #1 start_b;
                    scl_oen <= #1 scl_oen; // keep SCL in same state
                    sda_oen <= #1 1'b1;    // set SDA high
                    sda_chk <= #1 1'b0;    // don't check SDA output
                end

                start_b:
                begin
                    c_state <= #1 start_c;
                    scl_oen <= #1 1'b1; // set SCL high
                    sda_oen <= #1 1'b1; // keep SDA high
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                start_c:
                begin
                    c_state <= #1 start_d;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 1'b0; // set SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                start_d:
                begin
                    c_state <= #1 start_e;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 1'b0; // keep SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                start_e:
                begin
                    c_state <= #1 idle;
                    cmd_ack <= #1 1'b1;
                    scl_oen <= #1 1'b0; // set SCL low
                    sda_oen <= #1 1'b0; // keep SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                // stop
                stop_a:
                begin
                    c_state <= #1 stop_b;
                    scl_oen <= #1 1'b0; // keep SCL low
                    sda_oen <= #1 1'b0; // set SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                stop_b:
                begin
                    c_state <= #1 stop_c;
                    scl_oen <= #1 1'b1; // set SCL high
                    sda_oen <= #1 1'b0; // keep SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                stop_c:
                begin
                    c_state <= #1 stop_d;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 1'b0; // keep SDA low
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                stop_d:
                begin
                    c_state <= #1 idle;
                    cmd_ack <= #1 1'b1;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 1'b1; // set SDA high
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                // read
                rd_a:
                begin
                    c_state <= #1 rd_b;
                    scl_oen <= #1 1'b0; // keep SCL low
                    sda_oen <= #1 1'b1; // tri-state SDA
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                rd_b:
                begin
                    c_state <= #1 rd_c;
                    scl_oen <= #1 1'b1; // set SCL high
                    sda_oen <= #1 1'b1; // keep SDA tri-stated
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                rd_c:
                begin
                    c_state <= #1 rd_d;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 1'b1; // keep SDA tri-stated
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                rd_d:
                begin
                    c_state <= #1 idle;
                    cmd_ack <= #1 1'b1;
                    scl_oen <= #1 1'b0; // set SCL low
                    sda_oen <= #1 1'b1; // keep SDA tri-stated
                    sda_chk <= #1 1'b0; // don't check SDA output
                end

                // write
                wr_a:
                begin
                    c_state <= #1 wr_b;
                    scl_oen <= #1 1'b0; // keep SCL low
                    sda_oen <= #1 din;  // set SDA
                    sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
                end

                wr_b:
                begin
                    c_state <= #1 wr_c;
                    scl_oen <= #1 1'b1; // set SCL high
                    sda_oen <= #1 din;  // keep SDA
                    sda_chk <= #1 1'b0; // don't check SDA output yet
                                        // allow some time for SDA and SCL to settle
                end

                wr_c:
                begin
                    c_state <= #1 wr_d;
                    scl_oen <= #1 1'b1; // keep SCL high
                    sda_oen <= #1 din;
                    sda_chk <= #1 1'b1; // check SDA output
                end

                wr_d:
                begin
                    c_state <= #1 idle;
                    cmd_ack <= #1 1'b1;
                    scl_oen <= #1 1'b0; // set SCL low
                    sda_oen <= #1 din;
                    sda_chk <= #1 1'b0; // don't check SDA output (SCL low)
                end

          endcase
  end

?设置IIC的输出:接地

assign scl_o = 1'b0;
assign sda_o = 1'b0;

endmodule

参考:
https://blog.csdn.net/xiangsimoyinjiu/article/details/106175606?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165408452216782395325005%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=165408452216782395325005&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-106175606-null-null.142v11control,157v12control&utm_term=aribitration+lost&spm=1018.2226.3001.4187

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-08 19:10:53  更:2022-06-08 19:11:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 16:24:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码