Files
2026-06-06 16:49:48 +08:00

273 lines
9.3 KiB
C

/*!
* \file xc_drv_i2c.c
*
* \brief Target xc i2c driver implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
*
* _ __ _ ________ _
* | |/ /(_)___ / ____/ /_ (_)___
* | // / __ \/ / / __ \/ / __ \
* / |/ / / / / /___/ / / / / /_/ /
* /_/|_/_/_/ /_/\____/_/ /_/_/ .___/
* /_/
* (C) 2022-2025 XinChip
*
* \endcode
*
* \author ( XinChip ) Alex-J
*
* \author ( XinChip )
*/
/*------------------------------------------------------------------------------------
INCLUDE HEADE FILES
-------------------------------------------------------------------------------------*/
#include "xc_drv_i2c.h"
/*------------------------------------------------------------------------------------
Macros
-------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------
Global Variables
-------------------------------------------------------------------------------------*/
I2C_Block_t i2c_ctl_block;
/*------------------------------------------------------------------------------------
TypeDef
-------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------
Local Variables
-------------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------------
Func Prototype
-------------------------------------------------------------------------------------*/
void xc_i2c_ctl_block_reset(void);
/*------------------------------------------------------------------------------------
Functions
-------------------------------------------------------------------------------------*/
void xc_i2c_init(I2C_InitCfg_t *init_cfg)
{
cpr_ctlapbclken_grctl__i2c_pclk_en__setf(ENABLE);
cpr_rstctl_subrst_sw__i2c_rstn__setf(RSTCTL_ENABLE);
cpr_rstctl_subrst_sw__i2c_rstn__setf(RSTCTL_DISABLE);
cpr_i2c_clk_ctl__i2c_clk_en__setf(ENABLE);
cpr_i2c_clk_ctl__i2c_clk_div__setf(init_cfg->DivClk);
i2c_flag_status_get(I2C_STATUS_ACTIVITY_SET);
i2c_enable__enable__setf(I2C_ENABLE_EN_DISABLE);
i2c_rx_tl__rx_tl__setf(I2C_RX_TL_FIFO_1);
i2c_tx_tl__tx_tl__setf(I2C_TX_TL_FIFO_0);
i2c_intr_en_set(I2C_INTR_EN_RX_UNDER_DISABLE | I2C_INTR_EN_RX_OVER_DISABLE | I2C_INTR_EN_RX_FULL_DISABLE |
I2C_INTR_EN_TX_OVER_DISABLE | I2C_INTR_EN_TX_EMPTY_DISABLE | I2C_INTR_EN_RD_REQ_DISABLE |
I2C_INTR_EN_TX_ABRT_DISABLE | I2C_INTR_EN_RX_DONE_DISABLE | I2C_INTR_EN_ACTIVITY_DISABLE |
I2C_INTR_EN_STOP_DET_DISABLE | I2C_INTR_EN_START_DET_DISABLE | I2C_INTR_EN_GEN_CALL_DISABLE);
i2c_tar__i2c_10bitaddr_master__setf(I2C_TAR_I2C_7BITADDR_MODE);
if (init_cfg->I2C_Mode == I2C_MODE_MASTER) {
i2c_tar__i2c_tar__setf(init_cfg->I2C_SlaveAddr);
i2c_con__master_mode__setf(I2C_CON_MASTER_MODE_ENABLE);
i2c_con__slave_disable__setf(I2C_CON_SLAVE_DISABLE_DISABLE);
} else if (init_cfg->I2C_Mode == I2C_MODE_SLAVE) {
i2c_sar__setf(init_cfg->I2C_SlaveAddr);
i2c_con__master_mode__setf(I2C_CON_MASTER_MODE_DISABLE);
i2c_con__slave_disable__setf(I2C_CON_SLAVE_DISABLE_ENABLE);
i2c_con__addr_10bit_slave__setf(I2C_CON_7BITADDR_SLAVE_MODE);
i2c_con__restart_en__setf(I2C_CON_RESTART_EN_DISABLE);
}
xc_i2c_ctl_block_reset();
if (init_cfg->I2C_ClockSpeed == I2C_FREQUENCY_100K) {
i2c_con__speed__setf(I2C_CON_SPEED_STANDARD_MODE);
if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) {
i2c_ss_scl_hcnt__ss_scl_hcnt__setf(I2C_MLCK32M_FREQUENCY_HCNT_100K);
i2c_ss_scl_lcnt__ss_scl_lcnt__setf(I2C_MLCK32M_FREQUENCY_LCNT_100K);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) {
i2c_ss_scl_hcnt__ss_scl_hcnt__setf(I2C_MLCK48M_FREQUENCY_HCNT_100K);
i2c_ss_scl_lcnt__ss_scl_lcnt__setf(I2C_MLCK48M_FREQUENCY_LCNT_100K);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M) {
i2c_ss_scl_hcnt__ss_scl_hcnt__setf(I2C_MLCK64M_FREQUENCY_HCNT_100K);
i2c_ss_scl_lcnt__ss_scl_lcnt__setf(I2C_MLCK64M_FREQUENCY_LCNT_100K);
}
} else if (init_cfg->I2C_ClockSpeed == I2C_FREQUENCY_400K) {
i2c_con__speed__setf(I2C_CON_SPEED_FAST_MODE);
if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK32M_FREQUENCY_HCNT_400K);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MLCK32M_FREQUENCY_LCNT_400K);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK48M_FREQUENCY_HCNT_400K);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MLCK48M_FREQUENCY_LCNT_400K);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK64M_FREQUENCY_HCNT_400K);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MLCK64M_FREQUENCY_LCNT_400K);
}
} else {
i2c_con__speed__setf(I2C_CON_SPEED_FAST_MODE);
if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK32M_FREQUENCY_HCNT_1M);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MCLK32M_FREQUENCY_LCNT_1M);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK48M_FREQUENCY_HCNT_1M);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MCLK48M_FREQUENCY_LCNT_1M);
} else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M) {
i2c_fs_scl_hcnt__fs_scl_hcnt__setf(I2C_MLCK64M_FREQUENCY_HCNT_1M);
i2c_fs_scl_lcnt__fs_scl_lcnt__setf(I2C_MCLK64M_FREQUENCY_LCNT_1M);
}
}
i2c_flag_status_get(I2C_STATUS_ACTIVITY_SET);
i2c_enable__enable__setf(I2C_ENABLE_EN_ENABLE);
}
void xc_i2c_enable_it(uint32_t val) { i2c_intr_en_set(val); }
void xc_i2c_fifo_rxtl_set(uint32_t val) { i2c_rx_tl__rx_tl__setf(val); }
void xc_i2c_fifo_txtl_set(uint32_t val) { i2c_tx_tl__tx_tl__setf(val); }
void xc_i2c_ctl_block_reset(void)
{
memset(&i2c_ctl_block, 0, sizeof(i2c_ctl_block));
i2c_ctl_block.i2c_read_cb = NULL;
i2c_ctl_block.i2c_write_cb = NULL;
}
void xc_i2c_register_read_cb(i2c_read_callback i2c_cb) { i2c_ctl_block.i2c_read_cb = i2c_cb; }
void xc_i2c_register_write_cb(i2c_write_callback i2c_cb) { i2c_ctl_block.i2c_write_cb = i2c_cb; }
void xc_i2c_slave_addr_set(uint8_t addr)
{
i2c_enable__enable__setf(I2C_ENABLE_EN_DISABLE);
i2c_tar__i2c_tar__setf(addr);
i2c_enable__enable__setf(I2C_ENABLE_EN_ENABLE);
}
uint32_t xc_i2c_write_block(uint8_t dev_addr, uint8_t *src, size_t len, uint16_t reset, uint16_t stop)
{
xc_i2c_slave_addr_set(dev_addr);
uint32_t abort_reason = 0;
uint16_t timeout = 0xFFFF;
for (int i = 0; i < len; i++) {
i2c_data_cmd_set(I2C_DATA_CMD_CMD_WRITE | stop | reset | *src++);
do {
} while (timeout-- && !(i2c_raw_intr_stat_get() & I2C_RAW_INTR_STAT_TX_EMPTY_SET));
if (!timeout) {
break;
}
abort_reason = i2c_tx_abrt_source_get();
if (abort_reason) {
i2c_clr_tx_abrt_get();
break;
}
}
return abort_reason;
}
uint32_t xc_i2c_read_block(uint8_t dev_addr, uint8_t *dst, size_t len, uint16_t reset, uint16_t stop)
{
xc_i2c_slave_addr_set(dev_addr);
uint32_t abort_reason;
uint16_t timeout = 0xFFFF;
for (int i = 0; i < len; i++) {
while (!(I2C_FIFO_LEN - i2c_txflr_get()))
;
i2c_data_cmd_set(I2C_DATA_CMD_CMD_READ | stop | reset);
do {
} while (timeout-- && !i2c_rxflr_get());
if (!timeout) {
DEBUG("xc_i2c_read_block timeout\n");
break;
}
abort_reason = i2c_tx_abrt_source_get();
if (abort_reason) {
DEBUG("xc_i2c_read_block tx_abrt\n");
i2c_clr_tx_abrt_get();
break;
}
*dst++ = i2c_data_cmd_get();
}
return abort_reason;
}
void i2c_user_handler()
{
uint8_t val;
uint32_t stat;
stat = i2c_intr_stat_get();
val = i2c_clr_intr_get();
if (stat & I2C_INTR_STAT_RX_DONE_SET) {
}
if (stat & I2C_INTR_STAT_RX_FULL_SET) {
val = i2c_data_cmd__dat__getf();
if (i2c_ctl_block.i2c_read_cb != NULL) {
i2c_ctl_block.i2c_read_cb(&val, 1);
}
}
if (stat & I2C_INTR_STAT_RD_REQ_SET) {
if (i2c_ctl_block.i2c_write_cb != NULL) {
i2c_ctl_block.i2c_write_cb();
}
}
if (stat & I2C_INTR_STAT_TX_EMPTY_SET) {
}
if (stat & I2C_INTR_STAT_STOP_DET_SET) {
}
}
FlagStatus i2c_flag_status_get(uint32_t i2c_flag)
{
FlagStatus bitstatus = RESET;
if ((i2c_status_get() & i2c_flag) != (uint32_t)RESET) {
bitstatus = SET;
} else {
bitstatus = RESET;
}
return bitstatus;
}
void I2C_Handler() { i2c_user_handler(); }