400 lines
13 KiB
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 IVEC_I2cControllerStatus_e xStatus_i2c = IVEC_I2C_STATUS_IDLE;
|
|
/*____________________________________________________________________________________________________________________________________________________________________________________________*/
|
|
|
|
|
|
/*=============================================================================================================================================================================================
|
|
PRIVATE_DECLARATIONS
|
|
==============================================================================================================================================================================================*/
|
|
|
|
void _prv_vI2C_Callback()
|
|
{
|
|
switch (DL_I2C_getPendingInterrupt(I2C0))
|
|
{
|
|
case DL_I2C_IIDX_CONTROLLER_RX_DONE:
|
|
xStatus_i2c = IVEC_I2C_STATUS_RX_COMPLETE;
|
|
break;
|
|
case DL_I2C_IIDX_CONTROLLER_TX_DONE:
|
|
DL_I2C_disableInterrupt(I2C0, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
|
|
xStatus_i2c = IVEC_I2C_STATUS_TX_COMPLETE;
|
|
break;
|
|
case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
|
|
xStatus_i2c = IVEC_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 = IVEC_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 == IVEC_I2C_STATUS_RX_STARTED) ||(xStatus_i2c == IVEC_I2C_STATUS_TX_STARTED))
|
|
{
|
|
xStatus_i2c = IVEC_I2C_STATUS_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (DL_I2C_getPendingInterrupt(I2C1))
|
|
{
|
|
case DL_I2C_IIDX_CONTROLLER_RX_DONE:
|
|
xStatus_i2c = IVEC_I2C_STATUS_RX_COMPLETE;
|
|
break;
|
|
case DL_I2C_IIDX_CONTROLLER_TX_DONE:
|
|
DL_I2C_disableInterrupt(I2C1, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
|
|
xStatus_i2c = IVEC_I2C_STATUS_TX_COMPLETE;
|
|
break;
|
|
case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
|
|
xStatus_i2c = IVEC_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 = IVEC_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 == IVEC_I2C_STATUS_RX_STARTED) ||(xStatus_i2c == IVEC_I2C_STATUS_TX_STARTED))
|
|
{
|
|
xStatus_i2c = IVEC_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
|
|
*/
|
|
IVEC_CoreStatus_e xMCAL_I2C_init(I2C_Regs *I2C_inst, IVEC_I2cBaud_e 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==IVEC_I2C_BAUD_400KHZ)
|
|
{
|
|
/* Set frequency to 400000 Hz*/
|
|
DL_I2C_setTimerPeriod(I2C_inst, 9);
|
|
}
|
|
else if(baud==IVEC_I2C_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 IVEC_CORE_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
|
|
*/
|
|
IVEC_CoreStatus_e 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 = IVEC_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 != IVEC_I2C_STATUS_TX_COMPLETE) && (xStatus_i2c != IVEC_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 IVEC_CORE_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
|
|
*/
|
|
IVEC_CoreStatus_e 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 = IVEC_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 != IVEC_I2C_STATUS_RX_COMPLETE);
|
|
|
|
while (DL_I2C_getControllerStatus(I2C_inst) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
|
|
|
|
return IVEC_CORE_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
|
|
*/
|
|
IVEC_CoreStatus_e 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!=IVEC_I2C_STATUS_TX_COMPLETE)
|
|
{
|
|
return IVEC_CORE_STATUS_ERROR;
|
|
}
|
|
else
|
|
{
|
|
return IVEC_CORE_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
|
|
*/
|
|
IVEC_CoreStatus_e 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 IVEC_CORE_STATUS_SUCCESS;
|
|
}
|
|
|
|
IVEC_CoreStatus_e 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 IVEC_CORE_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
/*____________________________________________________________________________________________________________________________________________________________________________________________*/
|
|
|
|
|