273 lines
9.3 KiB
C
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(); }
|