zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    grunt in webstorm
    10+ Best Responsive HTML5 AngularJS Templates
    响应式布局
    responsive grid
    responsive layout
    js event bubble and capturing
    Understanding Service Types
    To add private variable to this Javascript literal object
    Centering HTML elements larger than their parents
    java5 新特性
  • 原文地址:https://www.cnblogs.com/Dinging006/p/9073560.html
Copyright © 2011-2022 走看看