• IIC通信控制的AD5259------在调试过程中遇到的奇葩问题


    首先说一下的遇到的问题:

    1.AD5259按照SCL是100KHz的情况下,可以正常接收上位机的数据,但是一段时间后,就不能正确的按照时序来走了

    原因在于AD5259在接收到上位机的数据后需要一定的响应时间,而在这个响应时间内,scl和sda都不应该有任何的活动,否则会导致不能准确接收下一个数据的开始信号,但要特别注意的是,这段时间内的SCL以及SDA的设置也是有一个说法的。

    2.断电后可以保持在正常工作的条件下。

    断电相当于是一个复位的过程,也就是说,复位后可以正常工作~

    3.网上找到的完整的IIC分析

    IIC协议

      IIC协议是一种多机通讯,由SDA数据线和SCL时钟线构成串行总线,所有的IIC设备都可以挂载到总线上,但每个设备都有唯一的设备读地址和设备写地址。在使用IIC作为数字接口的芯片datasheet中都可以看到该设备的设备读/写地址情况,并可以查找到相应的读写时序,以及对速率的要求。下图是一个通用的IIC协议时序:

    我们可以总结出五种IIC协议的时序状态:
      1. 空闲状态,当SDA和SCL两条信号线都处于高电平时总线处于空闲状态。
      2. 开始信号,SCL为高电平期间SDA信号线上产生了下降沿标志着的一次数据传输的开始。开始信号应当由主机发起。
      3. 数据传输,在SCL同步控制下SDA串行的传送每一位,因此传送8bits的数据需要8个SCL时钟。SCL为高电平时期SDA电平状态必须稳定;SCL为低电平期间才允许SDA改变状态。
      4. 应答信号,IIC总线上每传送一个8位字节,第9个脉冲期间便会释放总线,由接收器发出一个应答信号,反馈有没有成功接收。
      5. 停止信号,在SCL保持高电平期间,将SDA信号线释放恢复到高电平,标志一次数据传输的结束,IIC总线也重新回到了空闲状态。

    计数器控制IIC读写

      在“FPGA基础设计(三):UART串口通信”中已经接触到了使用计数器控制时序的方法,这个方法在控制IIC通信时同样实用。一次完整的写入操作如下所示:
    case( i )
    0: // iic Start
    begin
    isOut <= 1; //SDA端口输出

    if( C1 == 0 ) rSCL <= 1'b1;
    else if( C1 == 200 ) rSCL <= 1'b0; //SCL由高变低

    if( C1 == 0 ) rSDA <= 1'b1;
    else if( C1 == 100 ) rSDA <= 1'b0; //SDA先由高变低

    if( C1 == 250 -1) begin C1 <= 9'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1;
    end

    1: // Write Device Addr
    begin rData <= {4'b1010, 3'b000, 1'b0}; i <= 5'd7; Go <= i + 1'b1; end

    2: // Wirte Word Addr
    begin rData <= Addr_Sig; i <= 5'd7; Go <= i + 1'b1; end

    3: // Write Data
    begin rData <= WrData; i <= 5'd7; Go <= i + 1'b1; end

    4: //iic Stop
    begin
    isOut <= 1'b1;

    if( C1 == 0 ) rSCL <= 1'b0;
    else if( C1 == 50 ) rSCL <= 1'b1; //SCL先由低变高

    if( C1 == 0 ) rSDA <= 1'b0;
    else if( C1 == 150 ) rSDA <= 1'b1; //SDA由低变高

    if( C1 == 250 -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1;
    end

    5:
    begin isDone <= 1'b1; i <= i + 1'b1; end //写I2C 结束

    6:
    begin isDone <= 1'b0; i <= 5'd0; end

    7,8,9,10,11,12,13,14: //发送Device Addr/Word Addr/Write Data
    begin
    isOut <= 1'b1;
    rSDA <= rData[14-i]; //高位先发送

    if( C1 == 0 ) rSCL <= 1'b0;
    else if( C1 == 50 ) rSCL <= 1'b1;
    else if( C1 == 150 ) rSCL <= 1'b0;

    if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1;
    end

    15: // waiting for acknowledge
    begin
    isOut <= 1'b0; //SDA端口改为输入
    if( C1 == 100 ) isAck <= SDA;

    if( C1 == 0 ) rSCL <= 1'b0;
    else if( C1 == 50 ) rSCL <= 1'b1;
    else if( C1 == 150 ) rSCL <= 1'b0;

    if( C1 == F250K -1 ) begin C1 <= 9'd0; i <= i + 1'b1; end
    else C1 <= C1 + 1'b1;
    end

    16:
    if( isAck != 0 ) i <= 5'd0;
    else i <= Go;

    endcase

     向IIC总线写数据时,需要依次写入待写入的设备写地址、设备中的写地址和待写入的数据共3个8bits字节数据。i代表总线上不同的状态,通过计数器来控制状态之间的跳转。i为0时发出开始信号;i为7~14时控制8bits数据的发送;i为1、2、3时分别为设备地址、字节地址和数据,依次调用7-14完成数据的传输;其余还有停止位、应答位、IIC通信完成置位等状态。

      从器件中读取数据的方法与此一样,只不过通常都需要先向IIC总线写入待读取的设备地址和器件地址,之后再读数据。读数据整体过程比写数据要麻烦一点,但只要控制好状态之间跳转的过程即可。

    分频时钟控制IIC读写

      由计数器控制通信时序的方法优点是很灵活,几乎所有的时序方法都可以用这种方法完成;缺点就是太麻烦,需要控制好状态之间的跳转,时序越复杂使用越麻烦,其实在“FPGA采集-传输-显示系统(二):基于FPGA的温度采集和以太网传输”中,我对DS18B20的时序控制就是采用计数器控制的方法。DS18B20的时序要求较多,因此其中的状态跳转已经相当复杂。

      其实在控制IIC这种时钟速率固定的串行协议时,还可以在外部分频或PLL生成一个低频的通信时钟,用这个时钟来控制数据传输过程。如下所示:
    always@(posedge clock_i2c)
    begin
    if(reset_n==1'b0) begin
    tr_end<=0;
    ack1<=1;
    ack2<=1;
    ack3<=1;
    sclk<=1;
    reg_sdat<=1;
    end
    else
    case(cyc_count)
    begin ack1<=1;ack2<=1;tr_end<=0;sclk<=1;reg_sdat<=1;end
    reg_sdat<=0; //开始传输
    sclk<=0;
    reg_sdat<=i2c_data[23];
    reg_sdat<=i2c_data[22];
    reg_sdat<=i2c_data[21];
    reg_sdat<=i2c_data[20];
    reg_sdat<=i2c_data[19];
    reg_sdat<=i2c_data[18];
    reg_sdat<=i2c_data[17];
    reg_sdat<=i2c_data[16];
    reg_sdat<=1; //应答信号
    begin reg_sdat<=i2c_data[15];ack1<=i2c_sdat;end
    reg_sdat<=i2c_data[14];
    reg_sdat<=i2c_data[13];
    reg_sdat<=i2c_data[12];
    reg_sdat<=i2c_data[11];
    reg_sdat<=i2c_data[10];
    reg_sdat<=i2c_data[9];
    reg_sdat<=i2c_data[8];
    reg_sdat<=1; //应答信号
    begin reg_sdat<=i2c_data[7];ack2<=i2c_sdat;end
    reg_sdat<=i2c_data[6];
    reg_sdat<=i2c_data[5];
    reg_sdat<=i2c_data[4];
    reg_sdat<=i2c_data[3];
    reg_sdat<=i2c_data[2];
    reg_sdat<=i2c_data[1];
    reg_sdat<=i2c_data[0];
    reg_sdat<=1; //应答信号
    begin ack3<=i2c_sdat;sclk<=0;reg_sdat<=0;end
    sclk<=1;
    begin reg_sdat<=1;tr_end<=1;end //IIC传输结束
    endcase

  • 相关阅读:
    BZOJ3566: [SHOI2014]概率充电器
    BZOJ5018: [Snoi2017]英雄联盟
    BZOJ4627: [BeiJing2016]回转寿司
    BZOJ4719: [Noip2016]天天爱跑步
    BZOJ1511: [POI2006]OKR-Periods of Words
    BZOJ4721: [Noip2016]蚯蚓
    BZOJ1922: [Sdoi2010]大陆争霸
    BZOJ2525: [Poi2011]Dynamite
    单选按钮 / 复选框 样式自定义
    HDU 产生冠军 2094
  • 原文地址:https://www.cnblogs.com/Dinging006/p/9073560.html
Copyright © 2020-2023  润新知