通过官网的i2c例程测试下at24c02读写测试。
一、硬件部分
1.1、i2c硬件电路图部分
I2C1使用端口PH4和PB11
1.2、数据手册中PH4和PB11的映射
1.3、at24c02存储器参数
存储结构
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的内容。
四、附件
文章非常棒,从原理图到外设的介绍,源代码都有提供。