512 lines
13 KiB
C
Executable File
512 lines
13 KiB
C
Executable File
|
|
/****************************************************************************
|
|
*
|
|
* Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
*
|
|
* This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
* be copied by any method or incorporated into another program without
|
|
* the express written consent of Aerospace C.Power. This Information or any portion
|
|
* thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
* is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
* liability for its use in any way and conveys no license or title under
|
|
* any patent or copyright and makes no representation or warranty that this
|
|
* Information is free from patent or copyright infringement.
|
|
*
|
|
* ****************************************************************************/
|
|
#include "os_types.h"
|
|
#include "iot_errno.h"
|
|
#include "apb_glb_reg.h"
|
|
#include "hw_reg_api.h"
|
|
#include "iot_io.h"
|
|
|
|
#include "iot_i2c_api.h"
|
|
#include "gpio_mtx.h"
|
|
#include "i2c_reg.h"
|
|
#include "i2c_hw.h"
|
|
#include "apb.h"
|
|
|
|
#include "iot_irq.h"
|
|
|
|
static const IOT_INTR_VECTOR g_i2c_vector_table[] = {
|
|
HAL_VECTOR_IIC_M0, HAL_VECTOR_IIC_M1, HAL_VECTOR_IIC_M2, HAL_VECTOR_IIC_M3};
|
|
|
|
i2c_isr g_isr[I2C_PORT_NUM] = {NULL, NULL, NULL, NULL};
|
|
|
|
uint8_t i2c_gpio_sel(uint8_t port, uint8_t scl, uint8_t sda)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
gpio_mtx_enable();
|
|
uint8_t scl_func = 0;
|
|
uint8_t sda_func = 0;
|
|
scl_func = gpio_pin_func_get(scl);
|
|
sda_func = gpio_pin_func_get(sda);
|
|
gpio_sig_info_t info = {0};
|
|
if (port == IOT_I2C_PORT_0) {
|
|
info.sig_type = 2;
|
|
info.CFG[0].type = IO_TYPE_OUT;
|
|
info.CFG[0].func = scl_func;
|
|
info.CFG[0].gpio = scl;
|
|
info.CFG[0].inid = 0xff;
|
|
info.CFG[0].outid = GPIO_MTX_I2C0_SCL_OUT;
|
|
info.CFG[1].type = IO_TYPE_IO;
|
|
info.CFG[1].func = sda_func;
|
|
info.CFG[1].gpio = sda;
|
|
info.CFG[1].inid = GPIO_MTX_I2C0_SDA_IN;
|
|
info.CFG[1].outid = GPIO_MTX_I2C0_SDA_OUT;
|
|
} else if (port == IOT_I2C_PORT_1){
|
|
info.sig_type = 2;
|
|
info.CFG[0].type = IO_TYPE_OUT;
|
|
info.CFG[0].func = scl_func;
|
|
info.CFG[0].gpio = scl;
|
|
info.CFG[0].inid = 0xff;
|
|
info.CFG[0].outid = GPIO_MTX_I2C1_SCL_OUT;
|
|
info.CFG[1].type = IO_TYPE_IO;
|
|
info.CFG[1].func = sda_func;
|
|
info.CFG[1].gpio = sda;
|
|
info.CFG[1].inid = GPIO_MTX_I2C1_SDA_IN;
|
|
info.CFG[1].outid = GPIO_MTX_I2C1_SDA_OUT;
|
|
} else if (port == IOT_I2C_PORT_2) {
|
|
info.sig_type = 2;
|
|
info.CFG[0].type = IO_TYPE_OUT;
|
|
info.CFG[0].func = scl_func;
|
|
info.CFG[0].gpio = scl;
|
|
info.CFG[0].inid = 0xff;
|
|
info.CFG[0].outid = GPIO_MTX_I2C2_SCL_OUT;
|
|
info.CFG[1].type = IO_TYPE_IO;
|
|
info.CFG[1].func = sda_func;
|
|
info.CFG[1].gpio = sda;
|
|
info.CFG[1].inid = GPIO_MTX_I2C2_SDA_IN;
|
|
info.CFG[1].outid = GPIO_MTX_I2C2_SDA_OUT;
|
|
}else if (port == IOT_I2C_PORT_3) {
|
|
info.sig_type = 2;
|
|
info.CFG[0].type = IO_TYPE_OUT;
|
|
info.CFG[0].func = scl_func;
|
|
info.CFG[0].gpio = scl;
|
|
info.CFG[0].inid = 0xff;
|
|
info.CFG[0].outid = GPIO_MTX_I2C3_SCL_OUT;
|
|
info.CFG[1].type = IO_TYPE_IO;
|
|
info.CFG[1].func = sda_func;
|
|
info.CFG[1].gpio = sda;
|
|
info.CFG[1].inid = GPIO_MTX_I2C3_SDA_IN;
|
|
info.CFG[1].outid = GPIO_MTX_I2C3_SDA_OUT;
|
|
}
|
|
|
|
gpio_module_pin_select(&info);
|
|
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_port_enable(uint8_t port)
|
|
{
|
|
if (port == IOT_I2C_PORT_0) {
|
|
apb_enable(APB_I2CM0);
|
|
} else if (port == IOT_I2C_PORT_1) {
|
|
apb_enable(APB_I2CM1);
|
|
} else if (port == IOT_I2C_PORT_2) {
|
|
apb_enable(APB_I2CM2);
|
|
} else if (port == IOT_I2C_PORT_3) {
|
|
apb_enable(APB_I2CM3);
|
|
} else {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_txfifo_full(uint8_t port)
|
|
{
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
|
|
|
|
return REG_FIELD_GET(TX_FIFO_FULL, tmp);
|
|
}
|
|
|
|
uint8_t i2c_txfifo_empty(uint8_t port)
|
|
{
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
|
|
|
|
return REG_FIELD_GET(TX_FIFO_EMPTY, tmp);
|
|
}
|
|
|
|
uint8_t i2c_rxfifo_full(uint8_t port)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
|
|
|
|
return REG_FIELD_GET(RX_FIFO_FULL, tmp);
|
|
}
|
|
|
|
uint8_t i2c_rxfifo_empty(uint8_t port)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_STATUS_ADDR);
|
|
|
|
return REG_FIELD_GET(RX_FIFO_EMPTY, tmp);
|
|
}
|
|
|
|
uint8_t i2c_send_num_set(uint8_t port, uint8_t num)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_DATA_NUM_CONF_ADDR);
|
|
REG_FIELD_SET(SEND_NUM, tmp, num);
|
|
I2C_PORT_WRITE_REG(port, CFG_DATA_NUM_CONF_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_receive_num_set(uint8_t port, uint8_t num)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_DATA_NUM_CONF_ADDR);
|
|
REG_FIELD_SET(REC_NUM, tmp, num);
|
|
I2C_PORT_WRITE_REG(port, CFG_DATA_NUM_CONF_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_mode_set(uint8_t port, uint8_t mode)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
|
|
REG_FIELD_SET(I2C_BUSRT_MODE, tmp, mode);
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_data_dir_mode(uint8_t port, uint8_t dir)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
if (dir != IOT_I2C_DIRC_RD && dir != IOT_I2C_DIRC_WR) {
|
|
return ERR_FAIL;
|
|
}
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
|
|
if (dir == IOT_I2C_DIRC_RD) {
|
|
REG_FIELD_SET(IIC_RD, tmp, 1);
|
|
REG_FIELD_SET(IIC_WR, tmp, 0);
|
|
} else {
|
|
REG_FIELD_SET(IIC_RD, tmp, 0);
|
|
REG_FIELD_SET(IIC_WR, tmp, 1);
|
|
}
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_stop(uint8_t port)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MODE_ADDR);
|
|
REG_FIELD_SET(I2C_TRANS_STOP, tmp, 1);
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MODE_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_start(uint8_t port)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_START_ADDR);
|
|
REG_FIELD_SET(I2C_START, tmp, 1);
|
|
I2C_PORT_WRITE_REG(port, CFG_START_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
//todo
|
|
uint8_t i2c_clear_int_status(uint8_t port, uint32_t mask)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = 0;
|
|
tmp |= mask;
|
|
|
|
I2C_PORT_WRITE_REG(port, CFG_CLR_INT_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
//todo
|
|
uint8_t i2c_clear_master_int_flag(uint8_t port, uint32_t mask)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = 0;
|
|
tmp |= mask;
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_CLR_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_clear_int(uint8_t port, uint32_t mask)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = 0;
|
|
tmp |= mask;
|
|
I2C_PORT_WRITE_REG(port, CFG_CLR_INT_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_enable_int(uint8_t port, uint32_t mask)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR);
|
|
tmp |= mask;
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_disable_int(uint8_t port, uint32_t mask)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR);
|
|
tmp &= ~mask;
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_INT_ENA_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
//todo
|
|
uint8_t i2c_get_int_status(uint8_t port, uint8_t bit)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return (REG_BIT_GET(port, CFG_I2C_STATUS_ADDR, bit));
|
|
}
|
|
|
|
uint8_t i2c_set_baudrate(uint8_t port, uint32_t baud)
|
|
{
|
|
uint32_t temp;
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
temp = I2C_INPUT_CLK_KHZ / baud - 1;// i2c clk 25Mhz
|
|
if (temp > (CLK_DIV_MASK >> CLK_DIV_OFFSET)) {
|
|
temp = CLK_DIV_OFFSET - 1;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_CLOCK_DIV_ADDR);
|
|
REG_FIELD_SET(CLK_DIV, tmp, temp);
|
|
I2C_PORT_WRITE_REG(port, CFG_CLOCK_DIV_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_set_nack_wait_num(uint8_t port, uint32_t num)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_WAIT_NACK_MAX_ADDR);
|
|
REG_FIELD_SET(WAIT_NACK_MAX, tmp, num);
|
|
I2C_PORT_WRITE_REG(port, CFG_WAIT_NACK_MAX_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_tx_fifo_write(uint8_t port, uint8_t data)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
i2c_data_dir_mode(port, IOT_I2C_DIRC_WR);
|
|
|
|
uint32_t cnt = 0;
|
|
while(1) {
|
|
uint8_t ret = i2c_txfifo_full(port);
|
|
if (ret) {
|
|
break;
|
|
} else {
|
|
cnt++;
|
|
if (cnt >= 1000000) {
|
|
iot_printf("i2c_tx_fifo_write timeout.\n");
|
|
return ERR_BUSY;
|
|
}
|
|
}
|
|
}
|
|
I2C_REG(port, CFG_I2C_TX_FIFO_WDATA_ADDR) = data;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_tx_fifo_thrs(uint8_t port, uint8_t thrs)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR);
|
|
REG_FIELD_SET(I2C_TXFIFO_THRS, tmp, thrs);
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t i2c_rx_fifo_thrs(uint8_t port, uint8_t thrs)
|
|
{
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t tmp = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR);
|
|
REG_FIELD_SET(I2C_RXFIFO_THRS, tmp, thrs);
|
|
I2C_PORT_WRITE_REG(port, CFG_I2C_MASTER_FIFO_CFG_ADDR, tmp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint32_t IRAM_ATTR i2c_interupt_handler(uint32_t vector, iot_addrword_t data)
|
|
{
|
|
uint32_t status = 0;
|
|
uint32_t mask = 0;
|
|
int port = 0;
|
|
|
|
/*vector map to port*/
|
|
if (HAL_VECTOR_IIC_M0 == vector) {
|
|
port = IOT_I2C_PORT_0;
|
|
} else if (HAL_VECTOR_IIC_M1 == vector) {
|
|
port = IOT_I2C_PORT_1;
|
|
} else if (HAL_VECTOR_IIC_M2 == vector) {
|
|
port = IOT_I2C_PORT_2;
|
|
} else if (HAL_VECTOR_IIC_M3 == vector) {
|
|
port = IOT_I2C_PORT_3;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
status = I2C_PORT_READ_REG(port, CFG_I2C_MASTER_INT_ST_ADDR);
|
|
if (status & I2C_M_NACK_INT_ST_MASK) {
|
|
mask |= I2C_NACK_TIMEOUT;
|
|
}
|
|
if (status & I2C_M_TX_EMP_INT_ST_MASK) {
|
|
mask |= I2C_FIFO_EMPTY;
|
|
}
|
|
if (status & I2C_M_RX_FULL_INT_ST_MASK) {
|
|
mask |= I2C_FIFO_FULL;
|
|
}
|
|
if (status & I2C_M_TX_UNDERFLOW_INT_ST_MASK) {
|
|
mask |= I2C_FIFO_UNDER;
|
|
}
|
|
if (status & I2C_M_RX_OVERFLOW_INT_ST_MASK) {
|
|
mask |= I2C_FIFO_OVER;
|
|
}
|
|
if (status & I2C_M_DONE_INT_ST_MASK) {
|
|
mask |= I2C_TRANS_DOWN;
|
|
}
|
|
/*call isr*/
|
|
if (NULL != g_isr[port]) {
|
|
g_isr[port](port, mask);
|
|
}
|
|
//---------------------------------------------
|
|
|
|
/*clear all int*/
|
|
i2c_clear_master_int_flag(port, I2C_M_NACK_INT_CLR_MASK
|
|
| I2C_M_TX_EMP_INT_CLR_MASK
|
|
| I2C_M_RX_FULL_INT_CLR_MASK
|
|
| I2C_M_TX_UNDERFLOW_INT_CLR_MASK
|
|
| I2C_M_RX_OVERFLOW_INT_CLR_MASK
|
|
| I2C_M_DONE_INT_CLR_MASK
|
|
);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t i2c_interrupt_init(uint8_t port, uint32_t mask, i2c_isr isr)
|
|
{
|
|
uint32_t i2c_mask = 0;
|
|
if (I2C_INVALID(port)) {
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* clr i2c int */
|
|
i2c_clear_int(port, I2C_INT_CLR_MASK | NACK_INT_CLR_MASK
|
|
| I2C_RXFIFO_CLR_MASK | I2C_TXFIFO_CLR_MASK);
|
|
|
|
i2c_clear_master_int_flag(port, I2C_M_NACK_INT_CLR_MASK
|
|
| I2C_M_TX_EMP_INT_CLR_MASK
|
|
| I2C_M_RX_FULL_INT_CLR_MASK
|
|
| I2C_M_TX_UNDERFLOW_INT_CLR_MASK
|
|
| I2C_M_RX_OVERFLOW_INT_CLR_MASK
|
|
| I2C_M_DONE_INT_CLR_MASK
|
|
);
|
|
|
|
/* inner int enable */
|
|
if (mask & I2C_NACK_TIMEOUT) {
|
|
i2c_mask |= I2C_M_NACK_INT_ENA_MASK;
|
|
}
|
|
if (mask & I2C_FIFO_EMPTY) {
|
|
i2c_mask |= I2C_M_TX_EMP_INT_ENA_MASK;
|
|
}
|
|
if (mask & I2C_FIFO_FULL) {
|
|
i2c_mask |= I2C_M_RX_FULL_INT_ENA_MASK;
|
|
}
|
|
if (mask & I2C_FIFO_UNDER) {
|
|
i2c_mask |= I2C_M_TX_UNDERFLOW_INT_ENA_MASK;
|
|
}
|
|
if (mask & I2C_FIFO_OVER) {
|
|
i2c_mask |= I2C_M_RX_OVERFLOW_INT_ENA_MASK;
|
|
}
|
|
if (mask & I2C_TRANS_DOWN) {
|
|
i2c_mask |= I2C_M_DONE_INT_ENA_MASK;
|
|
}
|
|
i2c_enable_int(port, i2c_mask);
|
|
|
|
g_isr[port] = isr;
|
|
|
|
/* interrupt controller */
|
|
iot_irq_t irq_handle = iot_interrupt_create(g_i2c_vector_table[port],
|
|
HAL_INTR_PRI_0, 0, i2c_interupt_handler);
|
|
|
|
iot_interrupt_attach(irq_handle);
|
|
iot_interrupt_unmask(irq_handle);
|
|
|
|
return 0;
|
|
}
|
|
|