【兆易GD32H759I-EVAL】--3.EEPROM读写
<div class='showpostmsg'> 本帖最后由 dirty 于 2024-5-12 12:50 编辑<p> 本篇讲述I2C读写板载EEPROM存储器AT24C02C-SSHM-T。</p>
<p><strong><span style="color:#0000cc;">一.硬件原理</span></strong></p>
<p> 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;">引脚 </span> <span style="color:#0000cc;"> 功能</span></p>
<p>VCC、GND 电源</p>
<p>WP 写保护</p>
<p>SCL、SDA I2C接口</p>
<p>A0、A1、A2 I2C地址</p>
<p> </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) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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 > 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 <= 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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 <= 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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) & 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)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if(timeout < 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 < 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 < 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> </p>
<p><strong><span style="color:#0000cc;">三.编译烧录测验</span></strong></p>
<p> 编译烧录后日志如下:</p>
<p> </p>
<div style="text-align: center;"></div>
<div style="text-align: center;">图2:I2C读写EEPROM</div>
<p> </p>
<p> 上面可以看到,i2c读写EEPROM AT24C02获得成功。</p>
<p> </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> <p>看上GD的IIC应用还是挺简单的</p>
<div class="quote">
<blockquote><font size="2"><a href="forum.php?mod=redirect&goto=findpost&pid=3327638&ptid=1281631" target="_blank"><font color="#999999">jobszheng5 发表于 2024-5-12 13:33</font></a></font> 看上GD的IIC应用还是挺简单的</blockquote>
</div>
<p>SDK写的不错,可以很方便使用</p>
<p>通讯速率怎么计算的呀</p>
页:
[1]