草庐IT

DW_apb_i2c 使用介绍2--i2c初始化以及读写eeprom测试

原海青木 2023-05-27 原文

1.DW_apb_i2c寄存器

        目前我使用DW_apb_i2c协议是:DW_apb_i2c_2018,即2018版本。这个IP的寄存器共有68个,相对于stm32来说,这个寄存器数量确实有点多,实际使用起来也确实有点繁琐,不过当前的项目需求,有一大部分寄存器是用不到的,所以也还好。另外因为项目原因,一些具体的代码细节不太方便写出来,有疑问可以留言交流。

        寄存器是在第5章,截图如下:

 具体每个寄存器如何使用就不展开了,直接看寄存器说明即可。

2.DW_apb_i2c初始化流程

        在第6章的6.3章节,有一个初始化流程图,如下图:

        这是一个结合DMA的使用流程图,现在我只是初始化i2c,所以只关心上图的黄色框部分,做一个简单的初始化总结:

(1)先在i2c_enable寄存器中disable i2c。因为这个IP的有些寄存器必须在i2c处于disable状态下才能配置生效;

(2)在i2c_con寄存器中使能restart_en

(3)在i2c_con寄存器中选择地址模式,一般都是使用7bit模式;

(4)在i2c_con寄存器中配置SCL速率模式,我的用例是配置成standard mode;

(5)在i2c_con寄存器中使能master模式;

(6)在IC_TAR寄存器中设置slave device地址;

(7)配置i2c_ss_scl_hcnt和i2c_ss_scl_lcnt。虽然步骤4配置SCL成standard mode,但是实际SCL的大小是与i2c_ss_scl_hcnt和i2c_ss_scl_lcnt有关的。

(8)配置i2c_intr_mask寄存器,使能相关的中断;

(9)配置i2c_tx_tl和i2c_rx_tl寄存器,这2个寄存器这关系到TX_EMPTY和RX_FULL中断的触发条件;

(10)配置i2c_dma_tdlr和i2c_dma_rdlr寄存器,这里是配置DMA水线;

(11)最后在i2c_enable寄存器中enable i2c。

3.初始化测试代码 

        以下是个人的初始化代码,仅作参考。这里与上面的流程顺序可能不太一致,我还增加了广播功能、中断函数注册等,这个不影响功能。

(1)用结构体 i2c_reg_s 定义寄存器:

typedef struct{
    i2c_con_s i2c_con;                                                 /* offset: 0x00 i2c control */
    i2c_tar_s i2c_tar;                                                 /* offset: 0x04 i2c target address */
    i2c_sar_s i2c_sar;                                                 /* offset: 0x08 i2c slave address  */
    i2c_hs_maddr_s i2c_hs_maddr;                                       /* offset: 0x0c i2c hs master mode code address */
    i2c_data_cmd_s i2c_data_cmd;                                       /* offset: 0x10 i2c rx/tx data buffer and command */
    i2c_ss_scl_hcnt_s i2c_ss_scl_hcnt;                                 /* offset: 0x14 standard speed i2c clock scl high count */
    i2c_ss_scl_lcnt_s i2c_ss_scl_lcnt;                                 /* offset: 0x18 standard speed i2c clock scl low count */
    i2c_fs_scl_hcnt_s i2c_fs_scl_hcnt;                                 /* offset: 0x1c fast speed i2c clock scl high count */
    i2c_fs_scl_lcnt_s i2c_fs_scl_lcnt;                                 /* offset: 0x20 fast speed i2c clock scl low count */
    i2c_hs_scl_hcnt_s i2c_hs_scl_hcnt;                                 /* offset: 0x24 high speed i2c clock scl high count */
    i2c_hs_scl_lcnt_s i2c_hs_scl_lcnt;                                 /* offset: 0x28 high speed i2c clock scl low count */
    i2c_intr_stat_s i2c_intr_stat;                                     /* offset: 0x2c i2c interrupt status */
    i2c_intr_mask_s i2c_intr_mask;                                     /* offset: 0x30 i2c interrupt mask */
    i2c_raw_intr_stat_s i2c_raw_intr_stat;                             /* offset: 0x34 i2c raw interrupt status */
    i2c_rx_tl_s i2c_rx_tl;                                             /* offset: 0x38 i2c receive fifo threshold */
    i2c_tx_tl_s i2c_tx_tl;                                             /* offset: 0x3c i2c transmit fifo threshold */
    i2c_clr_intr_s i2c_clr_intr;                                       /* offset: 0x40 clear combined and individual interrupts */
    i2c_clr_rx_under_s i2c_clr_rx_under;                               /* offset: 0x44 i2c clear rx_under interrupt */
    i2c_clr_rx_over_s i2c_clr_rx_over;                                 /* offset: 0x48 i2c clear rx_over interrupt */
    i2c_clr_tx_over_s i2c_clr_tx_over;                                 /* offset: 0x4c i2c clear tx_over interrupt */
    i2c_clr_rd_req_s i2c_clr_rd_req;                                   /* offset: 0x50 i2c clear rd_req interrupt */
    i2c_clr_tx_abrt_s i2c_clr_tx_abrt;                                 /* offset: 0x54 i2c clear tx_abrt interrupt */
    i2c_clr_rx_done_s i2c_clr_rx_done;                                 /* offset: 0x58 i2c clear rx_done interrupt */
    i2c_clr_activity_s i2c_clr_activity;                               /* offset: 0x5c i2c clear activity interrupt */
    i2c_clr_stop_det_s i2c_clr_stop_det;                               /* offset: 0x60 i2c clear stop_det interrupt */
    i2c_clr_start_det_s i2c_clr_start_det;                             /* offset: 0x64 i2c clear start_det interrupt */
    i2c_clr_gen_call_s i2c_clr_gen_call;                               /* offset: 0x68 i2c clear gen_cal interrupt */
    i2c_enable_s i2c_enable;                                           /* offset: 0x6c i2c enable */
    i2c_status_s i2c_status;                                           /* offset: 0x70 i2c status register */
    i2c_txflr_s i2c_txflr;                                             /* offset: 0x74 tansmit fifo level register */
    i2c_rxflr_s i2c_rxflr;                                             /* offset: 0x78 receive fifo level register*/
    i2c_sda_hold_s i2c_sda_hold;                                       /* offset: 0x7c set sda hold time */
    i2c_tx_abrt_source_s i2c_tx_abrt_source;                           /* offset: 0x80 i2c transmit abort status register */
    i2c_slv_data_nack_only_s i2c_slv_data_nack_only;                   /* offset: 0x84 */
    i2c_dma_cr_s i2c_dma_cr;                                           /* offset: 0x88 dma control register for transmit and receive handshaking interface */
    i2c_dma_tdlr_s i2c_dma_tdlr;                                       /* offset: 0x8c dma transmit data level */
    i2c_dma_rdlr_s i2c_dma_rdlr;                                       /* offset: 0x90 dma receive data level */
    i2c_sda_setup_s i2c_sda_setup;                                     /* offset: 0x94 */
    i2c_ack_general_call_s i2c_ack_general_call;                       /* offset: 0x98 */
    i2c_enable_status_s i2c_enable_status;                             /* offset: 0x9c */
    i2c_fs_spklen_s i2c_fs_spklen;                                     /* offset: 0xa0 */
    i2c_hs_spklen_s i2c_hs_spklen;                                     /* offset: 0xa4 */
    i2c_clr_restart_det_s i2c_clr_restart_det;                         /* offset: 0xa8 */
    i2c_scl_stuck_at_low_timeout_s i2c_scl_stuck_at_low_timeout;       /* offset: 0xac */
    i2c_sda_stuck_at_low_timeout_s i2c_sda_stuck_at_low_timeout;       /* offset: 0xb0 */
    i2c_clr_scl_stuck_det_s i2c_clr_scl_stuck_det;                     /* offset: 0xb4 */
    i2c_device_id_s i2c_device_id;                                     /* offset: 0xb8 */
    i2c_smbus_clk_low_sext_s i2c_smbus_clk_low_sext;                   /* offset: 0xbc */
    i2c_smbus_clk_low_mext_s i2c_smbus_clk_low_mext;                   /* offset: 0xc0 */
    i2c_smbus_thigh_max_idle_count_s i2c_smbus_thigh_max_idle_count;   /* offset: 0xc4 */
    i2c_smbus_intr_stat_s i2c_smbus_intr_stat;                         /* offset: 0xc8 */
    i2c_smbus_intr_mask_s i2c_smbus_intr_mask;                         /* offset: 0xcc */
    i2c_smbus_raw_intr_stat_s i2c_smbus_raw_intr_stat;                 /* offset: 0xd0 */
    i2c_clr_smbus_intr_s i2c_clr_smbus_intr;                           /* offset: 0xd4 */
    i2c_optional_sar_s i2c_optional_sar;                               /* offset: 0xd8 */
    i2c_smbus_udid_lsb_s i2c_smbus_udid_lsb;                           /* offset: 0xdc */
    //i2c_smbus_udid_word0_s i2c_smbus_udid_word0;                       /* offset: 0xdc */
    i2c_smbus_udid_word1_s i2c_smbus_udid_word1;                       /* offset: 0xe0 */
    i2c_smbus_udid_word2_s i2c_smbus_udid_word2;                       /* offset: 0xe4 */
    i2c_smbus_udid_word3_s i2c_smbus_udid_word3;                       /* offset: 0xe8 */
    unsigned int reserved;                                               /* offset: 0xec  reserved */
    i2c_reg_timeout_rst_s reg_timeout_rst;                             /* offset: 0xf0 */
    i2c_comp_param_1_s i2c_comp_param_1;                               /* offset: 0xf4 */
    i2c_comp_version_s i2c_comp_version;                               /* offset: 0xf8 */
    i2c_comp_type_s i2c_comp_type;                                     /* offset: 0xfc */
    i2c_sar2_s i2c_sar2;                                               /* offset: 0x100 */
    i2c_sar3_s i2c_sar3;                                               /* offset: 0x104 */
    i2c_sar4_s i2c_sar4;                                               /* offset: 0x108 */
    unsigned int reserved1;                                            /* offset: 0x10c  reserved */
    unsigned int reserved2;                                            /* offset: 0x110  reserved */
    unsigned int reserved3;                                            /* offset: 0x114  reserved */
    unsigned int reserved4;                                            /* offset: 0x118  reserved */
    i2c_clr_wr_req_s i2c_clr_wr_req;                                   /* offset: 0x11c */
    i2c_clr_slv_addr_tag_s i2c_clr_slv_addr_tag;                       /* offset: 0x120 */
}volatile i2c_reg_s;

(2)定义 i2c_handle,传递相关配置参数:

typedef struct i2c_handle {
    i2c_reg_s           *instance;        /**< i2c base address */
    unsigned int        irq_num;          /**< interruption number */
    i2c_mode_e          i2c_mode;         /**< i2c work mode: master or slave mode */
    i2c_speed_mode_e    i2c_speed_mode;   /**< i2c_speed_mode: standrd,fast or high speed*/
    i2c_addr_mode_e     i2c_addr_mode;    /**< i2c_addr_mode: 7bit or 10bit mode */
    i2c_general_cell_e  i2c_general_cell; /**< i2c_general_cell: enable or disable*/
    i2c_restart_e       i2c_restart;      /**< i2c_restart:  enable or disable restart */
    i2c_dma_mode_e      i2c_dma_mode;     /**< dma_mode: enable or disable dma_mode */
    i2c_notify_type_e   i2c_notify_type;  /**< indicate the way to send or receive date */
} i2c_handle_s;

(3)i2c初始化函数: 这里省略了i2c的时钟门控、软复位、管脚复用配置,这部分和CPU以及硬件环境有关,参考意义不大,就不展示出来了。

void i2c_init(i2c_handle_s *handle)
{
    i2c_reg_s *i2c_reg = handle->instance;  //get i2c base addr

    /* 时钟门控使能 */
    i2c_clk_en(handle);
    
    /* 软复位和解复位 */
    i2c_rst_en(handle);
    
    /* 管脚复用 */
    i2c_io_config(handle);

    i2c_disable(i2c_reg);
    i2c_clear_all_irq(i2c_reg);
    i2c_disable_all_irq(i2c_reg);

    //work mode setting
    if (handle->i2c_mode == I2C_MODE_MASTER) {
        i2c_set_operation_mode(i2c_reg, I2C_MODE_MASTER);
    } else {
        i2c_set_operation_mode(i2c_reg, I2C_MODE_SLAVE);
        i2c_set_own_address(i2c_reg,0x4f);
    }

    //speed mode setting
    i2c_set_speed_mode(i2c_reg, handle->i2c_speed_mode);

    //address mode setting
    i2c_set_addr_mode(i2c_reg, handle->i2c_addr_mode);

    //genereal call setting
    if (handle->i2c_general_cell == GENERAL_CELL_ENABLE) {
        i2c_master_set_general_call(i2c_reg, GENERAL_CELL_ENABLE);
        i2c_slave_set_general_call(i2c_reg, ACK_GENERAL_CALL);
    } else {
        i2c_master_set_general_call(i2c_reg, GENERAL_CELL_DISABLE);
        i2c_slave_set_general_call(i2c_reg, NACK_GENERAL_CALL);
    }

    //restart setting
    if (handle->i2c_restart == RESTART_ENABLE) {
        i2c_enable_restart(i2c_reg);
    } else {
        i2c_disable_restart(i2c_reg);
    }

    //DMA setting
    if (handle->i2c_dma_mode == DMA_ENABLE) {
        i2c_dma_transmit_enable(i2c_reg);
        i2c_dma_receive_enable(i2c_reg);
    } else {
        i2c_dma_transmit_disable(i2c_reg);
        i2c_dma_receive_disable(i2c_reg);
    }

    //notify type setting
    if (handle->i2c_notify_type == I2C_NOTIFY_TYPE_INT) {
         //注册中断号、中断回调函数
        drv_irq_register(handle->irq_num, i2c_irq_handle_callback, handle);   
        //设置中断优先级       
        drv_irq_enable(handle->irq_num, IRQ_TYPE_VECTOR_HIGH_LEVEL, IRQ_PRIORITY_2);  
    } else {
        drv_irq_disable(handle->irq_num);
        drv_irq_unregister(handle->irq_num);
    }

    //intr mask setting
    i2c_set_intr_mask(i2c_reg);

    //SDA hold time setting
    i2c_set_sda_hold_time(i2c_reg, 0x01, 0x01);

    //SCL/SDA timeout setting
    i2c_set_scl_stuck_at_low_timeout(i2c_reg, 0xffffffff);
    i2c_set_sda_stuck_at_low_timeout(i2c_reg, 0xffffffff);

    //rx_fifo_full_hold_ctrl enable(逻辑默认使能)
    i2c_set_rx_fifo_full_hold_ctrl(i2c_reg, 1);

    //i2c_fifo_threshold setting(配置超过fifo深度的时候,这里实际写进去的是fifo深度-1)
    i2c_set_transmit_fifo_threshold(i2c_reg, 0);
    i2c_set_receive_fifo_threshold(i2c_reg, 7);

    i2c_enable(i2c_reg);
}

4.读写eeprom

#define I2C1_ADDR                (i2c_reg_s *)I2C1_BASE

/*
*    i2c1 作为 master,采用轮训方式,写AT24C16
*    验证:100khz速率读写测试
*/
void i2c1_master_test_case_write_read_100khz(void)
{
    i2c_reg_s *i2c_reg = NULL;
    static i2c_handle_s i2c1_handle ={0};
    unsigned char receive_data[3] = {0};

    i2c1_handle.instance          = I2C1_ADDR;
    i2c1_handle.irq_num           = IRQ_NUM_I2C1;
    i2c1_handle.i2c_mode          = I2C_MODE_MASTER;
    i2c1_handle.i2c_speed_mode    = I2C_BUS_SPEED_STANDARD;
    i2c1_handle.i2c_addr_mode     = I2C_ADDRESS_7BIT;
    i2c1_handle.i2c_general_cell  = GENERAL_CELL_DISABLE;
    i2c1_handle.i2c_restart       = RESTART_DISABLE;
    i2c1_handle.i2c_dma_mode      = DMA_DISABLE;
    i2c1_handle.i2c_notify_type   = I2C_NOTIFY_TYPE_INT;

    i2c_init(&i2c1_handle);
    dbg_uart_print("i2c1_master_100khz init end!!\r\n");

    i2c_reg = i2c1_handle.instance;
    i2c_clear_all_irq(i2c_reg);

    // 0x57:1010 111 这是器件地址,其中1010是固定地址;111是页地址高3位。
    // 0x12: 00010002 这是操作地址,其中0001是页地址低,0002是页地址偏移量,即该页第2个地址
    // 故页地址是111 0001,即0x71,第113页;即往第113页第2个字节地址写入0x45
    AT24C16_write_byte(i2c_reg, 0x57, 0x12, 0x45);                                                       
    mdelay(5);
    //即往第113页第3个字节地址写入0x87
    AT24C16_write_byte(i2c_reg, 0x57, 0x13, 0x87);        
    mdelay(5);
    receive_data[0] = AT24C16_read_byte(i2c_reg, 0x57, 0x12);
    dbg_uart_print("read_date, 0x%x\r\n", receive_data[0]);
    receive_data[1] = AT24C16_read_byte(i2c_reg, 0x57, 0x13);
    mdelay(5);
    dbg_uart_print("read_date, 0x%x\r\n", receive_data[1]);
    if ((receive_data[0] == 0x45) & (receive_data[1] == 0x87)) {
        dbg_uart_print("100khz_write_read pass!!\r\n");
    } else {
        dbg_uart_print("100khz_write_read failed!!\r\n");
    }
}

用逻辑分析仪抓写数据的波形:

用逻辑分析仪抓读数据的波形:

 100KHz速率读写数据都是OK的。

有关DW_apb_i2c 使用介绍2--i2c初始化以及读写eeprom测试的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐