凔海笔记之FPGA(九):Verilog描述IIC单字节读写协议

一、简介AT24C04

AT24C04是小容量(4KB)IIC总线EPROM存储元件。这句话说得很有内容呀。首先,AT24c04是存储元件,还是EPROM即可擦写可编程只读存储器,而且断电可保存。其次,对AT24c04的控制是采用IIC协议的,也就是说,IIC≠AT24C04,曾几何时,傻傻的以为IIC=AT24CXX。

那接下来,就先说一下AT24C04吧。

A0空引脚,不是地址设置引脚,A1/A2器件地址设置引脚,是用来设置器件地址的,可以挂4个AT24c04。WP写保护,低电平可对整个AT24c04的512字节进行读写操作,高电平则会使前256个地址受保护,只读不能写,后面的则爱咋地咋地了。SDA数据总线,是一个双向口,SCL则是时钟线。
IIC总线采用两线制,由数据线SDA和时钟线SCL构成。IIC总线对数据通信时序进行了严格的定义,主要包括起始、应答、结束还有数据读写的时序。
下面,就看看IIC单字节读写操作吧。n(*≧▽≦*)n

可见,写IIC协议就是玩拼图,拼的好与坏,就看咱对时序的分析了。
但在玩拼图之前咱还是先了解一下IIC协议的一些基本知识。
1、起始信号
    SCL保持高电平的状态下,SDA出现下降沿定义为I2C总线的起始信号,它是由主控器主动建立的一种电平跳变时序信号,标志着一次数据传输的开始,而在建立该信号之前IIC总线必须处于空闲状态。瞧下图

2、写地址
    写地址包括写设备地址和写数据地址。就如同笔者兼职家教,得先找到人家在哪个小区哪个楼,再找到人家在哪个单元等。然后才能去输出自己的知识(数据)。
写地址有固定的格式:

硬件ID:就是知道是哪个小区,它会随着厂商设备的种类不同而改变,例如:AT24C04是4’b1010。
硬件地址:就是芯片上的A0\A1\A2,A0空引脚(why?),A1/A2器件地址设置引脚,是用来设置器件地址的,可以挂4个AT24c04。
访问方向:写为1读是0。
写数据地址:AT24C04可以对512字节进行读写操作,而数据地址只有8位!也就是说,只能读写256字节,肿么破??????????????这时候会不会想到A0为什么说是空引脚呢?没错,它就是来凑数的,实现对512字节的读写。对此,我不得不说

还得补充一句,写数据是新的下降沿跟新数据,上升沿锁存/读取数据。
3、应答信号
 IIC总线上的所有数据都是以8位字节传送的,发送器每发送一个字节,就在下一个时钟脉冲释放数据线,由主机反馈一个应答信号。读数据就无视应答位。
  应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示主机已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示主机接收该字节没有成功。

4、读写数据:
写数据就是写数据是新的下降沿跟新数据,上升沿锁存/读取数据,并且高位在前
读数据可以看做重复读取8次应答位,SCL的下降沿使从机跟新数据,然后主机在SCL的上升沿读取数据,此外,从机也会由高到低更新数据位。
结束位:
    在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。
    停止信号也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,建立该信号之后,I2C总线将返回空闲状态。

所谓的空闲状态就是I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

(二)bala一下Verilog综合的AT24c04

上面介绍了IIC协议的一些概念,下面,就开始真二八经的用Verilog综合出来吧。首先来确定要实现的功能:向AT24C04写入123456,然后读出来送给6位数码管依次显示。
       接下来,先来说说大体的框架。
smg_display_module.v数码管显示模块,这块就不多说了吧,留着以后再bala吧。
IIC_function_module.v实现对AT24c04的读写时序的综合
IIC_ctrl.v实现对写、读AT24C04的控制和对数码管显示的控制。
这三个模块也就干这点活了

iAddr、iData分别是由IIC_ctrl模块发送给IIC_function_module地址地址和数据,oData是读出来的数据,共24位,一并发给数码管显示给我们看。iCall实现读写控制,oDone是完成信号,控制IIC_ctrl的工作启停。
      在这还是插句话吧,咱知道AT24c04的数据线是双向口,所以要用isQ来对数据线的输入输出状态进行选择。所以用实现,inout  SDA;assign SDA    =  isQ ? rSDA : 1'bz;isQ=1时为输出,即将数据写入AT24C04,isQ=0时为输入,即读出AT24C04数据。那为什么在输入时要设为高阻态呢?
      答:处于高阻抗状态时,输出电阻很大,相当于开路,没有任何逻辑控制功能。即可以认为是没有输出,对下级电路没有任何影响。而一个输出端口在高阻态的时候,其状态是由于其相连的其他电路决定的,可以将其看作是输入。当三态门的输出处于高阻状态的时候,取值由外部电路决定,也就是说,这一时刻是可以作为输入。

是否还记得,我们上节说了读写流程,就是下面这幅图,

仔细端详这幅图我们不难发现,我们要写的就是起始位,写数据,读数据,应答位,结束位,其他的

接下来开始苦干人生了
       IIC_function_module.v该模块要完成与AT 24C04的读写通讯,也就是IIC协议。说白了就是完成写字节和读字节,所以要直勾勾的盯着下面这张图来写一写

该图给出了AT24C04对时序的要求,高电平多少,低电平多少都有规范。可见,想实现度AT24C04的控制,要求的还是蛮多的。下面我们采用400KHz的时钟周期进行读写操作。

1、起始信号,也就是通知AT24c04要干活的指令是要求在时钟线拉高的情况下数据线产生一个负跳变(高电平变为低电平)。而且要求起始信号的保持直接不少于600ns.所以我们可以这样描述
            begin
            isQ <= 1'b1;
            rSCL <= 1'b1;
            
            if(C1 == 8'd0)
                rSDA <= 1'b1;
            else if(C1 == (TR+20))   //上升沿再保持400ns
                rSDA <= 1'b0;
                
            if(C1 == TCLK-1)     //一个时钟周期后进入下一步骤
                begin C1 <= 8'd0; i <= i + 1'b1; end
            else
                C1 <= C1 + 1'b1;
            end
    说一下哈,else if(C1 == (TR+20))那个20不是规定,使我想让它保持20的,其实也不需要一个时钟周期,只怪我愿意

2、应答位可以看做是读取一位数据,主机写完成或读取一字节时,从机都会产生应答位,在主机拉低SCL那一刻,从机便会发送应答位,主机借上升沿读取应答,应答信号低电平有效。
    5'd15:
            begin
            isQ <= 1'b0;
            if(C1 ==TF+8'd20)    isAck <= SDA;
            
            if(C1 == 8'd0)        rSCL <= 1'b0;
            else if(C1 == TF+8'd20)        rSCL <= 1'b1;
        
            if(C1 == TCLK -1'b1)
                begin C1 <= 8'd0; i <= i + 1'b1;    end
            else    C1 <= C1 + 1'b1;
            end
    5'd16:
        if(isAck != 1'b0)
                i <= 5'd0;
            else
                i <= jump;
3、结束位
    在SCL保持高电平时,SDA被释放,使得SDA返回高电平,即为停止信号,这也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,该信号建立后,IIC返回空闲状态。
            begin
            isQ <= 1'b1;
            if(C1 == 0)    rSCL <= 1'b0;
            else if(C1 == 8'd31)     rSCL <= 1'b1;
            
            if(C1==0)    rSDA <= 1'b0;
            else if(C1 == 8'd76)    rSDA <= 1'b1;
            
            if(C1 == 8'd155)    
                begin C1 <= 8'd0; i <= i + 1'b1; end
            else C1 <= C1 + 1'b1;
            end
4、写数据SCL下降沿更新数据,上升沿锁存数据

5'd7,5'd8,5'd9,5'd10,5'd11,5'd12,5'd13,5'd14:
            begin
            isQ <= 1'b1;    //写入AT24c04
            rSDA <= oData[5'd14 - i];
            
            if(C1 == 0)        rSCL <= 1'b0;
            else if(C1 == (TF+TLOW))        rSCL <= 1'b1;
            
            if(C1 == TCLK -1'b1)
                begin C1 <= 8'b0; i <= i + 1'b1;    end
            else    C1 <= C1 + 1'b1;
            end
5、读数据,权当读取八个应答信号吧
        5'd19,5'd20,5'd21,5'd22,5'd23,5'd24,5'd25,5'd26:
            begin
            isQ <= 1'b0;
            if(C1 == 8'd62)    rData[26-i] <=SDA;
            if(C1 == 0)    rSCL <= 1'b0;
            else    if(C1 == 8'd62) rSCL <= 1'b1;
            if(C1 == TCLK-1’b1)    
                begin    C1 <= 8'd0; i <= i + 1'b1;end
            else    C1 <= C1 + 1'b1;
            end

最后呢?就是IIC_ctrl中的内容了
case(i)
    3'd0:
        if(DoneU1)
                begin isCall <= 2'b00;i <= i + 1'b1;end
        else
                begin isCall <= 2'b10;rAd <= 8'd6;rDa <= 8'h21;end
                
    3'd1:
        if(DoneU1)
                begin    isCall<= 2'b00;i<= i + 1'b1;end
        else
                begin isCall <= 2'b10;rAd <= 8'd16;rDa <= 8'h43;end
                
    3'd2:
        if(DoneU1)
                begin isCall <= 2'b00;i <= i + 1'b1;end
        else
                begin isCall <= 2'b10;rAd <= 8'd66;rDa <= 8'h65;end
    3'd3:
        if(DoneU1)
            begin rNum[7:0] <= oData;isCall <= 2'b00;i <=i+1'b1; end
        else
                begin isCall <= 2'b01;rAd <= 8'd6;end
    3'd4:
        if(DoneU1)
            begin    rNum[15:8] <= oData;isCall <= 2'b00;i<=i + 1'b1;end
        else
                begin isCall <= 2'b01;rAd <= 8'd16;end
    3'd5:
        if(DoneU1)
               begin rNum[23:16] <= oData;isCall <= 2'b00;i<= i + 1'b1;end
        else
            begin isCall <= 2'b01;rAd <= 8'd66;end
    3'd6:
            i <= i;
            
        endcase

在地址6、16、66分别写入12、34、56。说实话我挺喜欢黑金这样的写法的,虽然不知道这样写算不算好的代码风格,但挺容易懂的。在完成信号来之前,重复进行一个动作,例如begin isCall <= 2'b10;rAd <= 8'd6;rDa <= 8'h21;end写操作,在地址6写入数据12,等完成信号来了,就进入下一个操作。

(0)

相关推荐

  • 【精品博文】IIC 通信协议的Verilog实现

    刚刚花了几天时间把 IIC 总算搞懂了一些,查了很多资料,也纠结过于很多细节,不过只要耐着性子,一点点的去理解,去尝试,终会得到你想要的结果,人生不也是吗,嘿嘿~ ,不闲扯了,下面就写写我的理解以及方 ...

  • IIC原理超详细讲解

    文章目录 IIC 简介 IIC的物理层 IIC的高阻态 IIC物理层总结: IIC的协议层 IIC 总线时序图 初始(空闲)状态 开始信号: 停止信号 数据有效性 应答信号 IIC数据传送 数据传送格 ...

  • 常用通信协议——IIC详解(全网最全)

    一.IIC 简介 I2C(Inter-Integrated Circuit) 是内部整合电路的称呼, 是一种串行通讯总线, 使用多主从架构, 由飞利浦公司在1980年为了让主板. 嵌入式系统或手机用以 ...

  • UC头条:IIC, SPI, UART, 单总线

    IIC与SPI通信 IIC SPI通信 IIC与SPI的比较 UART 单总线 因为面试时被问到IIC和SPI通信,所以又重新学习了一下. IIC IIC顾名思义就是两根线,一根SCL(时钟线),一根 ...

  • 一天一个设计实例-万字长文E2PROM接口电路、时序及应用程序设计

    因为IIC 接口的E2PROM存储芯片比较常见和实用,所以本节主要以I2C的接口电路为主,后期有需要再添加. 1.1.1I2C 总线规范简介 1) I2C 总线特性介绍 在现代电子产品开发过程中,为了 ...

  • IIC详解,包括原理、过程,最后一步步教你实现IIC

    IIC详解 1.I2C总线具有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL 2.IIC总线上可以挂很多设备:多个主设备,多个从设备(外围 设备).上图中主设备是两个单片机,剩下的都是从设备 ...

  • IIC总线知多少?

    注:本文转载自公众号"记得诚" ❝ IIC是串行总线,只用到两个线,应用非常广泛,本文介绍IIC的软件协议及硬件相关知识. ❞ 一.IIC概述 1. IIC定义 IIC总线是由Ph ...

  • 凔海笔记之FPGA(八):Verilog描述RS232 UART

    在我看来,有些代码会用,但未必理解,有些代码理解,但未必会写,有些代码会写,但未必能用自己的话说出来.当能够以自己的想法深入浅出的讲解所学知识,那也就可以说自己掌握了,所以,我还是来发帖吧. 记得刚用 ...

  • 凔海笔记之FPGA(四):Verilog HDL语法简单述

    在百度百科中,是这样介绍Verilog HDL的,它是一种硬件描述语言(HDL:Hardware Description Language),以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表 ...

  • 凔海笔记之FPGA(十一):SDRAM

    对于SDRAM,就以以下四个方面来写下自己的笔记吧 1.初探存储器 2.对SDRAM的认识 3.Verilog综合的SDRAM单字节读写时序 4.多字节读写和页读写 嗯,就这样 下图这个,学过数电的都 ...

  • 凔海笔记之FPGA(十):玩一玩DS1302

    现在这日子过得,一周四节课,没有考试没有作业更没有实验课,真不知道说什么好,还是来说说DS1302吧.(- ̄▽ ̄)-            它生有八脚,电源分主备,晶振有要求,时序有讲究,可记年月日, ...

  • 凔海笔记之FPGA(七):触发器和锁存器

    大多数数字系统中,除了需要具有逻辑运算和算数功能的组合逻辑电路外,还需要具有存储功能的电路,组合逻辑与时序逻辑可构成时序逻辑电路,简称时序电路.现在讨论实现存储功能的两种逻辑单元电路,即锁存器和触发器 ...

  • 凔海笔记之FPGA(五):(基本|| 组合)逻辑

    与门电路:有0则为0 与门(英语:AND gate)又称"与电路".逻辑"积".逻辑"与"电路.是执行"与"运算的基本逻 ...

  • 凔海笔记之FPGA(一):我和我的FPGA

    "老师,单片机那个试验箱都弄完了,接下来我想学学arm" "噢,那挺好的,要不你先学学FPGA吧,学好了FPGA再接触arm会学得更好些" "FPGA ...

  • 凔海笔记之单片机(五):给按键编个码

    按键通常是一种长常开型按钮开关,例如下图,如果不按动得话它就是断开状态的. 它作为单片机的附属小鬼,主要就是为了让单片机检测出它的状态,然后单片机根据这个状态来干一些事.例如,当按键按下灯亮,当按键按 ...

  • 海厦伤寒论笔记(五九)

    伤寒论第50条辨:脉浮紧者,法当身疼痛,宜以汗解之.假令尺中迟者,不可发汗.何以知之然?以荣气不足,血少故也. 原文解释:脉象浮紧的是太阳伤寒症的脉象,照理应当出现身体疼痛等太阳伤寒见症,宜用发汗法来 ...