[MCU] 【兆易GD32H759I-EVAL】 i2c读写at24c02测试

TL-LED   2024-5-14 23:58 楼主

通过官网的i2c例程测试下at24c02读写测试。

 

一、硬件部分

 

1.1、i2c硬件电路图部分

I2C1使用端口PH4和PB11

001.jpg

 

1.2、数据手册中PH4和PB11的映射

003.jpg 002.jpg

 

1.3、at24c02存储器参数

004.jpg

 

存储结构

005.jpg

 

at24c02总存储空间是2048bits=2048/8=256字节。内部有32页,每页有8个字节。

 

二、程序部分

 

2.1、i2c引脚配置

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

 

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

 

2.3、at24c02写函数

void eeprom_buffer_write(uint8_t *p_buffer, uint8_t write_address, uint16_t number_of_byte)
{
    uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0;

    address = write_address % I2C_PAGE_SIZE;
    count = I2C_PAGE_SIZE - address;
    number_of_page =  number_of_byte / I2C_PAGE_SIZE;
    number_of_single = number_of_byte % I2C_PAGE_SIZE;

    /* if write_address is I2C_PAGE_SIZE aligned */
    if(0 == address) {
        while(number_of_page--) {
            eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE);
            delay_1ms(6);
            write_address +=  I2C_PAGE_SIZE;
            p_buffer += I2C_PAGE_SIZE;
        }
        if(0 != number_of_single) {
            eeprom_page_write(p_buffer, write_address, number_of_single);
            delay_1ms(6);
        }
    } else {
        /* if write_address is not I2C_PAGE_SIZE aligned */
        if(number_of_byte < count) {
            eeprom_page_write(p_buffer, write_address, number_of_byte);
            delay_1ms(6);
        } else {
            number_of_byte -= count;
            number_of_page =  number_of_byte / I2C_PAGE_SIZE;
            number_of_single = number_of_byte % I2C_PAGE_SIZE;
            if(0 != count) {
                eeprom_page_write(p_buffer, write_address, count);
                delay_1ms(6);
                write_address += count;
                p_buffer += count;
            }
            /* write page */
            while(number_of_page--) {
                eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE);
                delay_1ms(6);
                write_address +=  I2C_PAGE_SIZE;
                p_buffer += I2C_PAGE_SIZE;
            }
            /* write single */
            if(0 != number_of_single) {
                eeprom_page_write(p_buffer, write_address, number_of_single);
                delay_1ms(6);
            }
        }
    }
}

 

2.4、at24c02读函数

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

2.5、main.c

#include "main.h"

void cache_enable(void);

char txbuf[]="https://bbs.eeworld.com.cn/GD32H759I-EVAL";
char rxbuf[];

int main(void)
{
	uint8_t x=0;
	uint32_t sd=0;
	uint32_t yd=0;
	cache_enable();
	systick_config();
	init_usart(115200);
	init_led();
	gpio_config();
	i2c_config();
	i2c_eeprom_init();
	exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);
	init_lcd();
	LCDDisplayDir(LCD_SCREEN_HORIZONTAL);
    LCDClear(LCD_COLOR_WHITE);

	eeprom_buffer_write(txbuf, 0x00, sizeof(txbuf));
	
	LCDShowString(10, 20, 400,16, LCD_FONT_16, LCD_TEXT_TRANS, LCD_COLOR_RED, NULL, "at24c02 write data:");
	LCDShowString(10, 40, 400,16, LCD_FONT_16, LCD_TEXT_TRANS, LCD_COLOR_RED, NULL, txbuf);

	eeprom_buffer_read(rxbuf, 0x00, sizeof(txbuf));
	
	LCDShowString(10, 80, 400,16, LCD_FONT_16, LCD_TEXT_TRANS, LCD_COLOR_BLUE, NULL, "at24c02 read data:");
	LCDShowString(10, 100, 400,16, LCD_FONT_16, LCD_TEXT_TRANS, LCD_COLOR_BLUE, NULL, rxbuf);
 
	while(1) 
	{
		delay_1ms(100);
	}
}

void cache_enable(void)
{
    /* enable i-cache */
    SCB_EnableICache();

    /* enable d-cache */
    SCB_EnableDCache();
}

 

三、运行结果

 

下载程序,开发板运行后,显示屏上显示写和读at24c02的内容。

at24c02.jpg

 

四、附件

 

2024051423554292.c (18.66 KB)
(下载次数: 1, 2024-5-14 23:55 上传)
at24cxx.h (2.64 KB)
(下载次数: 1, 2024-5-14 23:55 上传)
i2c.c (4.6 KB)
(下载次数: 2, 2024-5-14 23:55 上传)
i2c.h (2.38 KB)
(下载次数: 1, 2024-5-14 23:55 上传)

 

 

回复评论 (1)

文章非常棒,从原理图到外设的介绍,源代码都有提供。

点赞  2024-6-1 11:40
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复