基于FPGA的MCP4725驱动程序

2023-11-07

基于FPGA的MCP4725驱动程序

  1. 芯片资料
          MCP4725是低功耗、高精度、单通道的12位缓冲电压输出数模转换器(Digital-to-Analog Convertor,DAC),具有非易失性存储器(EEPROM)。用户可以使用I2C接口命令将DAC输入和配置数据烧写到非易失性存储器(EEPROM)。非易失性存储器功能使得DAC器件在断电期间仍能保持DAC输入代码,且DAC输出在上电后立即可用。
    在这里插入图片描述

                                                    图1.MCP4725功能框图
      MCP4725具有外部A0地址位选择引脚。此A0引脚可连接用户应用电路板的VDD或VSS。MCP4725具有2线型IIC兼容串行接口,可用于标准(100 kHz)、快速(400 kHz)或高速(3.4 MHz)模式。
图2.MCP4725封装类型
   Vout:模拟输出电压;
   Vss:参考地;
   VDD:电源电压;3.7~5.5V
   SDA:IIC串行数据;
   SCL:IIC串行时钟输入
   A0:地址位选择引脚;该引脚可连接到VSS或VDD ,或由数字逻辑电平有效驱动。该引脚的逻辑状态决定了I2 C地址位的A0位。
2. 输出电压计算
在这里插入图片描述
      例如当我们输入0x400,即十进制数1024,电源电压接入为5V,那么输出电压Vout=5*1024/4096=1.25V。
3. 工作原理
      当器件连接到I2C总线时,器件作为从器件工作。使用I2C接口命令,主器件可以读/写DAC输入寄存器或EEPROM。MCP4725器件地址包含4个固定位(1100 =器件代码)和3个地址位(A2、A1和A0)。A2和A1位是在出厂前硬连线的,而A0位由A0引脚的逻辑状态决定。A0引脚可连接到VDD或VSS,或由数字逻辑电平有效驱动。写命令用于将配置位和DAC输入代码装载到DAC寄存器,或写入器件的EEPROM。通过使用3个写命令类型位(C2、C1和C0)定义写命令类型。
在这里插入图片描述
      当C2=0,C1=0 时,为快速模式,此命令用于更改DAC寄存器,EEPROM不受影响;当C2=0,C1=1,C0=0 时,为写DAC寄存器模式,即将配置位和数据代码装载到DAC寄存器;当C2=0,C1=1,C0=1 时,为写DAC寄存器和更新EEPROM模式,将配置位和数据代码装载到DAC寄存器并且写入EEPROM中。本次主要使用写DAC寄存器模式和写DAC寄存器和更新EEPROM模式,如下图所示。
在这里插入图片描述
      第一个字节为器件寻址,A2和A1已经被厂家设置为0,A0由自己控制(默认为0,即接地),因此第一个字节为0x60;第二个字节为写数据地址,PD0和PD1都为0时为正常模式,因此第二个字节为0x60;第三个字节和第四个字节的高4位组成12位数据输入,由我们自己定义输入。
4. IIC串行通信
      MCP4725器件使用2线IIC串行接口,该接口可在标准、快速或高速模式下工作。在总线上发送数据的器件定义为发送器,而接收数据的器件定义为接收器。总线必须由主器件控制,主器件产生串行时(SCL)信号、控制总线访问权并产生启动条件和停止条件。MCP4725器件作为从器件工作。主器件和从器件都可以作为发送器或接收器工作,但是由主器件决定激活哪种模式。通信由主器件(单片机)发起,它发送启动位,随后是从地址字节。发送的第一个字节始终为从地址字节,它包含器件代码、地址位和R/W位。MCP4725器件的器件代码为1100。当器件接收到读命令(R/W = 1)时,发送DAC输入寄存器和EEPROM的内容。下图给出了IIC通信时序要求。
在这里插入图片描述
      在本次设计中,SCL时钟输入频率选择为250KHz,FPGA工作时钟为50MHz,上电等待20ms后开始IIC数据写入。采用模块化设计,分为IIC驱动设计,MCP4725初始化设计,顶层模块。
5. 代码模块

5.1 IIC驱动模块

module i2c_dri
    #(// slave address(器件地址)
      parameter   SLAVE_ADDR =  7'b1100000  ,
      parameter   CLK_FREQ   = 26'd50_000_000,   //  时钟频率(CLK_FREQ)
      parameter   I2C_FREQ   = 18'd250_000       // I2C的SCL时钟频率
     )(
          //global clock
          input                clk        ,      // 时钟
          input                rst_n      ,      // 复位信号

          //i2c interface
          input                i2c_exec   ,      // I2C触发执行信号
          input                bit_ctrl   ,      // 字地址位控制(16b/8b)
          input                i2c_rh_wl  ,      // I2C读写控制信号
          input        [15:0]  i2c_addr   ,      // I2C器件内地址
          input        [15:0]  i2c_data_w ,      // I2C要写的数据
          output  reg  [ 7:0]  i2c_data_r ,      // I2C读出的数据
          output  reg          i2c_done   ,      // I2C一次操作完成
          output  reg          scl        ,      // I2C的SCL时钟信号
          inout                sda        ,      // I2C的SDA信号

          //user interface
          output  reg          dri_clk           // 驱动I2C操作的驱动时钟
     );

//localparam define
localparam  st_idle     = 8'b0000_0001;          // 空闲状态
localparam  st_sladdr   = 8'b0000_0010;          // 发送器件地址(slave address)
localparam  st_addr16   = 8'b0000_0100;          // 发送16位字地址
localparam  st_addr8    = 8'b0000_1000;          // 发送8位字地址
localparam  st_data_wr  = 8'b0001_0000;          // 写数据(8 bit)
localparam  st_addr_rd  = 8'b0010_0000;          // 发送器件地址读
localparam  st_data_rd  = 8'b0100_0000;          // 读数据(8 bit)
localparam  st_stop     = 8'b1000_0000;          // 结束I2C操作

//reg define
reg            sda_dir     ;                     // I2C数据(SDA)方向控制
reg            sda_out     ;                     // SDA输出信号
reg            st_done     ;                     // 状态结束
reg            wr_flag     ;                     // 写标志
reg    [ 6:0]  cnt         ;                     // 计数
reg    [ 7:0]  cur_state   ;                     // 状态机当前状态
reg    [ 7:0]  next_state  ;                     // 状态机下一状态
reg    [15:0]  addr_t      ;                     // 地址
reg    [ 7:0]  data_r      ;                     // 读取的数据
reg    [15:0]  data_wr_t   ;                     // I2C需写的数据的临时寄存
reg    [ 9:0]  clk_cnt     ;                     // 分频时钟计数

//wire define
wire          sda_in      ;                      // SDA输入信号
wire   [8:0]  clk_divide  ;                      // 模块驱动时钟的分频系数



//SDA控制
assign  sda     = sda_dir ?  sda_out : 1'bz;     // SDA数据输出或高阻
assign  sda_in  = sda ;                          // SDA数据输入
assign  clk_divide = (CLK_FREQ/I2C_FREQ) >> 3;   // 模块驱动时钟的分频系数

//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dri_clk <=  1'b1;
        clk_cnt <= 10'd0;
    end
    else if(clk_cnt == clk_divide - 1'd1) begin
        clk_cnt <= 10'd0;
        dri_clk <= ~dri_clk;
    end
    else
        clk_cnt <= clk_cnt + 1'b1;
end

//(三段式状态机)同步时序描述状态转移
always @(posedge dri_clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= st_idle;
    else
        cur_state <= next_state;
end

//组合逻辑判断状态转移条件
always @( * ) begin
//    next_state = st_idle;
    case(cur_state)
        st_idle: begin                           // 空闲状态
           if(i2c_exec) begin
               next_state = st_sladdr;
           end
           else
               next_state = st_idle;
        end
        st_sladdr: begin
            if(st_done) begin
                if(bit_ctrl)                     // 判断是16位还是8位字地址
                   next_state = st_addr16;
                else
                   next_state = st_addr8 ;
            end
            else
                next_state = st_sladdr;
        end
        st_addr16: begin                         // 写16位字地址
            if(st_done) begin
                next_state = st_addr8;
            end
            else begin
                next_state = st_addr16;
            end
        end
        st_addr8: begin                          // 8位字地址
            if(st_done) begin
                if(wr_flag==1'b0)                // 读写判断
                    next_state = st_data_wr;
                else
                    next_state = st_addr_rd;
            end
            else begin
                next_state = st_addr8;
            end
        end
        st_data_wr: begin                        // 写数据(8 bit)
            if(st_done)
                next_state = st_stop;
            else
                next_state = st_data_wr;
        end
        st_addr_rd: begin                        // 写地址以进行读数据
            if(st_done) begin
                next_state = st_data_rd;
            end
            else begin
                next_state = st_addr_rd;
            end
        end
        st_data_rd: begin                        // 读取数据(8 bit)
            if(st_done)
                next_state = st_stop;
            else
                next_state = st_data_rd;
        end
        st_stop: begin                           // 结束I2C操作
            if(st_done)
                next_state = st_idle;
            else
                next_state = st_stop ;
        end
        default: next_state= st_idle;
    endcase
end

//时序电路描述状态输出
always @(posedge dri_clk or negedge rst_n) begin
    //复位初始化
    if(!rst_n) begin
        scl        <= 1'b1;
        sda_out    <= 1'b1;
        sda_dir    <= 1'b1;
        i2c_done   <= 1'b0;
        cnt        <= 1'b0;
        st_done    <= 1'b0;
        data_r     <= 1'b0;
        i2c_data_r <= 1'b0;
        wr_flag    <= 1'b0;
        addr_t     <= 1'b0;
        data_wr_t  <= 1'b0;
    end
    else begin
        st_done <= 1'b0 ;
        cnt     <= cnt +1'b1 ;
        case(cur_state)
             st_idle: begin                            // 空闲状态
                scl     <= 1'b1;
                sda_out <= 1'b1;
                sda_dir <= 1'b1;
                i2c_done<= 1'b0;
                cnt     <= 7'b0;
                if(i2c_exec) begin
                    wr_flag   <= i2c_rh_wl ;
                    addr_t    <= i2c_addr  ;
                    data_wr_t <= i2c_data_w;
                end
            end
            st_sladdr: begin                           // 写地址(器件地址和字地址)
                case(cnt)
                    7'd1 : sda_out <= 1'b0;            // 开始I2C
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= SLAVE_ADDR[6];   // 传送器件地址
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= SLAVE_ADDR[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= SLAVE_ADDR[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= SLAVE_ADDR[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= SLAVE_ADDR[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= SLAVE_ADDR[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= SLAVE_ADDR[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: sda_out <= 1'b0;            // 0:写
                    7'd33: scl <= 1'b1;
                    7'd35: scl <= 1'b0;
                    7'd36: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd37: scl     <= 1'b1;
                    7'd38: st_done <= 1'b1;
                    7'd39: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_addr16: begin
                case(cnt)
                    7'd0 : begin
                        sda_dir <= 1'b1 ;
                        sda_out <= addr_t[15];         // 传送字地址
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= addr_t[14];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= addr_t[13];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= addr_t[12];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= addr_t[11];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= addr_t[10];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= addr_t[9];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= addr_t[8];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_addr8: begin
                case(cnt)
                    7'd0: begin
                       sda_dir <= 1'b1 ;
                       sda_out <= addr_t[7];           // 字地址
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= addr_t[6];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= addr_t[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= addr_t[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= addr_t[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= addr_t[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= addr_t[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= addr_t[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default :  ;
                endcase
            end
            st_data_wr: begin                          // 写数据(12 bit)
                case(cnt)
                    7'd0: begin
                        sda_out <= data_wr_t[15];       // I2C写2次8位数据
                        sda_dir <= 1'b1;
                    end
                    7'd1 : scl <= 1'b1;
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= data_wr_t[14];
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= data_wr_t[13];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= data_wr_t[12];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= data_wr_t[11];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= data_wr_t[10];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= data_wr_t[9];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= data_wr_t[8];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl <= 1'b1;
              
                    7'd35: scl  <= 1'b0;
                    7'd36: sda_out <= data_wr_t[7];
					     7'd37: scl <= 1'b1;
					     
					     7'd39: scl  <= 1'b0;
					     7'd40: sda_out <= data_wr_t[6];
					     7'd41: scl <= 1'b1;
		              
						  7'd43: scl  <= 1'b0;
					     7'd44: sda_out <= data_wr_t[5];
					     7'd45: scl <= 1'b1;
						
				        7'd47: scl  <= 1'b0;
					     7'd48: sda_out <= data_wr_t[4];
					     7'd49: scl <= 1'b1;
						  
						  7'd51: scl  <= 1'b0;
					     7'd52: sda_out <= data_wr_t[3];
					     7'd53: scl <= 1'b1;
						  
						  7'd55: scl  <= 1'b0;
					     7'd56: sda_out <= data_wr_t[2];
					     7'd57: scl <= 1'b1;
						  
						  7'd59: scl  <= 1'b0;
					     7'd60: sda_out <= data_wr_t[1];
					     7'd61: scl <= 1'b1;
						  
						  7'd63: scl  <= 1'b0;
					     7'd64: sda_out <= data_wr_t[0];
					     7'd65: scl <= 1'b1;
						  
						  7'd67: scl <= 1'b0;
                    7'd68: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd69: scl <= 1'b1;
                    7'd70: st_done <= 1'b1;
                    7'd71: begin
                        scl  <= 1'b0;
                        cnt  <= 1'b0;
                    end
				 		                                
                    default  :  ;
                endcase
            end
            st_addr_rd: begin                          // 写地址以进行读数据
                case(cnt)
                    7'd0 : begin
                        sda_dir <= 1'b1;
                        sda_out <= 1'b1;
                    end
                    7'd1 : scl <= 1'b1;
                    7'd2 : sda_out <= 1'b0;            // 重新开始
                    7'd3 : scl <= 1'b0;
                    7'd4 : sda_out <= SLAVE_ADDR[6];   // 传送器件地址
                    7'd5 : scl <= 1'b1;
                    7'd7 : scl <= 1'b0;
                    7'd8 : sda_out <= SLAVE_ADDR[5];
                    7'd9 : scl <= 1'b1;
                    7'd11: scl <= 1'b0;
                    7'd12: sda_out <= SLAVE_ADDR[4];
                    7'd13: scl <= 1'b1;
                    7'd15: scl <= 1'b0;
                    7'd16: sda_out <= SLAVE_ADDR[3];
                    7'd17: scl <= 1'b1;
                    7'd19: scl <= 1'b0;
                    7'd20: sda_out <= SLAVE_ADDR[2];
                    7'd21: scl <= 1'b1;
                    7'd23: scl <= 1'b0;
                    7'd24: sda_out <= SLAVE_ADDR[1];
                    7'd25: scl <= 1'b1;
                    7'd27: scl <= 1'b0;
                    7'd28: sda_out <= SLAVE_ADDR[0];
                    7'd29: scl <= 1'b1;
                    7'd31: scl <= 1'b0;
                    7'd32: sda_out <= 1'b1;            // 1:读
                    7'd33: scl <= 1'b1;
                    7'd35: scl <= 1'b0;
                    7'd36: begin
                        sda_dir <= 1'b0;               // 从机应答
                        sda_out <= 1'b1;
                    end
                    7'd37: scl     <= 1'b1;
                    7'd38: st_done <= 1'b1;
                    7'd39: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                    end
                    default : ;
                endcase
            end
            st_data_rd: begin                          // 读取数据(8 bit)
                case(cnt)
                    7'd0: sda_dir <= 1'b0;
                    7'd1: begin
                        data_r[7] <= sda_in;
                        scl       <= 1'b1;
                    end
                    7'd3: scl  <= 1'b0;
                    7'd5: begin
                        data_r[6] <= sda_in ;
                        scl       <= 1'b1   ;
                    end
                    7'd7: scl  <= 1'b0;
                    7'd9: begin
                        data_r[5] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd11: scl  <= 1'b0;
                    7'd13: begin
                        data_r[4] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd15: scl  <= 1'b0;
                    7'd17: begin
                        data_r[3] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd19: scl  <= 1'b0;
                    7'd21: begin
                        data_r[2] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd23: scl  <= 1'b0;
                    7'd25: begin
                        data_r[1] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd27: scl  <= 1'b0;
                    7'd29: begin
                        data_r[0] <= sda_in;
                        scl       <= 1'b1  ;
                    end
                    7'd31: scl  <= 1'b0;
                    7'd32: begin
                        sda_dir <= 1'b1;              // 非应答
                        sda_out <= 1'b1;
                    end
                    7'd33: scl     <= 1'b1;
                    7'd34: st_done <= 1'b1;
                    7'd35: begin
                        scl <= 1'b0;
                        cnt <= 1'b0;
                        i2c_data_r <= data_r;
                    end
                    default  :  ;
                endcase
            end
            st_stop: begin                            // 结束I2C操作
                case(cnt)
                    7'd0: begin
                        sda_dir <= 1'b1;              // 结束I2C
                        sda_out <= 1'b0;
                    end
                    7'd1 : scl     <= 1'b1;
                    7'd3 : sda_out <= 1'b1;
                    7'd15: st_done <= 1'b1;
                    7'd16: begin
                        cnt      <= 1'b0;
                        i2c_done <= 1'b1;             // 向上层模块传递I2C结束信号
                    end
                    default  : ;
                endcase
            end
        endcase
    end
end

endmodule

5.2 MCP4725初始化模块

module MCP4725_init( 
 
    input                clk      ,   //时钟信号
    input                rst_n    ,   //复位信号,低电平有效
    
    input                i2c_done ,   //I2C寄存器配置完成信号
    output  reg          i2c_exec ,   //I2C触发执行信号   
    output  reg  [23:0]  i2c_data    //I2C要配置的地址与数据(高16位地址,低8位数据)
);




//reg define
reg   [14:0]   start_init_cnt;        //等待延时计数器



//scl配置成250khz,输入的clk为1Mhz,周期为1us,20000*1us = 20ms
//上电到开始配置IIC至少等待20ms
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        start_init_cnt <= 15'd0;
    else if(start_init_cnt < 15'd20000)
        start_init_cnt <= start_init_cnt + 1'b1;                    
end



//i2c触发执行信号   
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        i2c_exec <= 1'b0;
    else if(start_init_cnt == 15'd19999)
        i2c_exec <= 1'b1;

    else
        i2c_exec <= 1'b0;
end 



//配置寄存器地址与数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        i2c_data <= 16'd0;
	 else 
	     i2c_data <= {8'h60,8'h40,8'h00} ;//第一个字节为模式控制(60:同步更新到EEPROM;40:只更新DAC寄存器),后面两个字节为输入数据,取高12位
	 
	 end
endmodule

5.3 顶层模块

module MCP4725_CTRL(

  input clk,
  input rst_n,
  
  output scl,
  inout sda

);

  wire                  i2c_exec        ;  //I2C触发执行信号
  wire   [23:0]         i2c_data        ;  //I2C要配置的地址与数据(高8位地址,低16位数据)          
  wire                  i2c_done        ;  //I2C寄存器配置完成信号
  wire                  i2c_dri_clk     ;  //I2C操作时钟
  
  parameter  SLAVE_ADDR = 7'h60         ;  //MCP4725的器件地址7'h60
  parameter  BIT_CTRL   = 1'b0          ;  //字节地址为8位  0:8位 1:16位
  parameter  CLK_FREQ   = 26'd50_000_000;  //时钟频率 50MHz
  parameter  I2C_FREQ   = 18'd250_000   ;  //I2C的SCL时钟频率,250KHz

  
 i2c_dri 
   #(
    .SLAVE_ADDR         (SLAVE_ADDR),       //参数传递
    .CLK_FREQ           (CLK_FREQ  ),              
    .I2C_FREQ           (I2C_FREQ  )                
    )   
   u_i2c_dri(   
    .clk                (clk       ),
    .rst_n              (rst_n     ),   
        
    .i2c_exec           (i2c_exec  ),   
    .bit_ctrl           (BIT_CTRL  ),   
    .i2c_rh_wl          (1'b0),             //固定为0,只用到了IIC驱动的写操作   
    .i2c_addr           (i2c_data[23:16]),   
    .i2c_data_w         (i2c_data[15:0]),   
    .i2c_data_r         (),   
    .i2c_done           (i2c_done  ),   
    .scl                (scl   ),   
    .sda                (sda   ),   
        
    .dri_clk            (i2c_dri_clk)       //I2C操作时钟
); 
  
MCP4725_init u_MCP4725_init( 
 
   .clk     (i2c_dri_clk),   //时钟信号
   .rst_n   (rst_n),   //复位信号,低电平有效
   .i2c_done(i2c_done),   //I2C寄存器配置完成信号
   .i2c_exec(i2c_exec),   //I2C触发执行信号   
   .i2c_data(i2c_data)   //I2C要配置的地址与数据(高8位地址,低16位数据)
);
  
  
  
endmodule 

PS:IIC驱动程序是我在以前写的IIC单字节读写程序的基础上修改而来,从而实现两个字节的写入(这里可以再增加实现多个字节的写入,但要注意cnt的位宽)。MCP4725初始化程序中最后的 i2c_data <= {8’h60,8’h40,8’h00} ; 这一行大家可以根据自己的实际需求做更改,详细更改的内容自行参考芯片的数据手册。

6.验证
      将工程编译好后的sof文件下载到EP4CE6F17C8器件中,连接好MCP4725各个引脚,电源接5V,输入的数据为1024,为4096的四分之一,因此输出电压应该为1.25V,利用万用表测量数据为1.25V,将模块断电再重新上电,再次测量也为1.25V,证明数据成功写入EEPROM中,验证成功。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于FPGA的MCP4725驱动程序 的相关文章

随机推荐

  • watch监听(普通和深度监听)

    普通 data user 定义要监听的对象 watch 普通监听值有变化就打印 newVal oldVal新旧值参数 user newVal oldVal console log user this user 深度监听 监听对象里面的数组或
  • 架构师日记-深入理解软件设计模式

    作者 京东零售 刘慧卿 一 设计模式与编程语言 1 1 什么是设计模式 设计模式 Design pattern 由软件开发人员在软件开发中面临常见问题的解决方案 是经过长时间的试验积累总结出来的 它使设计更加灵活和优雅 复用性更好 从实用的
  • vue2里设置input光标位置

    人狠话不多 直接上业务需求 垃圾需求 凑合看 我的业务是在企微应用里 图片识别 然后点客户姓名 手机号 输入框 识别的结果可以点击回填到输入框内 这里思考回填的情况 1 可能是 直接输入 然后点下面识别的字回填 输入框是空的 直接点一个字拼
  • 【小甲鱼C语言】课后笔记第一章第一节——打印(printf)

    目录 1 打印 就是 输出 的意思 2 使用 GCC 编译程序 gcc 源代码 o 可执行文件 3 printf 是格式化输出函数 a 函数概要 b 函数原型 c 参数分析 d 返回值 e 演示 4 转义字符 5 反斜杠的奥义 6 课后习题
  • Qt自定义标题栏-移动窗口

    前情提要 众所周知 一个最简单的窗口也是有标题栏的 Windows默认提供的标题栏上有 图标 窗口标题 Min Max Close按钮 但是 这未免太过局限 高自由度的自定义是极客 Geek 精神不可或缺的一部分 如果你想在标题栏上增加 减
  • spring.jpa.hibernate.ddl-auto的配置

    spring jpa hibernate ddl auto 可以显式设置 spring jpa hibernate ddl auto 标准的Hibernate属性值有 none validate update create create d
  • mysql之 mysql 5.6不停机双主一从搭建(活跃双主一从基于日志点复制)

    环境说明 版本 version 5 6 25 log 主1库ip 10 219 24 25主2库ip 10 219 24 22从1库ip 10 219 24 26os 版本 centos 6 7已安装热备软件 xtrabackup 防火墙已
  • A template class for binding C++ to Lua

    A template class for binding C to Lua 标签 classc bindingconstructorluafunction 2006 09 09 15 50 1397人阅读 评论 0 收藏 举报 目录 htt
  • OpenMMLab-AI实战营第二期-人体关键点检测与MMPose

    人体关键点检测与MMPose 课程链接 https www bilibili com video BV1kk4y1L7Xb 这个课程的大致内容是介绍如何从给定的二维影像中恢复出人体的姿态 2D或者3D 大纲如下所示 基本上可以认为流程是 先
  • hadoop的DFSOutputStream

    当我们用命令 hadoop fs copyFromLocal localfile hdfs 将本地文件复制到HDFS时 其背后的复制过程是怎样的 本地文件通过什么方式传输到datanode上的呢 这里面很显然的是 1 文件在多个电脑之间进行
  • 基于clickhouse做用户画像,标签圈选

    clickhouse在做用户画像标签时 怎么去做圈选 表结构应该是怎么样的 我们应该怎么去处理 能够使其高性能的圈选 尽可能缩小其占用的存储空间 这个问题 我通过代码给大家做下的演示 先在hive中对数据预处理 最初表结构 create t
  • python/pta 7-42 纵横

    7 42 纵横 莫大侠练成纵横剑法 走上了杀怪路 每次仅出一招 这次 他遇到了一个正方形区域 由n n个格子构成 每个格子 行号 列号都从1开始编号 中有若干个怪 莫大侠施展幻影步 抢占了一个格子 使出绝招 横扫四方 就把他上 下 左 右四
  • 眼底图像血管增强与分割--(4)基于自适应对比度增强算法实现

    在 http blog csdn net piaoxuezhong article details 78385517 中介绍的自适应对比度增强算法 其基本原理是将图像分为低频背景和高频细节两部分 算法选择高频部分进行增益放大 这样就增强了细
  • 修复“net::err_cert_authority_invalid”错误

    1 背景 在请求接口时接口报错net err cert authority invalid 当您的浏览器无法验证您网站的SSL证书的有效性时 就会出现此问题 如果您尚未设置证书或为您的网站使用HTTP 不推荐 则不应遇到此错误 2 解决办法
  • 利用Python子进程关闭Excel自动化过程出现的弹窗

    利用Python进行Excel自动化操作的过程中 尤其是涉及VBA时 可能遇到消息框 弹窗 MsgBox 此时需要人为响应 否则代码卡死直至超时 1 2 根本的解决方法是VBA代码中不要出现类似弹窗 但有时我们无权修改被操作的Excel文件
  • python多线程编程: 使用互斥锁同步线程

    由于每个线程互相独立 相互之间没有任何关系 你干你的 我干我的 互相不干扰 如果要几个线程同时干一件事怎么办 由于互相不走动 如果一个线程已经做过了 另一个线程再去做 不就重复了吗 很容易乱套 现在假设这样一个例子 有一个全局的计数num
  • 如何在windows使用valgrind_如何在windows下使用f2py

    什么是f2py f2py是一个将fortran或者c程序转化成python可以调用的库的工具 它几乎和numpy同时出现 使用也相对比较方便 因此一直在numpy包中 在早期 f2py起到的作用类似于numba 你可以将程序的主要逻辑交给p
  • 从在线字典网站获取词汇释义:一个Python爬虫实战案例

    目录 目录 1 准备工作 2 分析网页结构 3 编写爬虫 4 提取单词信息 5 输出结果
  • css 渐变实现loading

    div class loading div
  • 基于FPGA的MCP4725驱动程序

    基于FPGA的MCP4725驱动程序 芯片资料 MCP4725是低功耗 高精度 单通道的12位缓冲电压输出数模转换器 Digital to Analog Convertor DAC 具有非易失性存储器 EEPROM 用户可以使用I2C接口命