初始提交
This commit is contained in:
511
driver/src/hw3/i2c_hw.c
Executable file
511
driver/src/hw3/i2c_hw.c
Executable file
@@ -0,0 +1,511 @@
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user