ADS1015的IIC接口verilog接口实现

主要是参考以下这个blog

【接口时序】6、IIC总线的原理与Verilog实现 - jgliu - 博客园

如下图,ADS1015的数据每次读或者写操作,都是先写入指针寄存器的值,再去读或者写16bit的数据。

 

参考链接中,IIC操作流程是传送设备地址→传送指针寄存器→传送设备地址→读/写8bit数据→结束。

ADS1015的操作流程是传送设备地址→传送指针寄存器→传送设备地址→读/写高8bit数据→读/写低8bit数据→结束

 相比于参考链接中的IIC操作过程,ADS1015多了一个读8bit数据过程。因此,在原来的基础上增加一个读/写8bit数据的状态即可。

参考链接中,iic_recv.v和iic_send.v的信号命名都一致,可以很好的合并在一起。

在这里,我在移植代码只ADS1015的过程中,先将iic_recv和iic_send的读写16bit数据流程调通,然后再合并,最后通过一个顶层文件中的状态机进行调用,轮流读取4个通道的电压数值。

对比参考链接 recv过程中修改了4'd12(包括)之后的内容,send修改了4'd9和4'd10状态

module iic_recv_send_ctrl
(
    input                I_clk           , // 系统50MHz时钟
    input                I_rst_n         , // 系统全局复位
    input                I_iic_recv_en   , // IIC发送使能位
    input                I_iic_send_en   , // IIC发送使能位
    
    input        [6:0]   I_dev_addr      , // IIC设备的物理地址
    input        [7:0]   I_word_addr     , // IIC设备的字地址,即我们想操作的IIC的内部地址
    input        [15:0]  I_write_data    , // 往IIC设备的字地址写入的数据
    
    output  reg  [7:0]   O_read_data     , // 从IIC设备的字地址读出来的数据   
    output  reg          O_done_flag     , // 读或写IIC设备结束标志位
    output      [15:0]   O_read_16bit_data,
    
    // 标准的IIC设备总线
    output               O_scl           , // IIC总线的串行时钟线
    inout                IO_sda          // IIC总线的双向数据线
//    output               mode_test
);          

parameter   C_DIV_SELECT        =   10'd500 ; // 分频系数选择

parameter   C_DIV_SELECT0       =   (C_DIV_SELECT >> 2)  -  1           , // 用来产生IIC总线SCL低电平最中间的标志位
            C_DIV_SELECT1       =   (C_DIV_SELECT >> 1)  -  1           , // 用来产生IIC串行时钟线
            C_DIV_SELECT2       =   (C_DIV_SELECT0 + C_DIV_SELECT1) + 1 , // 用来产生IIC总线SCL高电平最中间的标志位
            C_DIV_SELECT3       =   (C_DIV_SELECT >> 1) + 1             ; // 用来产生IIC总线SCL下降沿标志位
 

reg     [9:0]   R_scl_cnt       ; // 用来产生IIC总线SCL时钟线的计数器   
reg             R_scl_en        ; // IIC总线SCL时钟线使能信号
reg     [3:0]   R_state         ; 
reg             R_sda_mode      ; // 设置SDA模式,1位输出,0为输入
reg             R_sda_reg       ; // SDA寄存器
reg     [7:0]   R_load_data     ; // 发送/接收过程中加载的数据,比如设备物理地址,字地址和数据等
reg     [3:0]   R_bit_cnt       ; // 发送字节状态中bit个数计数
reg             R_ack_flag      ; // 应答标志
reg     [3:0]   R_jump_state    ; // 跳转状态,传输一个字节成功并应答以后通过这个变量跳转到导入下一个数据的状态
reg     [7:0]   R_read_data_reg ;
reg     [15:0]  read_reg_16bit_data;
reg     [7:0]   r_high_bit_data;

reg     [7:0]   r_low_bit_data;
reg     [7:0]   r_low_bit_data_r;

wire            W_scl_low_mid   ; // SCL的低电平中间标志位
wire            W_scl_high_mid  ; // SCL的高电平中间标志位
wire            W_scl_neg;

assign IO_sda  =  (R_sda_mode == 1'b1) ? R_sda_reg : 1'bz ;

assign  O_read_16bit_data = read_reg_16bit_data;

//assign  mode_test = R_sda_mode;

always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        R_scl_cnt   <=  10'd0 ; 
    else if(R_scl_en)   
        begin
            if(R_scl_cnt == C_DIV_SELECT - 1'b1)
                R_scl_cnt <= 10'd0 ;
            else
                R_scl_cnt <= R_scl_cnt + 1'b1 ;     
        end
    else
        R_scl_cnt     <= 10'd0 ;
end

assign O_scl           = (R_scl_cnt <= C_DIV_SELECT1) ? 1'b1 : 1'b0 ; // 产生串行时钟信号O_scl
assign W_scl_low_mid  = (R_scl_cnt == C_DIV_SELECT2) ? 1'b1 : 1'b0 ; // 产生scl低电平正中间标志位
assign W_scl_high_mid = (R_scl_cnt == C_DIV_SELECT0) ? 1'b1 : 1'b0 ; // 产生scl高电平正中间标志位
assign W_scl_neg       = (R_scl_cnt == C_DIV_SELECT3) ? 1'b1 : 1'b0 ; // 产生scl下降沿标志位

always @(posedge I_clk or negedge I_rst_n)
begin
    if(!I_rst_n)
        begin
            R_state         <=  4'd0 ;
            R_sda_mode      <=  1'b1 ;
            R_sda_reg       <=  1'b1 ;
            R_bit_cnt       <=  4'd0 ;
            O_done_flag     <=  1'b0 ;
            R_jump_state    <=  4'd0 ;
            R_read_data_reg <=  8'd0 ;
            R_ack_flag        <=    1'b0 ;
            O_read_data        <=    8'd0 ;
            
            r_low_bit_data_r  <= 8'd0;
            r_low_bit_data    <= 8'd0;
            read_reg_16bit_data <= 16'd0;
        end
    else if(I_iic_recv_en) // 从IIC设备 读取数据
        begin
            case(R_state)
                4'd0    :   // 空闲状态,用来初始化相关所有信号
                    begin
                        R_sda_mode      <=  1'b1 ; // 设置SDA为输出
       
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值