- #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