cbad06d616
- 将 touch 底层从软件 I2C 位冲切换为硬件 I2C0 (PB6/PB7) - 修复 i2c_driver I2C0 引脚映射 (PB8/PB9 -> PB6/PB7) - 重写 master_write_read() 实现正确的重复起始条件 - 添加 i2c_driver.h C API 声明供 C 代码调用 - 添加 GT1151 EXTI 中断 (PD11, EXTI11 下降沿触发) - 删除 touch.h 中废弃的软件 I2C 函数声明 - test_touch() 改为中断驱动,无触摸时 I2C 总线空闲
373 lines
8.8 KiB
C++
373 lines
8.8 KiB
C++
#include "i2c_driver.h"
|
|
#include "gd32f4xx.h"
|
|
#include <cstddef>
|
|
|
|
#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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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;
|
|
}
|