打印
[研电赛技术支持]

GD32L233 I2C擦写外挂Flash测试

[复制链接]
120|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1.硬件选型
单片机:      GD32L233KBQ6



EEPROM:  FM24C256E



A0-A2高低电平组合决定从机(EEPROM)地址,WP高低电平决定EEPROM写入权限,具体可查询官方手册。

2.main.c
#include "gd32l23x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "gd32l23x_eval.h"
#include "gd32l23x_i2c.h"

#define EEPROM_ADDR 0x50  

void delay(volatile uint32_t t) {
    while(t--);
}

void usart0_gpio_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);      

    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);    // PA9 -> USART0_TX
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);   // PA10 -> USART0_RX

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9 | GPIO_PIN_10);
}

void usart0_config(void)
{
    rcu_periph_clock_enable(RCU_USART0);

    usart_deinit(USART0); // 复位

    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);   
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);

    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
        usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_enable(USART0);
}

void i2c0_gpio_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_I2C0);

    gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
}

void i2c0_config(void)
{
    i2c_deinit(I2C0);

    // 配置时钟:设置SCL高低电平持续时间 (单位 tI2CCLK),默认配置为 100kHz
    i2c_master_clock_config(I2C0, 0x13, 0x13);    // 根据手册调节 SCLH/SCLL
    i2c_timing_config(I2C0, 0x03, 0x02, 0x02);    // PSC, SCL delay, SDA delay

    // 启用模拟和数字滤波
    i2c_analog_noise_filter_enable(I2C0);
    i2c_digital_noise_filter_config(I2C0, FILTER_LENGTH_2);

    // 启用 I2C 外设
    i2c_enable(I2C0);
}


/*!
    \brief      向 I2C 外部 EEPROM 写入一个字节数据
    \param[in]  mem_addr: EEPROM 内部地址
    \param[in]  data: 要写入的数据
    \retval     无
*/
void eeprom_write(uint16_t mem_addr, uint8_t data)
{
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    // 顺序修正
    i2c_master_addressing(I2C0, EEPROM_ADDR << 1, I2C_MASTER_TRANSMIT);
    i2c_transfer_byte_number_config(I2C0, 3);  // 地址高、低 + 数据
    i2c_automatic_end_enable(I2C0);
    i2c_start_on_bus(I2C0);

    // 等待发送缓冲区空
    while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_data_transmit(I2C0, (mem_addr >> 8) & 0xFF);  // 高位地址

    while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_data_transmit(I2C0, mem_addr & 0xFF);         // 低位地址

    while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_data_transmit(I2C0, data);

    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
}


/*!
    \brief      从 I2C 外部 EEPROM 指定地址读取一个字节数据
    \param[in]  mem_addr: EEPROM 内部地址
    \retval     val: 读取到的数据
*/
uint8_t eeprom_read(uint16_t mem_addr)
{
    uint8_t data;

    // 等待I2C总线空闲
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    // 第一步:发送内存地址(写操作)
    i2c_master_addressing(I2C0, EEPROM_ADDR << 1, I2C_MASTER_TRANSMIT);
    i2c_transfer_byte_number_config(I2C0, 2);       // 高地址 + 低地址
    i2c_automatic_end_enable(I2C0);
    i2c_start_on_bus(I2C0);

    while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_data_transmit(I2C0, (mem_addr >> 8) & 0xFF);  // 地址高字节

    while(!i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_data_transmit(I2C0, mem_addr & 0xFF);         // 地址低字节

    // 等待地址写完 + STOP 发送
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    // 第二步:重新发送起始信号,切换为读操作
    i2c_master_addressing(I2C0, EEPROM_ADDR << 1, I2C_MASTER_RECEIVE);
    i2c_transfer_byte_number_config(I2C0, 1);         // 只读取1字节
    i2c_automatic_end_enable(I2C0);
    i2c_start_on_bus(I2C0);

    // 等待数据到达
    while(!i2c_flag_get(I2C0, I2C_FLAG_RBNE));
    data = i2c_data_receive(I2C0);

    // 等待 STOP 完成
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
    return data;
}

void i2c_flash_test(){
        uint16_t test_addr = 0x1234;
        uint8_t write_val = 0x66;
        eeprom_write(test_addr, write_val);
        delay_1ms(10);
        uint8_t read_val = 0;
        read_val = eeprom_read(test_addr);
       
    char buf[64];
    sprintf(buf, "\r\nI2C Flash Test - Wrote: 0x%02X, Read: 0x%02X\r\n", write_val, read_val);
    for (char *p = buf; *p; ++p) {
        usart_data_transmit(USART0, *p);
        while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET);
    }
}

int main(void)
{
    SystemInit();   
    systick_config();       
    usart0_gpio_config();      
    usart0_config();            
       
    i2c0_gpio_config();
    i2c0_config();

    delay_1ms(10);
        i2c_flash_test();

    while (1);
}



3.效果实现及注意事项



注意:Start之后必须立即发送从机地址,否则某些芯片(如GD32)不会自动开始传输,甚至不激活I2C控制器。因此最好在

i2c_start_on_bus(I2C0);


前完成配置:

i2c_master_addressing(I2C0, EEPROM_ADDR << 1, I2C_MASTER_TRANSMIT);
i2c_transfer_byte_number_config(I2C0, 3);  // 地址高、低 + 数据
i2c_automatic_end_enable(I2C0);



————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_60013390/article/details/149112685

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

106

主题

4312

帖子

4

粉丝