MXC_A39_20240320/SW/components/drivers/peripheral/Src/driver_i2c.c

1202 lines
31 KiB
C

/*
******************************************************************************
* @file driver_i2c.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2021
* @brief I2C module driver.
* This file provides firmware functions to manage the
* Inter-Integrated Circuit bus (I2C) peripheral
******************************************************************************
* @attention
*
* Copyright (c) 2021 FreqChip.
* All rights reserved.
******************************************************************************
*/
#include "fr30xx.h"
/************************************************************************************
* @fn i2c_IRQHandler
*
* @brief Handle I2C interrupt request.
*
* @param hi2c: I2C handle.
*/
void i2c_IRQHandler(I2C_HandleTypeDef *hi2c)
{
/* Is INT_TX_ABRT enable */
if (i2c_is_int_enable(hi2c, INT_TX_ABRT))
{
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
hi2c->b_RxBusy = false;
hi2c->b_TxBusy = false;
__I2C_DISABLE(hi2c->I2Cx);
i2c_int_disable(hi2c, INT_RX_FULL);
i2c_int_disable(hi2c, INT_TX_ABRT);
i2c_int_disable(hi2c, INT_TX_EMPTY);
}
}
/* Master */
if (hi2c->Init.I2C_Mode & I2C_MASK_MASTER)
{
/* Is INT_TX_EMPTY enabled */
if (i2c_is_int_enable(hi2c, INT_TX_EMPTY))
{
if (i2c_get_int_status(hi2c, INT_TX_EMPTY))
{
i2c_clear_int_status(hi2c, INT_TX_EMPTY);
while (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
if (hi2c->u32_TxCount < hi2c->u32_TxSize)
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++];
}
else
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++] | CMD_STOP;
hi2c->b_TxBusy = false;
i2c_int_disable(hi2c, INT_TX_EMPTY);
i2c_int_disable(hi2c, INT_TX_ABRT);
break;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
hi2c->b_TxBusy = false;
i2c_int_disable(hi2c, INT_TX_EMPTY);
i2c_int_disable(hi2c, INT_TX_ABRT);
break;
}
}
}
}
/* Is INT_RX_FULL enabled */
if (i2c_is_int_enable(hi2c, INT_RX_FULL))
{
if (i2c_get_int_status(hi2c, INT_RX_FULL))
{
i2c_clear_int_status(hi2c, INT_RX_FULL);
while (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
hi2c->p_RxData[hi2c->u32_RxCount++] = hi2c->I2Cx->DATA_CMD & 0xFF;
if (hi2c->u32_RxCount >= hi2c->u32_RxSize)
{
hi2c->b_RxBusy = false;
i2c_int_disable(hi2c, INT_RX_FULL);
}
}
while ((!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx)) && hi2c->b_TxBusy == true)
{
if (hi2c->u32_TxCount < hi2c->u32_RxSize - 1)
{
hi2c->I2Cx->DATA_CMD = CMD_READ;
hi2c->u32_TxCount++;
}
else
{
hi2c->I2Cx->DATA_CMD = CMD_READ | CMD_STOP;
hi2c->b_TxBusy = false;
break;
}
}
}
}
}
/* Slave */
else
{
/* Is INT_RD_REQ enabled */
if(i2c_is_int_enable(hi2c, INT_RD_REQ))
{
if(i2c_get_int_status(hi2c, INT_RD_REQ))
{
i2c_clear_int_status(hi2c, INT_RD_REQ);
i2c_int_disable(hi2c, INT_RD_REQ);
while(!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
if(hi2c->u32_TxCount < hi2c->u32_TxSize)
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++];
}
else
{
hi2c->b_TxBusy = false;
break;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
break;
}
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
hi2c->b_TxBusy = false;
__I2C_DISABLE(hi2c->I2Cx);
}
else
{
if(hi2c->u32_TxCount < hi2c->u32_TxSize)
{
i2c_int_enable(hi2c, INT_TX_EMPTY);
i2c_int_enable(hi2c, INT_TX_ABRT);
}
}
}
}
/* Is INT_TX_EMPTY enabled */
if (i2c_is_int_enable(hi2c, INT_TX_EMPTY))
{
if (i2c_get_int_status(hi2c, INT_TX_EMPTY))
{
i2c_clear_int_status(hi2c, INT_TX_EMPTY);
while (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
if (hi2c->u32_TxCount < hi2c->u32_TxSize)
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++];
}
else
{
hi2c->b_TxBusy = false;
i2c_int_disable(hi2c, INT_TX_EMPTY);
break;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
hi2c->b_TxBusy = false;
__I2C_DISABLE(hi2c->I2Cx);
i2c_int_disable(hi2c, INT_TX_EMPTY);
i2c_int_disable(hi2c, INT_TX_ABRT);
break;
}
}
}
}
/* Is INT_RX_FULL enabled */
if (i2c_is_int_enable(hi2c, INT_RX_FULL))
{
if (i2c_get_int_status(hi2c, INT_RX_FULL))
{
i2c_clear_int_status(hi2c, INT_RX_FULL);
while (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
hi2c->p_RxData[hi2c->u32_RxCount++] = hi2c->I2Cx->DATA_CMD & 0xFF;
if (hi2c->u32_RxCount >= hi2c->u32_RxSize)
{
hi2c->b_RxBusy = false;
i2c_int_disable(hi2c, INT_RX_FULL);
__I2C_DISABLE(hi2c->I2Cx);
break;
}
}
}
}
}
}
/************************************************************************************
* @fn i2c_init
*
* @brief Initialize the I2C according to the specified parameters in the struct_I2CInit_t
*
* @param hi2c: I2C handle.
*/
void i2c_init(I2C_HandleTypeDef *hi2c)
{
uint32_t lu32_TempValue;
__I2C_DISABLE(hi2c->I2Cx);
/* Master */
if (hi2c->Init.I2C_Mode & I2C_MASK_MASTER)
{
hi2c->I2Cx->CTRL.SLAVE_DISABLE = 1;
hi2c->I2Cx->CTRL.MASTER_MODE = 1;
hi2c->I2Cx->CTRL.SPEED = 2;
hi2c->I2Cx->TAR.ADDR_MASTER_10BIT = (hi2c->Init.I2C_Mode & I2C_MASK_10BIT) ? 1 : 0;
hi2c->I2Cx->TAR.SPECIAL = 0;
hi2c->I2Cx->TAR.DEVICE_ID = 0;
}
/* Slave */
else
{
hi2c->I2Cx->CTRL.SLAVE_DISABLE = 0;
hi2c->I2Cx->CTRL.MASTER_MODE = 0;
hi2c->I2Cx->CTRL.SPEED = 2;
hi2c->I2Cx->CTRL.ADDR_SLAVE_10BIT = (hi2c->Init.I2C_Mode & I2C_MASK_10BIT) ? 1 : 0;
hi2c->I2Cx->SAR = hi2c->Init.Slave_Address >> 1;
}
/* Rate config */
if (hi2c->Init.I2C_Mode & I2C_MASK_MASTER)
{
/* SCL_HCNT Minimum limit */
if (hi2c->Init.SCL_HCNT < 6)
{
hi2c->I2Cx->FS_SCL_HCNT = 6;
}
else
{
hi2c->I2Cx->FS_SCL_HCNT = hi2c->Init.SCL_HCNT;
}
/* SCL_LCNT Minimum limit */
if (hi2c->Init.SCL_LCNT < 8)
{
hi2c->I2Cx->FS_SCL_LCNT = 8;
}
else
{
hi2c->I2Cx->FS_SCL_LCNT = hi2c->Init.SCL_LCNT;
}
lu32_TempValue = hi2c->Init.SCL_LCNT / 2;
if (lu32_TempValue > 0xFF)
{
hi2c->I2Cx->SDA_SETUP = 0xFF;
hi2c->I2Cx->SDA_HOLD.SDA_TX_HOLD = hi2c->Init.SCL_LCNT - 0xFF;
/* Maximum limit */
if (hi2c->Init.SCL_LCNT - 0xFF > 0xFFFF)
{
hi2c->I2Cx->SDA_HOLD.SDA_TX_HOLD = 0xFFFF;
}
}
else
{
hi2c->I2Cx->SDA_SETUP = lu32_TempValue;
/* Minimum limit */
if (lu32_TempValue < 8)
{
hi2c->I2Cx->SDA_SETUP = 8;
}
hi2c->I2Cx->SDA_HOLD.SDA_TX_HOLD = lu32_TempValue;
/* Minimum limit */
if (lu32_TempValue < 5)
{
hi2c->I2Cx->SDA_HOLD.SDA_TX_HOLD = 1;
}
}
}
else
{
hi2c->I2Cx->FS_SCL_HCNT = 6;
hi2c->I2Cx->FS_SCL_LCNT = 8;
hi2c->I2Cx->SDA_SETUP = 8;
hi2c->I2Cx->SDA_HOLD.SDA_TX_HOLD = 1;
}
/* Rate config end */
/* Default configuration */
hi2c->I2Cx->CTRL.STOP_DET_IF_MASTER_ACTIVE = 1;
hi2c->I2Cx->CTRL.STOP_DET_IF_ADDR_ESSED = 1;
hi2c->I2Cx->CTRL.RX_FIFO_FULL_HLD_CTRL = 1;
hi2c->I2Cx->CTRL.TX_EMPTY_CTRL = 1;
hi2c->I2Cx->CTRL.RESTART_EN = 1;
/* nonblocking */
hi2c->I2Cx->ENABLE.TX_CMD_BLOCK = 0;
/* Disable all interrupt */
hi2c->I2Cx->INT_MASK = 0;
}
/************************************************************************************
* @fn i2c_master_transmit
*
* @brief master send an amount of data in blocking mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_master_transmit(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
while (fu32_Size - 1)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = *fp_Data++;
fu32_Size--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = *fp_Data++ | CMD_STOP;
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
while (__I2C_IS_BUSY(hi2c->I2Cx));
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
return true;
}
/************************************************************************************
* @fn i2c_master_receive
*
* @brief master receive an amount of data in blocking mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_master_receive(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
uint32_t lu32_RxCount = fu32_Size;
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
while (fu32_Size - 1)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = CMD_READ;
fu32_Size--;
}
while (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = CMD_READ | CMD_STOP;
while (lu32_RxCount)
{
if (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
while(__I2C_IS_BUSY(hi2c->I2Cx));
return true;
}
/************************************************************************************
* @fn i2c_master_transmit_IT
*
* @brief master send an amount of data in interrupt mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_master_transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hi2c->b_TxBusy) return false;
if (hi2c->b_RxBusy) return false;
while(__I2C_IS_BUSY(hi2c->I2Cx));
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_TxFIFO_THRESHOLD_LEVEL(hi2c->I2Cx, 16);
__I2C_ENABLE(hi2c->I2Cx);
hi2c->u32_TxSize = fu32_Size - 1;
hi2c->u32_TxCount = 0;
hi2c->p_TxData = fp_Data;
hi2c->b_TxBusy = true;
i2c_clear_int_status(hi2c, INT_TX_ABRT);
i2c_clear_int_status(hi2c, INT_TX_EMPTY);
while (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
if (hi2c->u32_TxCount < hi2c->u32_TxSize)
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++];
}
else
{
hi2c->I2Cx->DATA_CMD = hi2c->p_TxData[hi2c->u32_TxCount++] | CMD_STOP;
hi2c->b_TxBusy = false;
return true;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
hi2c->b_TxBusy = false;
return false;
}
}
while(__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
/* DevAddress NACK */
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
hi2c->b_TxBusy = false;
return false;
}
i2c_int_enable(hi2c, INT_TX_EMPTY);
i2c_int_enable(hi2c, INT_TX_ABRT);
return true;
}
/************************************************************************************
* @fn i2c_master_receive_IT
*
* @brief master receive an amount of data in interrupt mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_master_receive_IT(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hi2c->b_TxBusy) return false;
if (hi2c->b_RxBusy) return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_RxFIFO_THRESHOLD_LEVEL(hi2c->I2Cx, 0);
__I2C_ENABLE(hi2c->I2Cx);
hi2c->u32_RxSize = fu32_Size;
hi2c->u32_RxCount = 0;
hi2c->u32_TxCount = 0;
hi2c->p_RxData = fp_Data;
hi2c->b_RxBusy = true;
hi2c->b_TxBusy = true;
i2c_clear_int_status(hi2c, INT_TX_ABRT);
i2c_clear_int_status(hi2c, INT_RX_FULL);
while (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
if (hi2c->u32_TxCount < hi2c->u32_RxSize - 1)
{
hi2c->I2Cx->DATA_CMD = CMD_READ;
hi2c->u32_TxCount++;
}
else
{
hi2c->I2Cx->DATA_CMD = CMD_READ | CMD_STOP;
hi2c->b_TxBusy = false;
break;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
hi2c->b_RxBusy = false;
hi2c->b_TxBusy = false;
return false;
}
}
i2c_int_enable(hi2c, INT_RX_FULL);
return true;
}
/************************************************************************************
* @fn i2c_slave_transmit
*
* @brief slave send an amount of data in blocking mode..
*
* @param hi2c: I2C handle.
*/
bool i2c_slave_transmit(I2C_HandleTypeDef *hi2c, uint8_t *fp_Data, uint32_t fu32_Size)
{
__I2C_ENABLE(hi2c->I2Cx);
if (fu32_Size == 0)
return false;
while(!(i2c_get_int_status(hi2c, INT_RD_REQ)));
i2c_clear_int_status(hi2c, INT_RD_REQ);
while (fu32_Size)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = *fp_Data++;
fu32_Size--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
while(__I2C_IS_BUSY(hi2c->I2Cx));
__I2C_DISABLE(hi2c->I2Cx);
return true;
}
/************************************************************************************
* @fn i2c_slave_receive
*
* @brief slave receive an amount of data in blocking mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_slave_receive(I2C_HandleTypeDef *hi2c, uint8_t *fp_Data, uint32_t fu32_Size)
{
__I2C_ENABLE(hi2c->I2Cx);
while (fu32_Size)
{
if (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
fu32_Size--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
__I2C_DISABLE(hi2c->I2Cx);
return true;
}
/************************************************************************************
* @fn i2c_slave_transmit_IT
*
* @brief slave send an amount of data in interrupt mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_slave_transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hi2c->b_TxBusy) return false;
if (hi2c->b_RxBusy) return false;
__I2C_TxFIFO_THRESHOLD_LEVEL(hi2c->I2Cx, 16);
while(__I2C_IS_BUSY(hi2c->I2Cx));
__I2C_ENABLE(hi2c->I2Cx);
hi2c->u32_TxSize = fu32_Size;
hi2c->u32_TxCount = 0;
hi2c->p_TxData = fp_Data;
hi2c->b_TxBusy = true;
i2c_clear_int_status(hi2c, INT_TX_ABRT);
i2c_clear_int_status(hi2c, INT_TX_EMPTY);
i2c_clear_int_status(hi2c, INT_RD_REQ);
i2c_int_enable(hi2c,INT_RD_REQ);
return true;
}
/************************************************************************************
* @fn i2c_slave_receive_IT
*
* @brief slave receive an amount of data in interrupt mode.
*
* @param hi2c: I2C handle.
*/
bool i2c_slave_receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0) return false;
if (hi2c->b_TxBusy) return false;
if (hi2c->b_RxBusy) return false;
while(__I2C_IS_BUSY(hi2c->I2Cx));
i2c_clear_int_status(hi2c, INT_TX_ABRT);
i2c_clear_int_status(hi2c, INT_RX_FULL);
__I2C_ENABLE(hi2c->I2Cx);
__I2C_RxFIFO_THRESHOLD_LEVEL(hi2c->I2Cx, 0);
hi2c->u32_RxSize = fu32_Size;
hi2c->u32_RxCount = 0;
hi2c->p_RxData = fp_Data;
hi2c->b_RxBusy = true;
i2c_int_enable(hi2c, INT_RX_FULL);
return true;
}
/************************************************************************************
* @fn i2c_memory_write
*
* @brief i2c memory write.
*/
bool i2c_memory_write(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint16_t fu16_MemAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
//hi2c->I2Cx->DATA_CMD = (fu16_MemAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu16_MemAddress & 0xFF;
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
/* DevAddress NACK */
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
//printf("ack:%x %x\r\n",fu16_DevAddress,(fu16_DevAddress>>1));
while (fu32_Size - 1)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = *fp_Data++;
fu32_Size--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = *fp_Data++ | CMD_STOP;
while(__I2C_IS_BUSY(hi2c->I2Cx));
while(i2c_memory_is_busy(hi2c, fu16_DevAddress));
return true;
}
/************************************************************************************
* @fn i2c_sensor_write
*
* @brief i2c sensor write, fu8_AddressLength: The value can be 8, 16, or 32.
*/
bool i2c_sensor_write(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint32_t fu32_RegAddress, uint8_t fu8_AddressLength, uint8_t *fp_Data, uint32_t fu32_Size)
{
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
if(fu8_AddressLength == 8)
{
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
else if(fu8_AddressLength == 16)
{
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
else
{
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 24) & 0xFF;
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 16) & 0xFF;
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
while (fu32_Size - 1)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = *fp_Data++;
fu32_Size--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = *fp_Data++ | CMD_STOP;
while(__I2C_IS_BUSY(hi2c->I2Cx));
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
while(i2c_memory_is_busy(hi2c, fu16_DevAddress));
return true;
}
/************************************************************************************
* @fn i2c_memory_read
*
* @brief i2c memory read.
*/
bool i2c_memory_read(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint16_t fu16_MemAddress, uint8_t *fp_Data, uint32_t fu32_Size)
{
uint32_t lu32_RxCount = fu32_Size;
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
// hi2c->I2Cx->DATA_CMD = (fu16_MemAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu16_MemAddress & 0xFF;
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
/* DevAddress NACK */
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
if (fu32_Size > 1)
{
hi2c->I2Cx->DATA_CMD = CMD_RESTART | CMD_READ;
while (fu32_Size - 2)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = CMD_READ;
fu32_Size--;
}
while (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = CMD_READ | CMD_STOP;
}
else
{
hi2c->I2Cx->DATA_CMD = CMD_RESTART | CMD_READ | CMD_STOP;
}
while (lu32_RxCount)
{
if (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
}
while(__I2C_IS_BUSY(hi2c->I2Cx));
return true;
}
/************************************************************************************
* @fn i2c_sensor_read
*
* @brief i2c sensor read, fu8_AddressLength: The value can be 8, 16, or 32.
*/
bool i2c_sensor_read(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress, uint32_t fu32_RegAddress, uint8_t fu8_AddressLength, uint8_t *fp_Data, uint32_t fu32_Size)
{
uint32_t lu32_RxCount = fu32_Size;
if (fu32_Size == 0)
return false;
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
if(fu8_AddressLength == 8)
{
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
else if(fu8_AddressLength == 16)
{
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
else
{
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 24) & 0xFF;
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 16) & 0xFF;
hi2c->I2Cx->DATA_CMD = (fu32_RegAddress >> 8) & 0xFF;
hi2c->I2Cx->DATA_CMD = fu32_RegAddress & 0xFF;
}
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
if (fu32_Size > 1)
{
hi2c->I2Cx->DATA_CMD = CMD_RESTART | CMD_READ;
while (fu32_Size - 2)
{
if (!__I2C_IS_TxFIFO_FULL(hi2c->I2Cx))
{
hi2c->I2Cx->DATA_CMD = CMD_READ;
fu32_Size--;
}
while (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
}
/* Last byte with stop */
while (__I2C_IS_TxFIFO_FULL(hi2c->I2Cx));
hi2c->I2Cx->DATA_CMD = CMD_READ | CMD_STOP;
}
else
{
hi2c->I2Cx->DATA_CMD = CMD_RESTART | CMD_READ | CMD_STOP;
}
while(__I2C_IS_BUSY(hi2c->I2Cx));
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return false;
}
while (lu32_RxCount)
{
if (!__I2C_IS_RxFIFO_EMPTY(hi2c->I2Cx))
{
*fp_Data++ = hi2c->I2Cx->DATA_CMD & 0xFF;
lu32_RxCount--;
}
}
return true;
}
/************************************************************************************
* @fn i2c_memory_is_busy
*
* @brief i2c memory is busy.
*/
bool i2c_memory_is_busy(I2C_HandleTypeDef *hi2c, uint16_t fu16_DevAddress)
{
__I2C_DISABLE(hi2c->I2Cx);
hi2c->I2Cx->TAR.TAR = fu16_DevAddress >> 1;
__I2C_ENABLE(hi2c->I2Cx);
hi2c->I2Cx->DATA_CMD = 0x00;
hi2c->I2Cx->DATA_CMD = 0x00 | CMD_STOP;
while (!__I2C_IS_TxFIFO_EMPTY(hi2c->I2Cx));
/* DevAddress NACK */
if (i2c_get_int_status(hi2c, INT_TX_ABRT))
{
i2c_clear_int_status(hi2c, INT_TX_ABRT);
__I2C_DISABLE(hi2c->I2Cx);
return true;
}
else
{
return false;
}
}
/************************************************************************************
* @fn i2c_int_enable
*
* @brief I2C interrupt enable.
*
* @param hi2c: I2C handle.
* fe_INT_Index: interrupt index.
*/
void i2c_int_enable(I2C_HandleTypeDef *hi2c, enum_INT_Index_t fe_INT_Index)
{
hi2c->I2Cx->INT_MASK |= fe_INT_Index;
}
/************************************************************************************
* @fn i2c_int_disable
*
* @brief I2C interrupt disable.
*
* @param hi2c: I2C handle.
* fe_INT_Index: interrupt index.
*/
void i2c_int_disable(I2C_HandleTypeDef *hi2c, enum_INT_Index_t fe_INT_Index)
{
hi2c->I2Cx->INT_MASK &= ~fe_INT_Index;
}
/************************************************************************************
* @fn i2c_is_int_enable
*
* @brief Is I2C interrupt enable.
*
* @param hi2c: I2C handle.
* fe_INT_Index: interrupt index.
*/
bool i2c_is_int_enable(I2C_HandleTypeDef *hi2c, enum_INT_Index_t fe_INT_Index)
{
return (hi2c->I2Cx->INT_MASK & fe_INT_Index) ? true : false;
}
/************************************************************************************
* @fn i2c_get_int_status
*
* @brief I2C interrupt Status.
*
* @param hi2c: I2C handle.
* fe_INT_Index: interrupt index.
*/
bool i2c_get_int_status(I2C_HandleTypeDef *hi2c, enum_INT_Index_t fe_INT_Index)
{
bool lb_Status = (hi2c->I2Cx->RAW_INT_STAT & fe_INT_Index) ? true : false;
return lb_Status;
}
/************************************************************************************
* @fn i2c_clear_int_status
*
* @brief I2C interrupt status clear.
*
* @param hi2c: I2C handle.
* fe_INT_Index: interrupt index.
*/
void i2c_clear_int_status(I2C_HandleTypeDef *hi2c, enum_INT_Index_t fe_INT_Index)
{
volatile uint32_t lu32_Temp;
switch (fe_INT_Index)
{
case INT_RX_UNDER: lu32_Temp = hi2c->I2Cx->CLR_RX_UNDER; break;
case INT_RX_OVER: lu32_Temp = hi2c->I2Cx->CLR_RX_OVER; break;
case INT_TX_OVER: lu32_Temp = hi2c->I2Cx->CLR_TX_OVER; break;
case INT_RD_REQ: lu32_Temp = hi2c->I2Cx->CLR_RD_REQ; break;
case INT_TX_ABRT: lu32_Temp = hi2c->I2Cx->CLR_TX_ABRT; break;
case INT_RX_DONE: lu32_Temp = hi2c->I2Cx->CLR_RX_DONE; break;
case INT_ACTIVITY: lu32_Temp = hi2c->I2Cx->CLR_ACTIVITY; break;
case INT_STOP_DET: lu32_Temp = hi2c->I2Cx->CLR_STOP_DET; break;
case INT_START_DET: lu32_Temp = hi2c->I2Cx->CLR_START_DET; break;
case INT_RESTART_DET: lu32_Temp = hi2c->I2Cx->CLR_RESTART_DET; break;
case INT_SCL_STUCK_AT_LOW: lu32_Temp = hi2c->I2Cx->CLR_SCL_STUCK_DET; break;
default: break;
}
}