dirty 发表于 2024-5-12 12:49

【兆易GD32H759I-EVAL】--3.EEPROM读写

<div class='showpostmsg'> 本帖最后由 dirty 于 2024-5-12 12:50 编辑

<p>&nbsp; &nbsp; &nbsp; 本篇讲述I2C读写板载EEPROM存储器AT24C02C-SSHM-T。</p>

<p><strong><span style="color:#0000cc;">一.硬件原理</span></strong></p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;AT24C02C为I2C接口,容量256Bytes.<strong><span style="color:#8e44ad;">I2C引脚配置为:PH4--SCL,PB11--SDA.</span></strong></p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图1:AT24C02C原理</div>

<p><span style="color:#0000cc;">引脚&nbsp; </span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#0000cc;">&nbsp;功能</span></p>

<p>VCC、GND&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;电源</p>

<p>WP&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 写保护</p>

<p>SCL、SDA&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I2C接口</p>

<p>A0、A1、A2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;I2C地址</p>

<p>&nbsp;</p>

<p><strong><span style="color:#0000cc;">二.代码</span></strong></p>

<p>1.引脚、参数宏定义</p>

<pre>
<code>#define I2C_SPEED         400000
#define I2C_PAGE_SIZE       8
#define I2CX                I2C1
#define RCU_GPIO_I2C_SDA    RCU_GPIOB
#define RCU_GPIO_I2C_SCL    RCU_GPIOH
#define RCU_I2C             RCU_I2C1
#define I2C_SCL_PORT      GPIOH
#define I2C_SDA_PORT      GPIOB
#define I2C_SCL_PIN         GPIO_PIN_4
#define I2C_SDA_PIN         GPIO_PIN_11
#define I2C_GPIO_AF         GPIO_AF_4</code></pre>

<p>2.io引脚初始化配置</p>

<pre>
<code>void gpio_config(void)
{
    /* enable I2C_SCL_PIN clock */
    rcu_periph_clock_enable(RCU_GPIO_I2C_SCL);
    /* enable I2C_SDA_PIN clock */
    rcu_periph_clock_enable(RCU_GPIO_I2C_SDA);
    /* enable I2C clock */
    rcu_periph_clock_enable(RCU_I2C);

    /* connect I2C_SCL_PIN to I2C_SCL */
    gpio_af_set(I2C_SCL_PORT, I2C_GPIO_AF, I2C_SCL_PIN);
    /* connect I2C_SDA_PIN to I2C_SDA */
    gpio_af_set(I2C_SDA_PORT, I2C_GPIO_AF, I2C_SDA_PIN);
    /* configure GPIO pins of I2C */
    gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SCL_PIN);
    gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, I2C_SCL_PIN);
    gpio_mode_set(I2C_SDA_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SDA_PIN);
    gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_60MHZ, I2C_SDA_PIN);
}</code></pre>

<p>3.i2c接口初始化配置</p>

<pre>
<code>void i2c_config(void)
{
    /* configure the I2C1 clock source selection */
    rcu_i2c_clock_config(IDX_I2C1, RCU_I2CSRC_IRC64MDIV);
    /* configure I2C timing */
    i2c_timing_config(I2CX, 0x0, 0x6, 0);
    i2c_master_clock_config(I2CX, 0x26, 0x73);
    /* enable I2C */
    i2c_enable(I2CX);
}</code></pre>

<p>3.器件地址,数据大小、超时时长,起始页等定义</p>

<pre>
<code>#define EEPROM_BLOCK0_ADDRESS    0xA0
#define BUFFER_SIZE            256
#define MAX_RELOAD_SIZE          255

#define I2C_TIME_OUT             (uint32_t)(50000)
#define EEP_FIRST_PAGE         0x00</code></pre>

<p>4.i2c读、写函数</p>

<pre>
<code>void eeprom_page_write(uint8_t *p_buffer, uint8_t write_address, uint8_t number_of_byte)
{
    i2c_process_enum state = I2C_START;
    uint32_t timeout = 0;
    uint8_t end_flag = 0;

    while(!end_flag) {
      switch(state) {
            case I2C_START:
                /* configure slave address */
                i2c_master_addressing(I2CX, eeprom_address, I2C_MASTER_TRANSMIT);
                /* configure number of bytes to be transferred */
                i2c_transfer_byte_number_config(I2CX, number_of_byte + 1);
                /* clear I2C_TDATA register */
                I2C_STAT(I2CX) |= I2C_STAT_TBE;
                /* enable I2C automatic end mode in master mode */
                i2c_automatic_end_enable(I2CX);
                /* i2c master sends start signal only when the bus is idle */
                while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  i2c_start_on_bus(I2CX);
                  timeout = 0;
                  state = I2C_SEND_ADDRESS;
                } else {
                  /* timeout, bus reset */
                  i2c_bus_reset();
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c bus is busy in page write!\n");
                }
                break;
            case I2C_SEND_ADDRESS:
                /* wait until the transmit data buffer is empty */
                while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  /* send the EEPROM's internal address to write to : only one byte address */
                  i2c_data_transmit(I2CX, write_address);
                  timeout = 0;
                  state = I2C_TRANSMIT_DATA;
                } else {
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master sends address timeout in page write!\n");
                }
                break;
            case I2C_TRANSMIT_DATA:
                while(number_of_byte--) {
                  /* wait until TI bit is set */
                  while((!i2c_flag_get(I2CX, I2C_FLAG_TI)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                        timeout++;
                  }
                  if(timeout &lt; I2C_TIME_OUT) {
                        /* while there is data to be written */
                        i2c_data_transmit(I2CX, *p_buffer);
                        /* point to the next byte to be written */
                        p_buffer++;
                        timeout = 0;
                        state = I2C_STOP;
                  } else {
                        /* wait TI timeout */
                        timeout = 0;
                        state = I2C_START;
                        printf("i2c master sends data timeout in page write!\n");
                        return ;
                  }
                }
                break;
            case I2C_STOP:
                /* wait until the stop condition is finished */
                while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  /* clear STPDET flag */
                  i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
                  timeout = 0;
                  state = I2C_END;
                  end_flag = 1;
                } else {
                  /* stop detect timeout */
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master sends stop signal timeout in page write!\n");
                }
                break;
            default:
                /* default status */
                state = I2C_START;
                end_flag = 1;
                timeout = 0;
                printf("i2c master sends start signal in page write!\n");
                break;
      }
    }
}

/*!
    \brief      read data from the EEPROM
    \paramp_buffer: pointer to the buffer that receives the data read from the EEPROM
    \paramread_address: EEPROM's internal address to start reading from
    \paramnumber_of_byte: number of bytes to reads from the EEPROM
    \param none
    \retval   none
*/
void eeprom_buffer_read(uint8_t *p_buffer, uint8_t read_address, uint16_t number_of_byte)
{
    uint32_t nbytes_reload = 0;
    i2c_process_enum state = I2C_START;
    uint32_t timeout = 0;
    uint8_t end_flag = 0;
    uint8_t restart_flag = 0;
    uint8_t first_reload_flag = 1;
    uint8_t last_reload_flag = 0;

    while(!end_flag) {
      switch(state) {
            case I2C_START:
                if(0 == restart_flag) {
                  /* clear I2C_TDATA register */
                  I2C_STAT(I2CX) |= I2C_STAT_TBE;
                  /* configure slave address */
                  i2c_master_addressing(I2CX, eeprom_address, I2C_MASTER_TRANSMIT);
                  /* configure number of bytes to be transferred */
                  i2c_transfer_byte_number_config(I2CX, 1);
                  /* disable I2C automatic end mode in master mode */
                  i2c_automatic_end_disable(I2CX);
                  /* i2c master sends start signal only when the bus is idle */
                  while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                        timeout++;
                  }
                  if(timeout &lt; I2C_TIME_OUT) {
                        i2c_start_on_bus(I2CX);
                        timeout = 0;
                        state = I2C_SEND_ADDRESS;
                  } else {
                        /* timeout, bus reset */
                        i2c_bus_reset();
                        timeout = 0;
                        state = I2C_START;
                        printf("i2c bus is busy in read!\n");
                  }
                } else {
                  /* restart */
                  i2c_start_on_bus(I2CX);
                  restart_flag = 0;
                  state = I2C_TRANSMIT_DATA;
                }
                break;
            case I2C_SEND_ADDRESS:
                /* wait until the transmit data buffer is empty */
                while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  /* send the EEPROM's internal address to write to : only one byte address */
                  i2c_data_transmit(I2CX, read_address);
                  timeout = 0;
                  state = I2C_RESTART;
                } else {
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master sends data timeout in read!\n");
                }
                break;
            case I2C_RESTART:
                /* wait until the transmit data buffer is empty */
                while((!i2c_flag_get(I2CX, I2C_FLAG_TC)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  /* configure the EEPROM's internal address to write to : only one byte address */
                  i2c_master_addressing(I2CX, eeprom_address, I2C_MASTER_RECEIVE);
                  /* enable I2C reload mode */
                  i2c_reload_enable(I2CX);
                  /* configure number of bytes to be transferred */
                  timeout = 0;
                  state = I2C_RELOAD;
                  restart_flag = 1;
                } else {
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master sends EEPROM's internal address timeout in read!\n");
                }
                break;
            case I2C_RELOAD:
                if(number_of_byte &gt; MAX_RELOAD_SIZE) {
                  number_of_byte = number_of_byte - MAX_RELOAD_SIZE;
                  nbytes_reload = MAX_RELOAD_SIZE;
                } else {
                  nbytes_reload = number_of_byte;
                  last_reload_flag = 1;
                }
                if(1 == first_reload_flag) {
                  /* configure number of bytes to be transferred */
                  i2c_transfer_byte_number_config(I2CX, nbytes_reload);
                  if(1 == last_reload_flag) {
                        last_reload_flag = 0;
                        /* disable I2C reload mode */
                        if(number_of_byte &lt;= MAX_RELOAD_SIZE) {
                            i2c_reload_disable(I2CX);
                            /* enable I2C automatic end mode in master mode */
                            i2c_automatic_end_enable(I2CX);
                        }
                  }
                  first_reload_flag = 0;
                  state = I2C_START;
                } else {
                  /* wait for TCR flag */
                  while((!i2c_flag_get(I2CX, I2C_FLAG_TCR)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                        timeout++;
                  }
                  if(timeout &lt; I2C_TIME_OUT) {
                        /* configure number of bytes to be transferred */
                        i2c_transfer_byte_number_config(I2CX, nbytes_reload);
                        /* disable I2C reload mode */
                        if(number_of_byte &lt;= MAX_RELOAD_SIZE) {
                            i2c_reload_disable(I2CX);
                            /* enable I2C automatic end mode in master mode */
                            i2c_automatic_end_enable(I2CX);
                        }
                        timeout = 0;
                        state = I2C_TRANSMIT_DATA;
                  } else {
                        timeout = 0;
                        state = I2C_START;
                        printf("i2c master reload data timeout in read!\n");
                  }
                }
                break;
            case I2C_TRANSMIT_DATA:
                /* wait until TI bit is set */
                while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  while(nbytes_reload) {
                        delay_1ms(2);
                        /* wait until the RBNE bit is set and clear it */
                        if(i2c_flag_get(I2CX, I2C_FLAG_RBNE)) {
                            /* read a byte from the EEPROM */
                            *p_buffer = i2c_data_receive(I2CX);
                            /* point to the next location where the byte read will be saved */
                            p_buffer++;
                            /* decrement the read bytes counter */
                            nbytes_reload--;
                        }
                  }
                  timeout = 0;
                  /* check if the reload mode is enabled or not */
                  if(I2C_CTL1(I2CX) &amp; I2C_CTL1_RELOAD) {
                        timeout = 0;
                        state = I2C_RELOAD;
                  } else {
                        timeout = 0;
                        state = I2C_STOP;
                  }
                } else {
                  /* wait TI timeout */
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master read data timeout in read!\n");
                }
                break;
            case I2C_STOP:
                /* wait until the stop condition is finished */
                while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) &amp;&amp; (timeout &lt; I2C_TIME_OUT)) {
                  timeout++;
                }
                if(timeout &lt; I2C_TIME_OUT) {
                  /* clear STPDET flag */
                  i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
                  timeout = 0;
                  state = I2C_END;
                  end_flag = 1;
                } else {
                  timeout = 0;
                  state = I2C_START;
                  printf("i2c master sends stop signal timeout in read!\n");
                }
                break;
            default:
                /* default status */
                state = I2C_START;
                end_flag = 1;
                timeout = 0;
                printf("i2c master sends start signal in read!\n");
                break;
      }
    }
}</code></pre>

<p>5.i2c读写数据测试。将256字节数据写入,然后读出并比较,根据结果做相应日志输出。</p>

<pre>
<code>uint8_t i2c_24c02_test(void)
{
    uint16_t i;
    uint8_t i2c_buffer_write;
    uint8_t i2c_buffer_read;

    printf("\r\nAT24C02 writing...\r\n");

    /* initialize i2c_buffer_write */
    for(i = 0; i &lt; BUFFER_SIZE; i++) {
      i2c_buffer_write = i;
      printf("0x%02X ", i2c_buffer_write);
      if(15 == i % 16) {
            printf("\r\n");
      }
    }
    /* EEPROM data write */
    eeprom_buffer_write(i2c_buffer_write, EEP_FIRST_PAGE, BUFFER_SIZE);
    printf("AT24C02 reading...\r\n");
    /* EEPROM data read */
    eeprom_buffer_read(i2c_buffer_read, EEP_FIRST_PAGE, BUFFER_SIZE);
    /* compare the read buffer and write buffer */
    for(i = 0; i &lt; BUFFER_SIZE; i++) {
      if(i2c_buffer_read != i2c_buffer_write) {
            printf("0x%02X ", i2c_buffer_read);
            printf("Err:data read and write aren't matching.\n\r");
            return I2C_FAIL;
      }
      printf("0x%02X ", i2c_buffer_read);
      if(15 == i % 16) {
            printf("\r\n");
      }
    }
    printf("I2C-AT24C02 test passed!\n\r");
    return I2C_OK;
}
</code></pre>

<p>&nbsp;</p>

<p><strong><span style="color:#0000cc;">三.编译烧录测验</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 编译烧录后日志如下:</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图2:I2C读写EEPROM</div>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; &nbsp; 上面可以看到,i2c读写EEPROM AT24C02获得成功。</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

jobszheng5 发表于 2024-5-12 13:33

<p>看上GD的IIC应用还是挺简单的</p>

dirty 发表于 2024-5-14 22:02

<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&amp;goto=findpost&amp;pid=3327638&amp;ptid=1281631" target="_blank"><font color="#999999">jobszheng5 发表于 2024-5-12 13:33</font></a></font> 看上GD的IIC应用还是挺简单的</blockquote>
</div>

<p>SDK写的不错,可以很方便使用</p>

zz19940910 发表于 2025-1-20 08:51

<p>通讯速率怎么计算的呀</p>
页: [1]
查看完整版本: 【兆易GD32H759I-EVAL】--3.EEPROM读写