826|3

507

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【兆易GD32H759I-EVAL】--3.EEPROM读写 [复制链接]

 
本帖最后由 dirty 于 2024-5-12 12:50 编辑

      本篇讲述I2C读写板载EEPROM存储器AT24C02C-SSHM-T。

一.硬件原理

    AT24C02C为I2C接口,容量256Bytes.I2C引脚配置为:PH4--SCL,PB11--SDA.

图1:AT24C02C原理

引脚                         功能

VCC、GND             电源

WP                          写保护

SCL、SDA              I2C接口

A0、A1、A2           I2C地址

 

二.代码

1.引脚、参数宏定义

#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

2.io引脚初始化配置

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);
}

3.i2c接口初始化配置

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);
}

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

#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

4.i2c读、写函数

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
    \param[in]  p_buffer: pointer to the buffer that receives the data read from the EEPROM
    \param[in]  read_address: EEPROM's internal address to start reading from
    \param[in]  number_of_byte: number of bytes to reads from the EEPROM
    \param[out] 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;
        }
    }
}

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

uint8_t i2c_24c02_test(void)
{
    uint16_t i;
    uint8_t i2c_buffer_write[BUFFER_SIZE];
    uint8_t i2c_buffer_read[BUFFER_SIZE];

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

    /* initialize i2c_buffer_write */
    for(i = 0; i < BUFFER_SIZE; i++) {
        i2c_buffer_write[i] = i;
        printf("0x%02X ", i2c_buffer_write[i]);
        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[i] != i2c_buffer_write[i]) {
            printf("0x%02X ", i2c_buffer_read[i]);
            printf("Err:data read and write aren't matching.\n\r");
            return I2C_FAIL;
        }
        printf("0x%02X ", i2c_buffer_read[i]);
        if(15 == i % 16) {
            printf("\r\n");
        }
    }
    printf("I2C-AT24C02 test passed!\n\r");
    return I2C_OK;
}

 

三.编译烧录测验

      编译烧录后日志如下:

 

图2:I2C读写EEPROM

 

      上面可以看到,i2c读写EEPROM AT24C02获得成功。

 

最新回复

通讯速率怎么计算的呀   详情 回复 发表于 前天 08:51
点赞 关注
个人签名

保持热爱

 
 

回复
举报

670

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

看上GD的IIC应用还是挺简单的

点评

SDK写的不错,可以很方便实用  详情 回复 发表于 2024-5-14 22:02
 
 
 

回复

507

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
jobszheng5 发表于 2024-5-12 13:33 看上GD的IIC应用还是挺简单的

SDK写的不错,可以很方便使用

个人签名

保持热爱

 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

4
 

通讯速率怎么计算的呀

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表