chg-stn-motherboard-ti-mcu/Core/Source/ivec_mcal_i2c.c

400 lines
13 KiB
C

/**
* @file ivec_mcal_i2c.c
* @author Akshat Dabas (akshat@vecmocon.com)
* @brief This source file contains API and Private members for I2C Functionality
* @version 0.1.0
* @date 2024-Mar-27
*
* @copyright Copyright (c) 2024
*
*/
#include "../Core/Include/ivec_mcal_i2c.h"
/*REQUIRED I2C CONFIGS*/
/*=======================================================================================PRIVATE_MEMBERS======================================================================================*/
static volatile bool b_I2C0_INIT_FLAG=0;
static volatile bool b_I2C1_INIT_FLAG=0;
static volatile uint8_t u8RxBuffer0[I2C_PACKETSIZE];
static volatile uint8_t u8RxBuffer1[I2C_PACKETSIZE];
static volatile int i32bufferIdx0=0;
static volatile int i32bufferIdx1=0;
volatile int i32TempCount=0;
volatile int global_len;
static const DL_I2C_ClockConfig gI2C_0ClockConfig = {
.clockSel = DL_I2C_CLOCK_BUSCLK,
.divideRatio = DL_I2C_CLOCK_DIVIDE_1,
};
static volatile uint8_t u8GlobalPacket[8];
static volatile xI2cControllerStatus_t xStatus_i2c = I2C_STATUS_IDLE;
/*____________________________________________________________________________________________________________________________________________________________________________________________*/
/*=============================================================================================================================================================================================
PRIVATE_DECLARATIONS
==============================================================================================================================================================================================*/
void _prv_vI2C_Callback()
{
switch (DL_I2C_getPendingInterrupt(I2C0))
{
case DL_I2C_IIDX_CONTROLLER_RX_DONE:
xStatus_i2c = I2C_STATUS_RX_COMPLETE;
break;
case DL_I2C_IIDX_CONTROLLER_TX_DONE:
DL_I2C_disableInterrupt(I2C0, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
xStatus_i2c = I2C_STATUS_TX_COMPLETE;
break;
case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
xStatus_i2c = I2C_STATUS_RX_INPROGRESS;
/* Receive all bytes from target */
while (DL_I2C_isControllerRXFIFOEmpty(I2C0) != true) {
if (i32bufferIdx0 <global_len)
{
u8RxBuffer0[i32bufferIdx0++] = DL_I2C_receiveControllerData(I2C0);
}
else
{
/* Ignore and remove from FIFO if the buffer is full */
DL_I2C_receiveControllerData(I2C0);
}
}
break;
case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
xStatus_i2c = I2C_STATUS_TX_INPROGRESS;
/* Fill TX FIFO with next bytes to send */
if (i32TempCount < global_len)
{
i32TempCount += DL_I2C_fillControllerTXFIFO(I2C0, &u8GlobalPacket[i32TempCount], global_len - i32TempCount);
}
break;
case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
__asm("nop");
break;
case DL_I2C_IIDX_CONTROLLER_NACK: /* NACK interrupt if I2C Target is disconnected */
if ((xStatus_i2c == I2C_STATUS_RX_STARTED) ||(xStatus_i2c == I2C_STATUS_TX_STARTED))
{
xStatus_i2c = I2C_STATUS_ERROR;
}
break;
default:
break;
}
switch (DL_I2C_getPendingInterrupt(I2C1))
{
case DL_I2C_IIDX_CONTROLLER_RX_DONE:
xStatus_i2c = I2C_STATUS_RX_COMPLETE;
break;
case DL_I2C_IIDX_CONTROLLER_TX_DONE:
DL_I2C_disableInterrupt(I2C1, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
xStatus_i2c = I2C_STATUS_TX_COMPLETE;
break;
case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
xStatus_i2c = I2C_STATUS_RX_INPROGRESS;
/* Receive all bytes from target */
while (DL_I2C_isControllerRXFIFOEmpty(I2C1) != true) {
if (i32bufferIdx0 <global_len)
{
u8RxBuffer0[i32bufferIdx0++] = DL_I2C_receiveControllerData(I2C1);
}
else
{
/* Ignore and remove from FIFO if the buffer is full */
DL_I2C_receiveControllerData(I2C1);
}
}
break;
case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
xStatus_i2c = I2C_STATUS_TX_INPROGRESS;
/* Fill TX FIFO with next bytes to send */
if (i32TempCount < global_len)
{
i32TempCount += DL_I2C_fillControllerTXFIFO(I2C1, &u8GlobalPacket[i32TempCount], global_len - i32TempCount);
}
break;
case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
__asm("nop");
break;
case DL_I2C_IIDX_CONTROLLER_NACK: /* NACK interrupt if I2C Target is disconnected */
if ((xStatus_i2c == I2C_STATUS_RX_STARTED) ||(xStatus_i2c == I2C_STATUS_TX_STARTED))
{
xStatus_i2c = I2C_STATUS_ERROR;
}
break;
default:
break;
}
}
void I2C0_IRQHandler()
{
_prv_vI2C_Callback();
}
void I2C1_IRQHandler()
{
_prv_vI2C_Callback();
}
/*____________________________________________________________________________________________________________________________________________________________________________________________*/
/*=============================================================================================================================================================================================
API
==============================================================================================================================================================================================*/
/**
* @brief Function to Init I2C Peripheral
*
* @param I2C_inst Pointer to I2C config registers
* @param baud enum to set I2C Baud rate
* @return xCoreStatus_t
*/
xCoreStatus_t xMCAL_I2C_init(I2C_Regs *I2C_inst, xI2C_baud_t baud)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
DL_I2C_setClockConfig(I2C_inst, (DL_I2C_ClockConfig *) &gI2C_0ClockConfig);
DL_I2C_disableAnalogGlitchFilter(I2C_inst);
/* Configure Controller Mode */
DL_I2C_resetControllerTransfer(I2C_inst);
if(baud==BAUD_400Khz)
{
/* Set frequency to 400000 Hz*/
DL_I2C_setTimerPeriod(I2C_inst, 9);
}
else if(baud==BAUD_100Khz)
{
/* Set frequency to 100000 Hz*/
DL_I2C_setTimerPeriod(I2C_inst, 31);
}
DL_I2C_setControllerTXFIFOThreshold(I2C_inst, DL_I2C_TX_FIFO_LEVEL_EMPTY);
DL_I2C_setControllerRXFIFOThreshold(I2C_inst, DL_I2C_RX_FIFO_LEVEL_BYTES_1);
DL_I2C_enableControllerClockStretching(I2C_inst);
/* Configure Interrupts */
DL_I2C_enableInterrupt(I2C_inst,
DL_I2C_INTERRUPT_CONTROLLER_ARBITRATION_LOST |
DL_I2C_INTERRUPT_CONTROLLER_NACK |
DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER |
DL_I2C_INTERRUPT_CONTROLLER_RX_DONE |
DL_I2C_INTERRUPT_CONTROLLER_TX_DONE);
/* Enable module */
DL_I2C_enableController(I2C_inst);
if(I2C_inst==I2C0)
{
NVIC_EnableIRQ(I2C0_INT_IRQn);
b_I2C0_INIT_FLAG=1;
}
if(I2C_inst==I2C1)
{
NVIC_EnableIRQ(I2C1_INT_IRQn);
b_I2C1_INIT_FLAG=1;
}
return STATUS_SUCCESS;
}
/**
* @brief Function to write Packet from controller to Target device
*
* @param I2C_inst Pointer to I2C config Register
* @param u8addr I2C target device address
* @param u8TxPacket Data to be written to target device
* @param len Number of bytes to be written to target device
* @return xCoreStatus_t
*/
xCoreStatus_t xMCU_i2cWriteMcal(I2C_Regs *I2C_inst,uint8_t u8addr ,uint8_t *u8TxPacket, int len)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
global_len=len;
if(len==1)
{
u8GlobalPacket[0]=*u8TxPacket;
global_len=1;
}
else
{
for(uint8_t j=0;j<len;j++)
{
u8GlobalPacket[j]=u8TxPacket[j];
}
}
i32TempCount = DL_I2C_fillControllerTXFIFO(I2C_inst, &u8GlobalPacket[0], global_len);
/* Enable TXFIFO trigger interrupt if there are more bytes to send */
if (i32TempCount < global_len)
{
DL_I2C_enableInterrupt(I2C_inst, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
}
else
{
DL_I2C_disableInterrupt(I2C_inst, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
}
/*
* Send the packet to the controller.
* This function will send Start + Stop automatically.
*
*/
xStatus_i2c = I2C_STATUS_TX_STARTED;
while (!(DL_I2C_getControllerStatus(I2C_inst) & DL_I2C_CONTROLLER_STATUS_IDLE));
DL_I2C_startControllerTransfer(I2C_inst, u8addr , DL_I2C_CONTROLLER_DIRECTION_TX, global_len);
/* Wait until the Controller sends all bytes */
while ((xStatus_i2c != I2C_STATUS_TX_COMPLETE) && (xStatus_i2c != I2C_STATUS_ERROR));
while (DL_I2C_getControllerStatus(I2C_inst) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
while (!(DL_I2C_getControllerStatus(I2C_inst) & DL_I2C_CONTROLLER_STATUS_IDLE));
memset((uint8_t *)&u8GlobalPacket[0], 0, sizeof(u8GlobalPacket));
i32TempCount=0;
global_len=0;
return STATUS_SUCCESS;
}
/**
* @brief Function to Read Data from Target device
*
* @param I2C_inst Pointer to I2C config Register
* @param u8addr I2C target device address
* @param len Number of bytes to Read from target device
* @return xCoreStatus_t
*/
xCoreStatus_t xMCU_i2cReadMcal(I2C_Regs *I2C_inst, uint8_t u8addr, int len)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
global_len=len;
xStatus_i2c = I2C_STATUS_RX_STARTED;
DL_I2C_startControllerTransfer(I2C_inst, u8addr, DL_I2C_CONTROLLER_DIRECTION_RX, len);
/* Wait for all bytes to be received in interrupt */
while (xStatus_i2c != I2C_STATUS_RX_COMPLETE);
while (DL_I2C_getControllerStatus(I2C_inst) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
return STATUS_SUCCESS;
}
/**
* @brief Function to ping I2C target device and check if its ready for communication
*
* @param I2C_inst pointer to I2C config Register
* @param u8addr I2C Target Address
* @return xCoreStatus_t
*/
xCoreStatus_t xMCU_i2cDevReadyMcal(I2C_Regs *I2C_inst,uint8_t u8addr)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
uint8_t u8DummyData=0;
xMCU_i2cWriteMcal(I2C_inst, u8addr, &u8DummyData, 1);
if(xStatus_i2c!=I2C_STATUS_TX_COMPLETE)
{
return STATUS_ERROR;
}
else
{
return STATUS_SUCCESS;
}
}
/**
* @brief Function to store read data from target into user array from static buffer in IRQ Handler
*
* @param I2C_inst pointer to I2C config Register
* @param u8RxData array to store read data from target
* @param len number of bytes to be read from buffer
* @return xCoreStatus_t
*/
xCoreStatus_t xMcal_I2C_getData(I2C_Regs *I2C_inst, uint8_t *u8RxData, uint8_t len)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
if(I2C_inst==I2C0)
{
for(uint8_t j=0;j<len;j++)
{
u8RxData[j]=u8RxBuffer0[j];
}
i32bufferIdx0=0;
memset((uint8_t *)&u8RxBuffer0[0], 0, sizeof(u8RxBuffer0));
}
else if(I2C_inst==I2C1)
{
for(uint8_t j=0;j<len;j++)
{
u8RxData[j]=u8RxBuffer1[j];
}
i32bufferIdx1=0;
memset((uint8_t *)&u8RxBuffer1[0], 0, sizeof(u8RxBuffer1));
}
return STATUS_SUCCESS;
}
xCoreStatus_t xMCAL_I2C_deinit(I2C_Regs *I2C_inst)
{
assert(!(b_I2C0_INIT_FLAG == 1 && b_I2C1_INIT_FLAG == 1));
assert(I2C_inst == I2C0 || I2C_inst == I2C1);
if(I2C_inst==I2C0)
{
NVIC_DisableIRQ(I2C0_INT_IRQn);
DL_I2C_disablePower(I2C_inst);
b_I2C0_INIT_FLAG=0;
}
else
{
NVIC_DisableIRQ(I2C1_INT_IRQn);
DL_I2C_disablePower(I2C_inst);
b_I2C1_INIT_FLAG=0;
}
return STATUS_SUCCESS;
}
/*____________________________________________________________________________________________________________________________________________________________________________________________*/