#include "i2c_driver.h" #include "gd32f4xx.h" #include #define I2C_TIMEOUT 50000 struct i2c_hw_config_t { uint32_t i2c_periph; rcu_periph_enum rcu_clock; uint32_t gpio_port; uint32_t scl_pin; uint32_t sda_pin; uint32_t af; rcu_periph_enum gpio_rcu; }; static constexpr i2c_hw_config_t i2c_hw_map[] = { {I2C0, RCU_I2C0, GPIOB, GPIO_PIN_6, GPIO_PIN_7, GPIO_AF_4, RCU_GPIOB}, {I2C1, RCU_I2C1, GPIOB, GPIO_PIN_10, GPIO_PIN_11, GPIO_AF_4, RCU_GPIOB}, {I2C2, RCU_I2C2, GPIOC, GPIO_PIN_4, GPIO_PIN_5, GPIO_AF_4, RCU_GPIOC}, }; static RetCode wait_flag(uint32_t i2c_periph, i2c_flag_enum flag) { uint32_t timeout = I2C_TIMEOUT; while (RESET == i2c_flag_get(i2c_periph, flag)) { if (--timeout == 0) { return RET_ERROR; } } return RET_OK; } extern "C" { static I2cBus i2c_0(I2cPort::_0); static I2cBus i2c_1(I2cPort::_1); static I2cBus i2c_2(I2cPort::_2); static I2cBus *i2c_instances[] = {&i2c_0, &i2c_1, &i2c_2}; static uint8_t i2c_inited[3] = {0}; int i2c_init(uint8_t port, uint32_t speed_hz) { if (port >= 3) return -1; I2cConfig cfg; cfg.speed_hz = speed_hz; RetCode ret = i2c_instances[port]->init(cfg); i2c_inited[port] = (ret == RET_OK) ? 1 : 0; return i2c_inited[port] ? 0 : -1; } int i2c_master_write(uint8_t port, uint16_t dev_addr, const uint8_t *data, uint32_t len) { if (port >= 3 || !i2c_inited[port]) return -1; I2cDevice dev(dev_addr); return i2c_instances[port]->master_write(dev, data, len) == RET_OK ? 0 : -1; } int i2c_master_read(uint8_t port, uint16_t dev_addr, uint8_t *data, uint32_t len) { if (port >= 3 || !i2c_inited[port]) return -1; I2cDevice dev(dev_addr); return i2c_instances[port]->master_read(dev, data, len) == RET_OK ? 0 : -1; } int i2c_master_write_read(uint8_t port, uint16_t dev_addr, const uint8_t *wdata, uint32_t wlen, uint8_t *rdata, uint32_t rlen) { if (port >= 3 || !i2c_inited[port]) return -1; I2cDevice dev(dev_addr); return i2c_instances[port]->master_write_read(dev, wdata, wlen, rdata, rlen) == RET_OK ? 0 : -1; } } /* extern "C" */ I2cDevice::I2cDevice(uint16_t dev_addr) : dev_addr_(dev_addr) { } RetCode I2cDevice::init() { return RET_OK; } I2cBus::I2cBus(I2cPort port) : port_(port) { } I2cBus::~I2cBus() { if (initialized_) { deinit(); } } RetCode I2cBus::init(const I2cConfig &config) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(i2c_hw_map) / sizeof(i2c_hw_map[0])) { return RET_INVALID_PARAM; } const i2c_hw_config_t &hw = i2c_hw_map[port_idx]; if (hw.i2c_periph == 0) { return RET_NOT_SUPPORTED; } config_ = config; rcu_periph_clock_enable(hw.rcu_clock); rcu_periph_clock_enable(hw.gpio_rcu); gpio_af_set(hw.gpio_port, hw.af, hw.scl_pin | hw.sda_pin); gpio_mode_set(hw.gpio_port, GPIO_MODE_AF, GPIO_PUPD_PULLUP, hw.scl_pin | hw.sda_pin); gpio_output_options_set(hw.gpio_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, hw.scl_pin | hw.sda_pin); i2c_deinit(hw.i2c_periph); uint32_t speed = config.speed_hz; if (speed == 0) { speed = 100000; } i2c_clock_config(hw.i2c_periph, speed, I2C_DTCY_2); i2c_mode_addr_config(hw.i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00); i2c_enable(hw.i2c_periph); i2c_ack_config(hw.i2c_periph, I2C_ACK_ENABLE); initialized_ = true; return RET_OK; } RetCode I2cBus::deinit() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(i2c_hw_map) / sizeof(i2c_hw_map[0])) { return RET_INVALID_PARAM; } const i2c_hw_config_t &hw = i2c_hw_map[port_idx]; i2c_deinit(hw.i2c_periph); rcu_periph_clock_disable(hw.rcu_clock); initialized_ = false; return RET_OK; } static RetCode i2c_master_start(uint32_t i2c_periph, uint16_t addr, uint32_t direction) { uint32_t timeout = I2C_TIMEOUT; while (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY)) { if (--timeout == 0) { return RET_TIMEOUT; } } i2c_start_on_bus(i2c_periph); if (wait_flag(i2c_periph, I2C_FLAG_SBSEND) != RET_OK) { return RET_TIMEOUT; } i2c_master_addressing(i2c_periph, addr, direction); if (wait_flag(i2c_periph, I2C_FLAG_ADDSEND) != RET_OK) { return RET_TIMEOUT; } i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND); return RET_OK; } RetCode I2cBus::master_write(I2cDevice &dev, const uint8_t *data, uint32_t len) { if (data == nullptr || len == 0) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; uint8_t port_idx = static_cast(port_); const i2c_hw_config_t &hw = i2c_hw_map[port_idx]; uint32_t i2c = hw.i2c_periph; RetCode ret = i2c_master_start(i2c, dev.dev_addr_, I2C_TRANSMITTER); if (ret != RET_OK) { i2c_stop_on_bus(i2c); return ret; } for (uint32_t i = 0; i < len; i++) { if (wait_flag(i2c, I2C_FLAG_TBE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_data_transmit(i2c, data[i]); } if (wait_flag(i2c, I2C_FLAG_TBE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_stop_on_bus(i2c); return RET_OK; } RetCode I2cBus::master_read(I2cDevice &dev, uint8_t *data, uint32_t len) { if (data == nullptr || len == 0) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; uint8_t port_idx = static_cast(port_); const i2c_hw_config_t &hw = i2c_hw_map[port_idx]; uint32_t i2c = hw.i2c_periph; if (len == 1) { i2c_ack_config(i2c, I2C_ACK_DISABLE); } else { i2c_ack_config(i2c, I2C_ACK_ENABLE); } RetCode ret = i2c_master_start(i2c, dev.dev_addr_, I2C_RECEIVER); if (ret != RET_OK) { i2c_stop_on_bus(i2c); return ret; } for (uint32_t i = 0; i < len; i++) { if (i == len - 1) { i2c_ack_config(i2c, I2C_ACK_DISABLE); i2c_stop_on_bus(i2c); } if (wait_flag(i2c, I2C_FLAG_RBNE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } data[i] = i2c_data_receive(i2c); } return RET_OK; } RetCode I2cBus::master_write_read(I2cDevice &dev, const uint8_t *wdata, uint32_t wlen, uint8_t *rdata, uint32_t rlen) { if (wdata == nullptr || wlen == 0 || rdata == nullptr || rlen == 0) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; uint8_t port_idx = static_cast(port_); const i2c_hw_config_t &hw = i2c_hw_map[port_idx]; uint32_t i2c = hw.i2c_periph; // === 写阶段:发送寄存器地址(不发 STOP) === uint32_t timeout = I2C_TIMEOUT; while (i2c_flag_get(i2c, I2C_FLAG_I2CBSY)) { if (--timeout == 0) return RET_TIMEOUT; } i2c_start_on_bus(i2c); if (wait_flag(i2c, I2C_FLAG_SBSEND) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_master_addressing(i2c, dev.dev_addr_, I2C_TRANSMITTER); if (wait_flag(i2c, I2C_FLAG_ADDSEND) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_flag_clear(i2c, I2C_FLAG_ADDSEND); for (uint32_t i = 0; i < wlen; i++) { if (wait_flag(i2c, I2C_FLAG_TBE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_data_transmit(i2c, wdata[i]); } if (wait_flag(i2c, I2C_FLAG_TBE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } // === 读阶段:以重复起始条件开始(无 STOP 间隔) === if (rlen == 1) { i2c_ack_config(i2c, I2C_ACK_DISABLE); } else { i2c_ack_config(i2c, I2C_ACK_ENABLE); } i2c_start_on_bus(i2c); if (wait_flag(i2c, I2C_FLAG_SBSEND) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_master_addressing(i2c, dev.dev_addr_, I2C_RECEIVER); if (wait_flag(i2c, I2C_FLAG_ADDSEND) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } i2c_flag_clear(i2c, I2C_FLAG_ADDSEND); for (uint32_t i = 0; i < rlen; i++) { if (i == rlen - 1) { i2c_ack_config(i2c, I2C_ACK_DISABLE); i2c_stop_on_bus(i2c); } if (wait_flag(i2c, I2C_FLAG_RBNE) != RET_OK) { i2c_stop_on_bus(i2c); return RET_TIMEOUT; } rdata[i] = i2c_data_receive(i2c); } return RET_OK; }