【FPGA】verilog实现的i2c接口控制

i2c协议规范:

一、时钟

首先第一步是产生fast-mode的400khz的scl速率,假设方波高低电平各占一半,即1.25us,理论上不满足规范上scl低周期1.3us,但是绝大多数器件都支持稍微超过400khz的速率。

我们仍打算产生一个规范内的速率。输入时钟clk=20mhz,计数12+1次后翻转,即可产生一个周期为13x2x50ns=1.3us的方波clk_800,这个周期满足规范。

也可以改变计数方式,产生一个高低占比不一样的波形,可以适当提高速率,同时也满足规范。

//    +clk2------------------------------------------
//    1) 20mhz -> clk2 -> SCL-400khz  clk2==2xSCL
//    2) cnt = 20m/800k = 25 /2 = 12 cnt[3:0]
//    -clk2------------------------------------------
always @(posedge clk or negedge rst_n)
    if(rst_n==0)
        begin
        cnt_clk <= 0;
        clk_800k <= 0;
        end
    else if(cnt_clk==12)
        begin
        cnt_clk <= 0;
        clk_800k <= ~clk_800k;// [email protected] [email protected]
        end
    else
        cnt_clk <= cnt_clk +1;

二、我们的规划是,scl在clk_800k的下降沿翻转,而sda在clk_800k的上升沿变化,这样就能保证在scl的高电平周期,sda是绝对稳定的,同时也能方便地产生start/stop条件。

根据上面clk的计数,可知scl的周期是1.3us x2=2.6us,速率约是384khz,没到400k。

//    +iic------------------------------------------
//    1)
//    -iic------------------------------------------
always @(negedge clk_800k or negedge rst_n)// negedge
    if(rst_n==0)
        iic_scl <= 0;
    else
        iic_scl <= ~iic_scl;// 400k

三、接下来就是采用状态机控制产生协议要求的时序波形。在clk_800k的rising沿动作。

IIC_start:检测到scl的高,将sda拉低,产生start条件。占用了1/4个scl周期,0.65us,完全满足start的建立条件;

IIC_data_setup:这一节拍正好是scl的低周期,不需要判断,在sda上送出数据的MSB;

IIC_data_hold:scl的高周期,sda必须保持不变。循环传出8个bit,完成一个字节后跳到下一状态;

IIC_ack_setup:先要释放sda,让从器件去拉低响应;

IIC_ack_hold:判断响应;如果不响应,或者我这里要求传完3个byte的数据,跳到下一状态;

IIC_stop_setup:这一步主要是把sda拉低,准备做stop;

IIC_stop_hold:在scl高周期,sda拉高,产生stop条件;结束。

只要第一步的start条件切入准了,后面按照节拍来,就不需要反复判断scl的高低了。

//    +iic------------------------------------------
//    1)
//    -iic------------------------------------------
always @(posedge clk_800k or negedge rst_n)
    if(rst_n==0)
        begin
        NS_iic <= IIC_idle;
        iic_sda <= 1;
        finish_iic <= 0;
        end
    else
        case(NS_iic)
            IIC_idle:
                begin
                if(start_iic==1)
                    NS_iic <= IIC_start;
                else
                    NS_iic <= IIC_idle;
                end
            IIC_start:
                begin
                if(iic_scl==1)
                    begin
                    NS_iic <= IIC_data_setup;
                    iic_sda <= 0;// start condition
                    data_iic <= bram_dout[23:0];
                    cnt_byte <= 2;
                    cnt_bit <= 0;// 0->7
                    end
            //    else
            //        NS_iic <= IIC_start;
                end
            IIC_data_setup:// data setup
                begin
                NS_iic <= IIC_data_hold;
                iic_sda <= data_iic[23];
                cnt_bit <= cnt_bit -1;
                end
            IIC_data_hold:// data hold
                begin
                if(cnt_bit==0) NS_iic <= IIC_ack_setup;
                else NS_iic <= IIC_data_setup;
                data_iic <= {data_iic[22:0],1‘b0};
                end
            IIC_ack_setup:// ack prepare
                begin
                NS_iic <= IIC_ack_hold;
                iic_sda <= 1‘bz;
                end
            IIC_ack_hold:// ack response
                begin
                if(iic_sda==1||cnt_byte==0)
                    NS_iic <= IIC_stop_setup;
                else
                    NS_iic <= IIC_data_setup;
                cnt_byte <= cnt_byte -1;
                end
            IIC_stop_setup:
                begin
                NS_iic <= IIC_stop_hold;
                iic_sda <= 0;
                finish_iic <= 1;
                end
            IIC_stop_hold:
                begin
                NS_iic <= IIC_idle;
                iic_sda <= 1;
                finish_iic <= 0;
                end
            default:
                begin
                NS_iic <= IIC_idle;
                end
        endcase

每次发送3字节的数据,addr+reg+data。cnt_byte是计数3个字节的cnt_bit是计数每个字节内的bit位。蓝色是相应位。

start条件。发送的数据是AA,即10101010,跟计数位相对应。

stop条件。

//

时间: 2024-08-01 07:05:49

【FPGA】verilog实现的i2c接口控制的相关文章

FPGA Verilog HDL 系列实例--------步进电机驱动控制

[连载] FPGA Verilog HDL 系列实例 Verilog HDL 之 步进电机驱动控制 步进电机的用途还是非常广泛的,目前打印机,绘图仪,机器人等等设备都以步进电机为动力核心.那么,下面我们就了解下什么是步进电机,它是怎么控制的. 一.步进电机相关知识简介 1.步进电机概述 步进电机是一种能够将电脉冲信号转换成角位移或线位移的机电元件,它实际上是一种单相或多相同步电动机.单相步进电动机有单路电脉冲驱动,输出功率一般很小,其用途为微小功率驱动.多相步进电动机有多相方波脉冲驱动,用途很广

(6)s3c2440用I2C接口访问EEPROM

在前面阅读理解了I2C的官方协议文档后,就拿s3c2440和EEPROM来验证一下. 本来是想用s3c2440的SDA和SCL管脚复用为GPIO来模拟的,但在没有示波器的情况下搞了一周,怎么都出不来,最后还是放弃了.甚至参考了linux下i2c-algo-bit.c和i2c-gpio.c,依然没调出来.如果有示波器,可能很快就能找到原因,现在完全不知道问题出在哪里.其实想用GPIO模拟I2C的目的很简单,以一种简单而又深刻的方式来理解I2C. 既然这条路暂时没法走,退而求其次,用s3c2440的

[FPGA]Verilog 60s秒表计时器(最大可计时间长达9min)

[FPGA]Verilog 60s秒表计时器 1.引述 这次的实验来自于本人本科课程数电结课时的自选题目.由于这次上传是后知后觉,学校已将小脚丫板子回收,所以在这篇文章中没法贴出代码结果的效果图了,但最终效果已经过测试,可放心食用.那么下面就贴上代码并略加讲解供大家参考. 2.分频模块 我们要实现一个秒表,自然要将实验板中的时钟脉冲clk分频为一个周期为1s的脉冲,已知小脚丫板子的晶振为12MHz.下面贴上分频模块的代码. module divide # ( //parameter是verilo

linux 标准i2c接口(一)

一:I2C设备操作方式: 1.  应用程序操作法:i2c的设备的驱动可以直接利用linux内核提供的i2c-dev.c文件提供的ioctl函数接口在应用层实现对i2c设备的读写,但是在应用层使用ioctl函数对应用程序员要求较高,需要自行构建msg结构体,必须了解设备的操作流程,时序之类的. 这方式实现需要用用程序员调用 read, write, ioctl, open, close等linux标准文件接口操作/dev/i2c(X)设备文件.   2. 驱动程序操作法:i2c设备的驱动也可以通过

树莓派配置RTC时钟(DS3231,I2C接口)

1.购买基于DS3231的RTC时钟模块,并且支持3.3V的那种 2.配置树莓派 a.打开树莓派的i2c接口 sudo raspi-config -->Interfacing Options -->I2C,全部选择yes b.添加i2c模块     sudo nano /etc/modules     然后添加以下两行内容:         i2c-bcm2708         i2c-dev c.安装i2c工具,查看i2c设备b sudo apt-get install i2c-tools

FPGA基础知识7(从芯片手册获取参数FPGA时序约束--“CMOS Sensor接口时序约束”)

需求说明:FPGA基本知识 内容       :如何确定时序约束数值 来自       :时间的诗 来源:http://www.61ic.com/Technology/embed/201304/48186.html FPGA工程的功能框图如图所示.上电初始,FPGA需要通过IIC接口协议对摄像头模块进行寄存器初始化配置.这个初始化的基本参数,如初始化地址和数据存储在一个预先配置好的FPGA内嵌ROM中.在初始化配置完成后,摄像头就能够持续输出RGB标准的视频数据流,FPGA通过对其相应的时钟.行

(10)用树莓派B+的GPIO接口控制发光二极管闪烁

从本篇开始,将逐步学习和分享树莓派GPIO相关操作,由于本人也是这方面的小白,关于接口.跳线.面包板.电流电压之类的叙述,可能有不准确的地方,还请大家仅将本系列文章作为入门读物. 本文需要的一些元件:母对公杜邦线N条,面包板1块,暂不需要面包板外接电源,发光二极管(电压2V-3.3V),电阻约400欧1个. 必须要了解的知识:根据树莓派官方文档的描述(见https://www.raspberrypi.org/documentation/hardware/raspberrypi/power/REA

[FPGA] Verilog 燃气灶控制器的设计与实现

燃气灶控制器的设计与实现 一.引述 本次实验所用可编程器件型号为MAXII EPM1270T144C5(其引脚表见本人另一博文,链接为 https://www.cnblogs.com/RDJLM/p/12075584.html),通过可编程实验板实现一个基本的模拟燃气灶. 二.设计课题的基本要求 1. 燃气灶的控制按键有三个:点火/关闭按键 BTN7.火力调节按键 BTN6(火力增大) 和 BTN5(火力减小) 2. 用 8×8 双色点阵模拟显示燃气灶的灶眼,用如图 1 所示的四个点阵显示状态分

IRequiresSessionState接口控制

刚刚接触.net web端的朋友都会被Session坑过,莫名其妙的不能读取Session数据,后来知道原来有IRequiresSessionState这个接口,不继承的就不能读取Session里面的数据,知道这个以后呢,也不清楚里面具体是如何实现的.对此一直不甘心,于是查了各方面的资料终于模拟出来了. 在一般处理程序(ashx文件)里面有个一个(HttpContext Context),F12进入HttpContext 类你面你会发现它应该是用了单例的模式,里面有个 public static