rt-thread/bsp/CME_M7/StdPeriph_Driver/src/cmem7_i2c.c

323 lines
8.5 KiB
C

/**
*****************************************************************************
* @file cmem7_i2c.c
*
* @brief CMEM7 I2C source file
*
*
* @version V1.0
* @date 3. September 2013
*
* @note
*
*****************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, CAPITAL-MICRO SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2013 Capital-micro </center></h2>
*****************************************************************************
*/
#include "cmem7_i2c.h"
#define I2C_INNER_INT_ALL 0x3FF
typedef struct {
union {
uint32_t DATA_CMD;
struct {
uint32_t DATA : 8;
uint32_t RD_CMD : 1;
uint32_t WR_CMD : 1;
uint32_t WR_RD_CMD : 1;
} DATA_CMD_b;
} INNER;
} I2C_INNER_DATA_CMD;
static uint32_t i2c_GetClock(I2C0_Type* I2Cx) {
uint32_t dividor;
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
if ((uint32_t)I2Cx == (uint32_t)I2C0) {
dividor = GLOBAL_CTRL->CLK_SEL_0_b.I2C0_CLK;
} else if ((uint32_t)I2Cx == (uint32_t)I2C1) {
dividor = GLOBAL_CTRL->CLK_SEL_0_b.I2C1_CLK;
}
return SYSTEM_CLOCK_FREQ / (1 << (dividor + 1));
}
static uint16_t i2c_NormalizeAddr(I2C0_Type* I2Cx, uint16_t addr) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
if (I2Cx->CTRL_b.MODE == I2C_Mode_Master) {
if (I2Cx->CTRL_b.MASTER_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) {
addr &= 0x007F;
} else {
addr &= 0x3FF;
}
}
if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
if (I2Cx->CTRL_b.SLAVE_ADDR_WIDTH == I2C_ADDR_WIDTH_7BIT) {
addr &= 0x007F;
} else {
addr &= 0x3FF;
}
}
return addr;
}
static void i2c_ReadClear(uint32_t bit) {
uint32_t tmp;
tmp = bit;
tmp = tmp;
}
void I2C_Init(I2C0_Type* I2Cx, I2C_InitTypeDef* I2C_Init) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(I2C_Init);
assert_param(IS_I2C_MODE(I2C_Init->I2C_Mode));
assert_param(IS_I2C_ADDR_WIDTH(I2C_Init->I2C_AddressWidth));
// reset
I2Cx->ENABLE_b.RESET = FALSE;
I2Cx->ENABLE_b.RESET = TRUE;
// clear interrupt
I2Cx->INT_MASK = I2C_INNER_INT_ALL;
i2c_ReadClear(I2Cx->CLR_ALL_INT_b.CLEAR);
I2Cx->CTRL_b.MODE = I2C_Init->I2C_Mode;
if (I2Cx->CTRL_b.MODE == I2C_Mode_Master) {
I2Cx->CTRL_b.MASTER_ADDR_WIDTH = I2C_Init->I2C_AddressWidth;
I2Cx->TAR_b.START_BYTE = TRUE;
I2Cx->TAR_b.ADDR10 = i2c_NormalizeAddr(I2Cx, I2C_Init->I2C_Address);
}
if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
I2Cx->CTRL_b.SLAVE_ADDR_WIDTH = I2C_Init->I2C_AddressWidth;
I2Cx->SAR_b.ADDR10 = i2c_NormalizeAddr(I2Cx, I2C_Init->I2C_Address);
}
I2Cx->RX_TL_b.THRESHOLD = 0;
I2Cx->TX_TL_b.THRESHOLD = 0;
I2Cx->SLAVE_NACK_b.NACK = FALSE;
if (I2C_Init->timing) {
I2Cx->SCL_CNT_b.HIGH_LEVEL_TICK =
i2c_GetClock(I2Cx) / I2C_Init->timing->I2C_Freq / 2;
I2Cx->SCL_CNT_b.LOW_LEVEL_TICK =
i2c_GetClock(I2Cx) / I2C_Init->timing->I2C_Freq / 2;
I2Cx->SDA_SETUP_b.TSU_DAT = ((uint64_t)I2C_Init->timing->I2C_TsuDat) *
i2c_GetClock(I2Cx) / 1000000000;
I2Cx->SDA_SETUP_b.TSETUP = ((uint64_t)I2C_Init->timing->I2C_Tsetup) *
i2c_GetClock(I2Cx) / 1000000000;
I2Cx->TSU_STA_SETUP_b.TBUF = ((uint64_t)I2C_Init->timing->I2C_Tbuf) *
i2c_GetClock(I2Cx) / 1000000000;
I2Cx->TSU_STA_SETUP_b.TSU_STA = ((uint64_t)I2C_Init->timing->I2C_TsuSta) *
i2c_GetClock(I2Cx) / 1000000000;
I2Cx->TSU_STA_SETUP_b.SDA_FILTER_EN = I2C_Init->timing->I2C_SdaFilterEn;
I2Cx->TSU_STA_SETUP_b.SDA_FILTER_CNT = I2C_Init->timing->I2C_SdaFilterSpike;
I2Cx->TSU_STA_SETUP_b.SCL_FILTER_EN = I2C_Init->timing->I2C_SclFilterEn;
I2Cx->TSU_STA_SETUP_b.SCL_FILTER_CNT = I2C_Init->timing->I2C_SclFilterSpike;
}
}
void I2C_Enable(I2C0_Type* I2Cx, BOOL enable) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
I2Cx->ENABLE_b.EN = enable;
}
void I2C_EnableInt(I2C0_Type* I2Cx, uint32_t Int, BOOL enable) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_INT(Int));
if (enable) {
I2Cx->INT_MASK &= ~Int;
} else {
I2Cx->INT_MASK |= Int;
}
}
BOOL I2C_GetIntStatus(I2C0_Type* I2Cx, uint32_t Int) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_INT(Int));
if (0 != (I2Cx->INT_STATUS & Int)) {
return TRUE;
}
return FALSE;
}
void I2C_ClearInt(I2C0_Type* I2Cx, uint32_t Int) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_INT(Int));
if (Int == I2C_INT_RX_FIFO_NOT_EMPTY) {
// It can't be clear by sw but read data
}
if (Int == I2C_INT_RD_REQUEST) {
i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR);
}
if (Int == I2C_INT_TX_ABORT) {
i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR);
}
if (Int == I2C_INT_RX_DONE) {
i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR);
}
if (Int == I2C_INT_TX_DONE) {
i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR);
}
}
BOOL I2C_GetStatus(I2C0_Type* I2Cx, uint32_t Status) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_STATUS(Status));
if (0 != (I2Cx->STATUS & Status)) {
return TRUE;
}
return FALSE;
}
void I2C_ClearStatus(I2C0_Type* I2Cx, uint32_t Status) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(IS_I2C_STATUS(Status));
if (Status & I2C_STATUS_RX_FIFO_NOT_EMPTY) {
// It can't be clear by sw but read
}
if (Status & I2C_STATUS_RD_REQUEST) {
i2c_ReadClear(I2Cx->CLR_RD_REQ_b.CLEAR);
}
if (Status & I2C_STATUS_TX_ABORT) {
i2c_ReadClear(I2Cx->CLR_TX_ABRT_b.CLEAR);
}
if (Status & I2C_STATUS_RX_DONE) {
i2c_ReadClear(I2Cx->CLR_RX_DONE_b.CLEAR);
}
if (Status & I2C_STATUS_TX_DONE) {
i2c_ReadClear(I2Cx->CLR_TX_DONE_b.CLEAR);
}
}
BOOL I2C_MasterReadReq(I2C0_Type* I2Cx, uint8_t size) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
if (!I2Cx->ENABLE_b.EN || I2Cx->STATUS_b.BUSY) {
return FALSE;
}
if (I2Cx->CTRL_b.MODE == I2C_Mode_Slave) {
return FALSE;
}
if (size == 0) {
return FALSE;
}
I2Cx->WRITE_READ_CNT_b.RD_BYTE_CNT = size;
if (size != 0) {
I2C_INNER_DATA_CMD inner;
inner.INNER.DATA_CMD_b.DATA = 0;
inner.INNER.DATA_CMD_b.RD_CMD = TRUE;
inner.INNER.DATA_CMD_b.WR_CMD = FALSE;
inner.INNER.DATA_CMD_b.WR_RD_CMD = FALSE;
I2Cx->DATA_CMD = inner.INNER.DATA_CMD;
}
return TRUE;
}
uint8_t I2C_ReadFifo(I2C0_Type* I2Cx, uint8_t size, uint8_t* data) {
uint8_t count;
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(data);
if (!I2Cx->ENABLE_b.EN) {
return 0;
}
count = 0;
while (I2Cx->STATUS_b.RX_FIFO_NOT_EMPTY && count < size) {
*(data + count++) = I2Cx->DATA_CMD_b.DATA;
}
return count;
}
BOOL I2C_WriteReq(I2C0_Type* I2Cx, uint8_t size, uint8_t firstData) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
if (!I2Cx->ENABLE_b.EN || I2Cx->STATUS_b.BUSY) {
return FALSE;
}
if (size == 0) {
return FALSE;
}
I2Cx->WRITE_READ_CNT_b.WR_BYTE_CNT = size;
if (size != 0) {
I2C_INNER_DATA_CMD inner;
inner.INNER.DATA_CMD_b.DATA = firstData ;
inner.INNER.DATA_CMD_b.RD_CMD = FALSE;
inner.INNER.DATA_CMD_b.WR_CMD =
(I2Cx->CTRL_b.MODE == I2C_Mode_Slave) ? FALSE : TRUE;
inner.INNER.DATA_CMD_b.WR_RD_CMD = FALSE;
I2Cx->DATA_CMD = inner.INNER.DATA_CMD;
}
return TRUE;
}
uint8_t I2C_WriteFifo(I2C0_Type* I2Cx, uint8_t size, uint8_t* data) {
uint8_t count;
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
assert_param(data);
if (!I2Cx->ENABLE_b.EN) {
return 0;
}
count = 0;
while (I2Cx->STATUS_b.TX_FIFO_NOT_FULL && count < size) {
I2Cx->DATA_CMD_b.DATA = *(data + count++);
}
return count;
}
BOOL I2C_StopReq(I2C0_Type* I2Cx) {
assert_param(IS_I2C_ALL_PERIPH(I2Cx));
udelay(600);
return TRUE;
}