#include "app_cfg.h"
#include "app_type.h"
#include "interfaces.h"
#if IFS_I2C_EN
#include "../core.h"
#define IIC_NUM 2
struct i2c_ctrl_t
{
uint8_t chip_addr;
uint8_t msg_len;
uint8_t msg_prt;
uint16_t msg_buf_prt;
struct interface_i2c_msg_t *msg;
void *param;
void (*callback)(void *, vsf_err_t);
} static gd32f1x0_i2c[IIC_NUM];
struct i2c_param_t
{
I2C_TypeDef *reg;
struct gd32f1x0_afio_pin_t sda[3];
struct gd32f1x0_afio_pin_t scl[3];
} static const gd32f1x0_i2c_param[IIC_NUM] =
{
#if IIC_NUM >= 1
{
I2C1,
{
{0, 10, 4}, // PA10, AF4
{1, 7, 1}, // PB7, AF1
{1, 9, 1}, // PB9, AF1
},
{
{0, 9, 4}, // PA9, AF4
{1, 6, 1}, // PB6, AF1
{1, 8, 1}, // PB8, AF1
},
},
#endif
#if IIC_NUM >= 2
{
I2C2,
{
{0, 1, 4}, // PA1, AF4
{1, 11, 1}, // PB11, AF1
{6, 7, -1}, // PF7, default
},
{
{0, 0, 4}, // PA0, AF4
{1, 10, 1}, // PB10, AF1
{6, 6, -1}, // PF6, default
},
},
#endif
};
// index spec(LSB to MSB):
// 2-bit iic_idx, 3-bit sda_idx, 3-bit scl_idx
vsf_err_t gd32f1x0_i2c_init(uint8_t index)
{
uint8_t iic_idx = (index & 0x03) >> 0;
uint8_t sda_idx = (index & 0x1C) >> 2;
uint8_t scl_idx = (index & 0xE0) >> 5;
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
gd32f1x0_afio_config(&gd32f1x0_i2c_param[iic_idx].sda[sda_idx], gd32f1x0_GPIO_AF | gd32f1x0_GPIO_OD);
gd32f1x0_afio_config(&gd32f1x0_i2c_param[iic_idx].scl[scl_idx], gd32f1x0_GPIO_AF | gd32f1x0_GPIO_OD);
RCC->APB1CCR |= RCC_APB1CCR_I2C1EN << iic_idx;
reg->CTLR1 = 0;
return VSFERR_NONE;
}
vsf_err_t gd32f1x0_i2c_fini(uint8_t index)
{
uint8_t iic_idx = (index & 0x03) >> 0;
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
reg->CTLR1 = 0;
return VSFERR_NONE;
}
vsf_err_t gd32f1x0_i2c_config(uint8_t index, uint16_t kHz)
{
uint8_t iic_idx = (index & 0x03) >> 0;
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
struct gd32f1x0_info_t *info;
uint16_t iic_clk, iic_freq;
gd32f1x0_interface_get_info(&info);
iic_clk = info->apb_freq_hz / 1000000;
iic_clk = min(iic_clk, 36);
reg->CTLR2 = iic_clk;
if (kHz <= 100)
{
// standard mode
iic_freq = info->apb_freq_hz / (kHz * 2000);
if (iic_freq < 4)
iic_freq = 4;
reg->RTR = (iic_clk >= 36) ? 36 : iic_clk + 1;
}
else
{
// fast mode
iic_freq = info->apb_freq_hz / (kHz * 3000);
if (!iic_freq)
iic_freq = 1;
reg->RTR = (uint16_t)(((iic_clk * 300) / 1000) + 1);
}
reg->CLKR = iic_freq;
reg->CTLR1 = I2C_CTLR1_I2CEN;
switch (iic_idx)
{
#if IIC_NUM >= 1
case 0: NVIC_EnableIRQ(I2C1_EV_IRQn); NVIC_EnableIRQ(I2C1_ER_IRQn); break;
#endif
#if IIC_NUM >= 2
case 1: NVIC_EnableIRQ(I2C2_EV_IRQn); NVIC_EnableIRQ(I2C2_ER_IRQn); break;
#endif
}
reg->CTLR2 |= I2C_CTLR2_EE | I2C_CTLR2_EIE | I2C_CTLR2_BIE;
return VSFERR_NONE;
}
vsf_err_t gd32f1x0_i2c_config_cb(uint8_t index, void *param,
void (*callback)(void *, vsf_err_t))
{
uint8_t iic_idx = (index & 0x03) >> 0;
gd32f1x0_i2c[iic_idx].param = param;
gd32f1x0_i2c[iic_idx].callback = callback;
return VSFERR_NONE;
}
vsf_err_t gd32f1x0_i2c_xfer(uint8_t index, uint16_t chip_addr,
struct interface_i2c_msg_t *msg, uint8_t msg_len)
{
uint8_t iic_idx = (index & 0x03) >> 0;
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
if ((msg == NULL) || (msg_len == 0))
return VSFERR_INVALID_PARAMETER;
gd32f1x0_i2c[iic_idx].chip_addr = chip_addr;
gd32f1x0_i2c[iic_idx].msg = msg;
gd32f1x0_i2c[iic_idx].msg_len = msg_len;
gd32f1x0_i2c[iic_idx].msg_prt = 0;
gd32f1x0_i2c[iic_idx].msg_buf_prt = 0;
reg->CTLR1 |= I2C_CTLR1_GENSTA;
return VSFERR_NONE;
}
static void gd32f1x0_i2c_cb(uint8_t iic_idx, vsf_err_t err)
{
struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
// MUST wait STOP clear, or next START will fail
reg->CTLR1 |= I2C_CTLR1_GENSTP;
while (reg->CTLR1 & I2C_CTLR1_GENSTP);
if (ctrl->callback != NULL)
ctrl->callback(ctrl->param, err);
}
static void gd32f1x0_i2c_chk_recv_next(uint8_t iic_idx)
{
struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
struct interface_i2c_msg_t *msg = &ctrl->msg[ctrl->msg_prt];
if ((msg->flag & I2C_ACKLAST) || (ctrl->msg_buf_prt < msg->len - 1) ||
((ctrl->msg_len > ctrl->msg_prt + 1) &&
(ctrl->msg[ctrl->msg_prt + 1].flag & (I2C_READ | I2C_NOSTART))))
{
reg->CTLR1 |= I2C_CTLR1_ACKEN;
}
else
{
reg->CTLR1 &= ~I2C_CTLR1_ACKEN;
}
}
static void gd32f1x0_i2c_err(uint8_t iic_idx)
{
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
reg->STR1 &= ~(I2C_STR1_BE | I2C_STR1_LOSTARB | I2C_STR1_AE);
gd32f1x0_i2c_cb(iic_idx, VSFERR_FAIL);
}
static void gd32f1x0_i2c_int(uint8_t iic_idx)
{
struct i2c_ctrl_t *ctrl = &gd32f1x0_i2c[iic_idx];
I2C_TypeDef *reg = gd32f1x0_i2c_param[iic_idx].reg;
struct interface_i2c_msg_t *msg = &ctrl->msg[ctrl->msg_prt];
uint16_t status = reg->STR1;
if (status & I2C_STR1_SBSEND)
{
// I2C_STR1_SBSEND is cleared by reading STR1 and writing DTR
reg->DTR = (ctrl->chip_addr << 1) | ((msg->flag & I2C_READ) ? 1 : 0);
// can not put in I2C_STR1_ADDSEND, no idea why
if (msg->flag & I2C_READ)
{
gd32f1x0_i2c_chk_recv_next(iic_idx);
}
}
else if (status & I2C_STR1_ADDSEND)
{
// I2C_STR1_ADDSEND is cleared by reading STR1 and reading STR2
status = reg->STR2;
}
else if (status & I2C_STR1_TBE)
{
// I2C_STR1_TBE is cleared by writing DTR while sending data
if (ctrl->msg_buf_prt < msg->len)
{
send_data:
reg->DTR = msg->buf[ctrl->msg_buf_prt++];
}
else if (++ctrl->msg_prt < ctrl->msg_len)
{
ctrl->msg_buf_prt = 0;
msg = &ctrl->msg[ctrl->msg_prt];
if (!(msg->flag & I2C_READ) && (msg->flag & I2C_NOSTART))
goto send_data;
else
reg->CTLR1 |= I2C_CTLR1_GENSTA;
}
else
{
gd32f1x0_i2c_cb(iic_idx, VSFERR_NONE);
}
}
else if (status & I2C_STR1_RBNE)
{
msg->buf[ctrl->msg_buf_prt++] = reg->DTR;
if (ctrl->msg_buf_prt < msg->len)
{
recv_data:
gd32f1x0_i2c_chk_recv_next(iic_idx);
}
else if (++ctrl->msg_prt < ctrl->msg_len)
{
ctrl->msg_buf_prt = 0;
msg = &ctrl->msg[ctrl->msg_prt];
if ((msg->flag & I2C_READ) && (msg->flag & I2C_NOSTART))
goto recv_data;
else
reg->CTLR1 |= I2C_CTLR1_GENSTA;
}
else
{
gd32f1x0_i2c_cb(iic_idx, VSFERR_NONE);
}
}
}
#if IIC_NUM >= 1
ROOTFUNC void I2C1_EV_IRQHandler(void)
{
gd32f1x0_i2c_int(0);
}
ROOTFUNC void I2C1_ER_IRQHandler(void)
{
gd32f1x0_i2c_err(0);
}
#endif
#if IIC_NUM >= 2
ROOTFUNC void I2C2_EV_IRQHandler(void)
{
gd32f1x0_i2c_int(1);
}
ROOTFUNC void I2C2_ER_IRQHandler(void)
{
gd32f1x0_i2c_err(1);
}
#endif
#endif