/** * @file module_driver_fciic.c * @author Flagchip * @brief FCIIC driver type definition and API * @version 2.0.0 * @date 2023-09-18 * * SDK Version: 2.6.0 * * @copyright Copyright (c) 2020-2024 Flagchip Semiconductors Co., Ltd. * */ /* ******************************************************************************** * Revision History: * * Version Date Initials CR# Descriptions * --------- ---------- ------------ ---------- --------------- * 0.1.0 2022/12/31 qxw0052 N/A First version for FC7300 * 0.2.0 2023/02/14 qxw0052 N/A Fix MISRA issues * 0.2.1 2023/09/18 qxw0100 N/A modify clock duty to 1:2 * x.x.x 2024/xx/xx qxw0100 N/A Refactor driver * 2.3.5 2025/06/25 qxw0120 N/A Update subaddress mode ******************************************************************************** */ #include "module_driver_fciic.h" #if FCIIC_INSTANCE_COUNT > 0U #include "module_driver_dma.h" #include "stdarg.h" #include "stdio.h" #include "string.h" #include "stdlib.h" #ifndef FCIIC_DEV_ERROR_REPORT #define FCIIC_DEV_ERROR_REPORT STD_OFF #endif #if FCIIC_DEV_ERROR_REPORT == STD_ON #define FCIIC_ReportDevError(func, error) ReportDevError(FCIIC_MODULE_ID, func, error) #endif /********* Local variable ************/ static FCIIC_Type *const s_aFCIIC_InstanceTable[FCIIC_INSTANCE_COUNT] = FCIIC_BASE_PTRS; /* ################################################################################## */ /* ################################ Global Functions ################################ */ /** * @brief Checks if the I2C bus is busy for the master. * * @param[in] pFciicMasterHandle Pointer to the FCIIC Master handle. * * @return FCIIC_StatusType Indicates whether the bus is busy or not. * @retval FCIIC_SUCCESS Bus is not busy. * @retval FCIIC_BUSY Bus is busy. */ FCIIC_StatusType FCIIC_MasterCheckForBusyBus(FCIIC_MasterHandleType *const pFciicMasterHandle) { FCIIC_StatusType ret = FCIIC_SUCCESS; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint32_t status = FCIIC_HWA_MasterGetStatusFlags(pFciic); if (0U != (status & (uint32_t)FCIIC_MSR_BBF)) { ret = FCIIC_BUSY; } return ret; } /** * @brief Initializes a default configuration for the I2C master. * * This function sets up the default configuration parameters for the I2C master. * * @param[out] pMasterConfig Pointer to the structure where the default configuration will be stored. * * The following configurations are set: * - bEnableMaster: Enables the master functionality. * - bDebugEnable: Disables debug mode by default. * - ePinConfig: Sets the pin configuration to open-drain. * - u32BaudRate: Sets the baud rate to 100 kHz. * - u32BusIdleTimeout: Disables the bus idle timeout. * - u32PinLowTimeout: Disables the pin low timeout. * - u8SdaGlitchFilterWidth: Disables the SDA glitch filter. * - u8SclGlitchFilterWidth: Disables the SCL glitch filter. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. */ void FCIIC_MasterGetDefaultConfig(FCIIC_MasterConfigType *const pMasterConfig) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pMasterConfig == NULL) { FCIIC_ReportDevError(FCIIC_MASTERGETDEFAULTCONFIG_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif pMasterConfig->bEnableMaster = true; pMasterConfig->bDebugEnable = false; pMasterConfig->ePinConfig = FCIIC_OPENDRAIN; pMasterConfig->u32BaudRate = 100000U; pMasterConfig->u32BusIdleTimeout = 0U; /* Set to 0 to disable the function */ pMasterConfig->u32PinLowTimeout = 0U; /* Set to 0 to disable the function */ pMasterConfig->u8SdaGlitchFilterWidth = 0U; /* Set to 0 to disable the function */ pMasterConfig->u8SclGlitchFilterWidth = 0U; /* Set to 0 to disable the function */ #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Sets the baud rate for the I2C master. * * This function calculates and sets the baud rate for the I2C master based on the given source clock frequency and desired baud rate. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] sourceClock_Hz The source clock frequency in Hz. * @param[in] pMasterConfig Pointer to the master configuration structure. * * The function performs the following steps: * - Calculates the optimal values for CLKHI, CLKLO, and PRESCALE to achieve the closest possible baud rate to the desired one. * - Configures the MCCR and MCFGR1 registers with the calculated values. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterSetBaudRate(FCIIC_MasterHandleType *const pFciicMasterHandle, uint32_t sourceClock_Hz, const FCIIC_MasterConfigType *const pMasterConfig) { /* SCL_LATENCY is defined as ROUNDDOWN ((2 + FILTSCL + SCL_RISETIME) / (2 ^ PRESCALE)) */ /* CLKLO: Minimum value is 0x3 */ /* CLKHI: Minimum value is 0x1 */ /* SCL clock period: (CLKHI + CLKLO + 2 + SCL_LATENCY) / (2 ^ PRESCALE) / function clock period */ #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERSETBAUDRATE_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MODULE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint32_t u32TempMcfgr1, u32TempMccr, u32CLKHI, u32CLKHITemp, u32CLKLO, u32CLKLOTemp; uint32_t u32Prescale; uint32_t u32BandrateDeltaCur, u32BandrateDeltaBest; uint32_t u32FreqDesired, u32FreqCur; uint32_t u32ClkSrcHz; uint32_t u32FlitScl; uint8_t u8PrescaleTemp; uint32_t u32Divide; u32ClkSrcHz = sourceClock_Hz; u32FreqDesired = pMasterConfig->u32BaudRate; u32BandrateDeltaBest = pMasterConfig->u32BaudRate; u32BandrateDeltaCur = pMasterConfig->u32BaudRate; u32FlitScl = pMasterConfig->u8SclGlitchFilterWidth; for (u8PrescaleTemp = 1U; (u8PrescaleTemp <= 8U) && (u32BandrateDeltaCur != 0); u8PrescaleTemp++) { u32Divide = Fc_Power(2U, u8PrescaleTemp); for (u32CLKHITemp = 1U; (u32CLKHITemp < 32U) && (u32BandrateDeltaCur != 0); u32CLKHITemp++) { for(u32CLKLOTemp = (2 * u32CLKHITemp - 1); (u32CLKLOTemp < (2 * u32CLKHITemp + 2)) && (u32BandrateDeltaCur != 0); u32CLKLOTemp++) { u32FreqCur = u32ClkSrcHz / (u32Divide * (u32CLKLOTemp + u32CLKHITemp + 2U) + 4 + u32FlitScl); u32BandrateDeltaCur = u32FreqDesired > u32FreqCur ? (u32FreqDesired - u32FreqCur) : (u32FreqCur - u32FreqDesired); if (u32BandrateDeltaCur < u32BandrateDeltaBest) { u32Prescale = u8PrescaleTemp; u32CLKHI = u32CLKHITemp; u32CLKLO = u32CLKLOTemp; u32BandrateDeltaBest = u32BandrateDeltaCur; } } } } u32TempMccr = FCIIC_MCCR_DATAVD(2) | FCIIC_MCCR_SETHOLD(2) | FCIIC_MCCR_CLKHI(u32CLKHI) | FCIIC_MCCR_CLKLO(u32CLKLO); u32TempMcfgr1 = FCIIC_HWA_GetMCFGR1(pFciic); u32TempMcfgr1 &= ~FCIIC_MCFGR1_PRESCALE_MASK; u32TempMcfgr1 |= FCIIC_MCFGR1_PRESCALE(u32Prescale); FCIIC_HWA_SetMCCR(pFciic, u32TempMccr); FCIIC_HWA_SetMCFGR1(pFciic, u32TempMcfgr1); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Initializes the I2C master with the specified configuration. * * This function initializes the I2C master with the provided configuration and sets up the baud rate. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] pMasterConfig Pointer to the master configuration structure. * @param[in] sourceClock_Hz The source clock frequency in Hz. * * The function performs the following steps: * - Resets the I2C hardware. * - Sets the baud rate using the `FCIIC_MasterSetBaudRate` function. * - Configures the master control register (MCR) for debug enablement. * - Configures the master configuration registers (MCFGR1, MCFGR2, MCFGR3) for pin configuration, glitch filters, and timeouts. * - Enables the master operation. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointers are null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterInit(FCIIC_MasterHandleType *const pFciicMasterHandle, const FCIIC_MasterConfigType *const pMasterConfig, uint32_t sourceClock_Hz) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL || pMasterConfig == NULL) { FCIIC_ReportDevError(FCIIC_MASTERINIT_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERINIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint32_t u32TempMcfgr1, u32TempMcfgr2, u32TempMcfgr3; FCIIC_HwA_MasterReset(pFciic); FCIIC_MasterSetBaudRate(pFciicMasterHandle, sourceClock_Hz, pMasterConfig); FCIIC_HWA_SetMcr(pFciic, FCIIC_MCR_DBGEN(pMasterConfig->bDebugEnable)); /* pin config and ignore ack */ u32TempMcfgr1 = FCIIC_HWA_GetMCFGR1(pFciic); u32TempMcfgr1 &= ~(FCIIC_MCFGR1_PINCFG_MASK | FCIIC_MCFGR1_IGNACK_MASK); u32TempMcfgr1 |= FCIIC_MCFGR1_PINCFG(pMasterConfig->ePinConfig); FCIIC_HWA_SetMCFGR1(pFciic, u32TempMcfgr1); /* Configure glitch filters. */ u32TempMcfgr2 = FCIIC_MCFGR2_FILTSDA(pMasterConfig->u8SdaGlitchFilterWidth) | FCIIC_MCFGR2_FILTSCL(pMasterConfig->u8SclGlitchFilterWidth) | FCIIC_MCFGR2_BUSIDLE(pMasterConfig->u32BusIdleTimeout); FCIIC_HWA_SetMCFGR2(pFciic, u32TempMcfgr2); u32TempMcfgr3 = FCIIC_MCFGR3_PINLOW(pMasterConfig->u32PinLowTimeout); FCIIC_HWA_SetMCFGR3(pFciic, u32TempMcfgr3); FCIIC_HwA_MasterEnable(pFciic, pMasterConfig->bEnableMaster); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Deinitializes the I2C master. * * This function deinitializes the I2C master by resetting it and clearing its configuration. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Resets the master control register (MCR) to disable the master, reset, and clear DMA and buffer flags. * - Disables DMA operations by setting the master DMA enable register (MDER). * - Clears the pin configuration and glitch filter settings in the master configuration registers (MCFGR1, MCFGR2, MCFGR3). * - Resets the I2C hardware. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. */ void FCIIC_MasterDeinit(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERDEINIT_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif uint32 u32PccCgcMask = 0x800000U; uint32 u32PccSelMask = 0x700000U; uint32 u32PccBase = 0x40024000U; uint32 u32IICPccRegOffset[2] = {0x198U, 0x41CU}; FCIIC_Type *const pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint32 u32TempMcr, u32TempMder, u32TempPcc; u32TempMcr = FCIIC_MCR_RRF(0U) | FCIIC_MCR_RTF(0U) | FCIIC_MCR_DBGEN(0U) | FCIIC_MCR_RST(0U) | FCIIC_MCR_MEN(0U); /* master disable */ u32TempMder = FCIIC_MDER_RDDE(0U) | /* disable receive dma */ FCIIC_MDER_TDDE(0U); /* disable transmit dma */ FCIIC_HWA_MasterDisableInterrupts(pFciic, FCIIC_MIER_MASK); FCIIC_HWA_SetMder(pFciic, u32TempMder); /* PRQA S 0306 ++ #Misra-C:2012 Rule-11.4 A conversion should not be performed between a pointer to object and an integer type * Reason: Pointer to register addressing map operation could not be avoid */ u32TempPcc = *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicMasterHandle->eInstance])); /* Disable PCC gate */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicMasterHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccCgcMask)); /* Disable function clock */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicMasterHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccSelMask)); FCIIC_HWA_SetMcr(pFciic, FCIIC_MCR_RST(1U)); FCIIC_HWA_SetMcr(pFciic, u32TempMcr); /* Disable PCC gate */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicMasterHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccCgcMask)); /* Recover function clock */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicMasterHandle->eInstance])) = u32TempPcc; /* PRQA S 0306 -- */ #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Initializes the I2C master handle. * * This function initializes the I2C master handle with the specified instance and clears its status and settings. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] eInstance The instance of the I2C master to initialize. * * The function performs the following steps: * - Sets the instance of the handle. * - Clears the status fields including command data, direction, channel status, and offsets. * - Sets callback functions and user data pointers to null. * - Initializes DMA-related settings to null or zero. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterInitHandle(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_InstanceType eInstance) { uint8_t i = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERINITHANDLE_ID, FCIIC_E_PARAM_NULLPTR); } else if (eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERINITHANDLE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciicMasterHandle->eInstance = eInstance; pFciicMasterHandle->tStatus.bUsed = false; pFciicMasterHandle->tStatus.eDirection = FCIIC_DIRNOCONFIG; for (i = 0; i < FCIIC_MASTER_CMD_SIZE; i++) { pFciicMasterHandle->tStatus.u8Cmd[i] = FCIIC_TX_CMD_STOP; pFciicMasterHandle->tStatus.u16DmaCmdData[i] = 0; pFciicMasterHandle->tStatus.u8CmdData[i] = 0; } pFciicMasterHandle->tStatus.u8CmdSize = 0; pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicMasterHandle->tStatus.u8CmdOffset = 0; pFciicMasterHandle->tStatus.u16DataSize = 0; pFciicMasterHandle->tStatus.u16DataOffset = 0; pFciicMasterHandle->tSettings.pCallback = NULL; pFciicMasterHandle->tSettings.pErrorCallback = NULL; pFciicMasterHandle->tSettings.pUserData = NULL; pFciicMasterHandle->tSettings.pData = NULL; pFciicMasterHandle->tStatus.u8DmaCmdSize = 0; pFciicMasterHandle->tStatus.u8DmaCmdOffset = 0; pFciicMasterHandle->tSettings.pFciicTxDmaConfig = NULL; pFciicMasterHandle->tSettings.pFciicRxDmaConfig = NULL; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Enables interrupt handling for the I2C master. * * This function sets the callback functions and user data for interrupt handling in the I2C master. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] pCallback Pointer to the transfer callback function. * @param[in] pErrorCallback Pointer to the error callback function. * @param[in] pUserData User-defined data to be passed to the callback functions. * * The function performs the following steps: * - Sets the transfer callback, error callback, and user data pointers in the handle's settings. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. */ void FCIIC_MasterEnableInterrupt(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransfer_CallbackType pCallback, FCIIC_MasterError_CallBackType pErrorCallback, void *pUserData) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERENABLEINTERRUPT_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif pFciicMasterHandle->tSettings.pCallback = pCallback; pFciicMasterHandle->tSettings.pErrorCallback = pErrorCallback; pFciicMasterHandle->tSettings.pUserData = pUserData; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Checks and clears errors in the I2C master. * * This function checks for specific error conditions in the I2C master and clears them if present. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] status The status flags to check and clear. * * @return FCIIC_StatusType The error status or FCIIC_SUCCESS if no errors were detected. * * The function performs the following steps: * - Checks the status flags against known error conditions. * - Selects the appropriate error code based on the severity and type of error. * - Clears the error flags in the I2C hardware. * - Resets the FIFOs if necessary. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterCheckAndClearError(FCIIC_MasterHandleType *const pFciicMasterHandle, uint32_t status) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERCHECKANDCLEARERROR_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERCHECKANDCLEARERROR_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif status &= (uint32_t)FCIIC_MasterErrorFlags; pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; if (0U != status) { /* Select the correct error code. Ordered by severity, with bus issues first. */ if (0U != (status & (uint32_t)FCIIC_MSR_PLTF)) { result = FCIIC_PINLOWTIMEOUT; } else if (0U != (status & (uint32_t)FCIIC_MSR_ALF)) { result = FCIIC_ARBITRATIONLOST; } else if (0U != (status & (uint32_t)FCIIC_MSR_NDF)) { result = FCIIC_NAK; } else if (0U != (status & (uint32_t)FCIIC_MSR_FEF)) { result = FCIIC_FIFOERROR; } else { } /* Clear the flags. */ FCIIC_HWA_MasterClearStatusFlags(pFciic, status); /* Reset fifos. These flags clear automatically. */ FCIIC_HWA_MasterResetFIFO(pFciic); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Waits for a specific flag to be set in the I2C master. * * This function waits for a given flag to be set in the I2C master status and returns the result. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] u32Flag The flag to wait for. * * @return FCIIC_StatusType The status indicating success or timeout. * * The function performs the following steps: * - Waits for the specified flag to be set within a certain number of attempts. * - Returns FCIIC_SUCCESS if the flag is set, or FCIIC_TIMEOUT if the flag is not set within the timeout period. * - Checks and clears any errors that may have occurred during the wait. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterWaitFlag(FCIIC_MasterHandleType *const pFciicMasterHandle, uint32_t u32Flag) { FCIIC_StatusType result = FCIIC_TIMEOUT; FCIIC_Type *pFciic; uint32_t u32TryCount, u32TryTick; uint32_t status; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERWAITFLAG_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERWAITFLAG_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; u32TryCount = 0U; while (u32TryCount < 100U) { u32TryTick = 0U; while (u32TryTick++ < 100U) { __asm("nop"); } status = FCIIC_HWA_MasterGetStatusFlags(pFciic); if (0U != (status & u32Flag)) { result = FCIIC_SUCCESS; break; } u32TryCount++; } if (result != FCIIC_TIMEOUT) { result = FCIIC_MasterCheckAndClearError(pFciicMasterHandle, status); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Initiates an I2C start condition. * * This function initiates an I2C start condition and sends the device address along with the read/write direction. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] address The 7-bit I2C address of the target device. * @param[in] dir The direction of the communication (read or write). * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Checks if the bus is busy before starting. * - Clears all relevant flags in the I2C hardware. * - Sends a start condition followed by the address and direction. * - Waits for the transmission done flag to be set. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterStart(FCIIC_MasterHandleType *const pFciicMasterHandle, uint8_t address, FCIIC_DirectionType dir) { FCIIC_StatusType result = FCIIC_FAIL; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERSTART_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERSTART_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; result = FCIIC_MasterCheckForBusyBus(pFciicMasterHandle); if (result == FCIIC_SUCCESS) { /* Clear all flags. */ FCIIC_HWA_MasterClearStatusFlags(pFciic, FCIIC_MasterClearFlags); FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_STARTANDTRANSMIT, (uint8_t)((address << 1U) | dir)); result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_TDF); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Initiates an I2C repeated start condition. * * This function initiates an I2C repeated start condition and sends the device address along with the read/write direction. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] address The 7-bit I2C address of the target device. * @param[in] dir The direction of the communication (read or write). * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Sends a repeated start condition followed by the address and direction. * - Waits for the transmission done flag to be set. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterRepeatedStart(FCIIC_MasterHandleType *const pFciicMasterHandle, uint8_t address, FCIIC_DirectionType dir) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERREPEATEDSTART_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERREPEATEDSTART_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_STARTANDTRANSMIT, (uint8_t)((address << 1U) | dir)); result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_TDF); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Sends a sequence of commands in the I2C master. * * This function sends a sequence of commands and data to the I2C bus. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Iterates through each command in the command buffer. * - Sends the command and corresponding data. * - Waits for the transmission done flag to be set for each command. * - Increments the command offset after each successful transmission. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterSendStartCommand(FCIIC_MasterHandleType *const pFciicMasterHandle) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; uint8 i; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERSEND_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERSEND_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; for (i = 0; i < pFciicMasterHandle->tStatus.u8CmdSize; ++i) { FCIIC_Master_HWA_Transmit(pFciic, pFciicMasterHandle->tStatus.u8Cmd[i], pFciicMasterHandle->tStatus.u8CmdData[i]); result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_TDF); if (result != FCIIC_SUCCESS) { break; } pFciicMasterHandle->tStatus.u8CmdOffset++; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Sends data over the I2C bus. * * This function sends a block of data over the I2C bus. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] txBuff Pointer to the transmit buffer containing the data to send. * @param[in] txSize The size of the data to send in bytes. * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Iterates through each byte in the transmit buffer. * - Sends the byte over the I2C bus. * - Waits for the transmission done flag to be set for each byte. * - Increments the data offset after each successful transmission. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterSend(FCIIC_MasterHandleType *const pFciicMasterHandle, uint8 *txBuff, uint16 txSize) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; uint16 i; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERSEND_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERSEND_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; for (i = 0; i < txSize; ++i) { FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_TRANSMIT, txBuff[i]); result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_TDF); if (result != FCIIC_SUCCESS) { break; } pFciicMasterHandle->tStatus.u16DataOffset++; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Receives data over the I2C bus. * * This function receives a block of data over the I2C bus. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Iterates through each byte of the receive buffer. * - Waits for the receive data flag to be set. * - Reads the received byte from the I2C bus. * - Stores the received byte in the receive buffer. * - Increments the data offset after each successful reception. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterReceive(FCIIC_MasterHandleType *const pFciicMasterHandle) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; uint8_t i; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERRECEIVE_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERRECEIVE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; for (i = 0; i < pFciicMasterHandle->tStatus.u16DataSize; ++i) { result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_RDF); if (result != FCIIC_SUCCESS) { break; } pFciicMasterHandle->tSettings.pData[i] = FCIIC_Master_HWA_Receive(pFciic); pFciicMasterHandle->tStatus.u16DataOffset++; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Sends a stop condition over the I2C bus. * * This function sends a stop condition over the I2C bus. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * @return FCIIC_StatusType The status indicating success or failure. * * The function performs the following steps: * - Sends a stop condition over the I2C bus. * - Waits for the transmission done flag to be set. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ FCIIC_StatusType FCIIC_MasterStop(FCIIC_MasterHandleType *const pFciicMasterHandle) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERSTOP_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERSTOP_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_STOP, 0U); result = FCIIC_MasterWaitFlag(pFciicMasterHandle, FCIIC_MSR_TDF); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Aborts an ongoing I2C transfer. * * This function aborts an ongoing I2C transfer by disabling interrupts, resetting the FIFO, and marking the handle as unused. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Disables interrupts for the I2C master. * - Resets the FIFO. * - Marks the handle as unused. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterTransferAbort(FCIIC_MasterHandleType *const pFciicMasterHandle) { FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_MASTERTRANSFERABORT_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERTRANSFERABORT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_HWA_MasterDisableInterrupts(pFciic, (uint32_t)FCIIC_MasterIrqFlags); FCIIC_HWA_MasterResetFIFO(pFciic); pFciicMasterHandle->tStatus.bUsed = false; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Sets the receive length for an ongoing I2C transfer. * * This function sets the number of bytes to receive during an ongoing I2C transfer. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] u8Len The number of bytes to receive. * * @return uint8_t Returns 1 if the receive length was successfully set, otherwise 0. * * The function performs the following steps: * - Checks if the transmit count is less than 8. * - If the condition is met, sends a receive command with the specified length minus one. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. */ uint8_t FCIIC_MasterSetReceiveLen(FCIIC_MasterHandleType *const pFciicMasterHandle, uint8 u8Len) { uint8_t eRetType = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERSETRECEIVELEN_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint8_t count = (uint8_t)FCIIC_Master_HWA_GetTxCount(pFciic); if (8u > count) { FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_RECEIVE, (uint8_t)(u8Len - (uint8)1u)); eRetType = 1; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return eRetType; } /** * @brief Transmits data over the I2C bus. * * This function transmits data over the I2C bus if the transmission data flag is set. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] pTxData Pointer to the transmit data structure containing the command and data to send. * * @return uint8_t Returns 1 if the transmission was initiated, otherwise 0. * * The function performs the following steps: * - Clears any error flags. * - Checks the transmission data flag. * - If the flag is set, sends the command and data. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointers are null and report an error accordingly. It also checks if the instance is valid. */ uint8_t FCIIC_MasterTransmit(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_TxDataType *pTxData) { uint8_t u8RetVal = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle || NULL == pTxData) { FCIIC_ReportDevError(FCIIC_MASTERTRANSMIT_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERTRANSMIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; /* clear error flag */ /* CheckAndClear(pFciic); */ /* check tx data flag */ u8RetVal = FCIIC_Master_HWA_GetStatus(pFciic, FCIIC_MSR_TDF_STATUS); /* pFciic->MSR |= FCIIC_MSR_FEF_MASK; */ /* clear fifo error error */ if (u8RetVal == 1U) { FCIIC_Master_HWA_Transmit(pFciic, pTxData->eCmd, pTxData->u8Data); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return u8RetVal; } /** * @brief Gets the status of the I2C master. * * This function retrieves the status of the I2C master based on the specified status type. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] eStatus The status type to retrieve. * * @return uint8_t Returns the status value as a bit mask. * * The function performs the following steps: * - Retrieves the status based on the specified status type. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ uint8_t FCIIC_MasterGetStatus(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterStatusType eStatus) { uint8_t u8Status = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERGETSTATUS_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERGETSTATUS_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; u8Status = (uint8_t)(1U >> FCIIC_Master_HWA_GetStatus(pFciic, eStatus)); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return u8Status; } /** * @brief Clears the status flags of the I2C master. * * This function clears specific status flags of the I2C master. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Clears the data match flag, protocol error flag, FIFO error flag, address lost flag, * not data flag, start detection flag, and end packet flag. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterClrStatus(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERCLRSTATUS_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERCLRSTATUS_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_Master_HWA_ClrStatus(pFciic, FCIIC_MSR_DMF_MASK | FCIIC_MSR_PLTF_MASK | FCIIC_MSR_FEF_MASK | FCIIC_MSR_ALF_MASK | FCIIC_MSR_NDF_MASK | FCIIC_MSR_SDF_MASK | FCIIC_MSR_EPF_MASK); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Performs a blocking I2C transfer. * * This function performs a blocking I2C transfer, which includes sending commands and data, and handling the transfer completion or errors. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] transfer Pointer to the I2C transfer parameters. * * @return FCIIC_StatusType Returns the status of the transfer operation. * * The function performs the following steps: * - Checks if the bus is busy or the handle is already in use. * - Clears the status flags. * - Initializes the handle's status fields. * - Generates and sends the start command. * - Sends or receives data based on the direction. * - Sends a stop signal after the data transfer. * - Calls the callback function upon successful transfer completion. * - Calls the error callback function if an error occurs during the transfer. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointers are null and report an error accordingly. */ FCIIC_StatusType FCIIC_MasterTransferBlocking(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransferType *const transfer) { FCIIC_StatusType result = FCIIC_SUCCESS; uint32_t u8CurChSts; FCIIC_DirectionType eDirection; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if ((NULL == pFciicMasterHandle) || (NULL == transfer)) { FCIIC_ReportDevError(FCIIC_MASTERTRANSFERBLOCKING_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif if ((NULL != pFciicMasterHandle) && (NULL != transfer) && (pFciicMasterHandle->eInstance < FCIIC_INSTANCE_COUNT)) { pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; result = FCIIC_MasterCheckForBusyBus(pFciicMasterHandle); if ((result == FCIIC_BUSY) || (pFciicMasterHandle->tStatus.bUsed == true) || (FCIIC_CH_IDLE != pFciicMasterHandle->tStatus.eChannelStatus)) { return FCIIC_BUSY; } /* Clear FIFO. */ FCIIC_HWA_MasterResetFIFO(pFciic); FCIIC_MasterClrStatus(pFciicMasterHandle); pFciicMasterHandle->tStatus.bUsed = true; pFciicMasterHandle->tStatus.eDirection = transfer->eDirection; pFciicMasterHandle->tSettings.pData = transfer->pData; pFciicMasterHandle->tStatus.u16DataSize = transfer->u16DataSize; pFciicMasterHandle->tStatus.u16DataOffset = 0; pFciicMasterHandle->tStatus.u8CmdSize = 0; pFciicMasterHandle->tStatus.u8CmdOffset = 0; eDirection = pFciicMasterHandle->tStatus.eDirection; FCIIC_MasterGenerateStartCommand(pFciicMasterHandle, transfer); /*master send command data stage*/ result = FCIIC_MasterSendStartCommand(pFciicMasterHandle); if ((FCIIC_SUCCESS == result) && (pFciicMasterHandle->tStatus.u8CmdOffset == pFciicMasterHandle->tStatus.u8CmdSize)) { pFciicMasterHandle->tStatus.eChannelStatus = eDirection == FCIIC_WRITE ? FCIIC_CH_START_WRITE : FCIIC_CH_START_READ; } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } /*master transmit or receive data stage*/ if ((FCIIC_WRITE == eDirection) && (FCIIC_CH_START_WRITE == pFciicMasterHandle->tStatus.eChannelStatus)) { result = FCIIC_MasterSend(pFciicMasterHandle, pFciicMasterHandle->tSettings.pData, pFciicMasterHandle->tStatus.u16DataSize); } else if ((FCIIC_READ == eDirection) && (FCIIC_CH_START_READ == pFciicMasterHandle->tStatus.eChannelStatus)) { result = FCIIC_MasterReceive(pFciicMasterHandle); } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; result = FCIIC_TRAMSMITORRECEIVEERROR; } /*master send stop signal stage*/ if ((FCIIC_SUCCESS == result) && (pFciicMasterHandle->tStatus.u16DataOffset == pFciicMasterHandle->tStatus.u16DataSize)) { result = FCIIC_MasterStop(pFciicMasterHandle); pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; result |= FCIIC_TRAMSMITORRECEIVEERROR; } /*master callback function*/ if ((FCIIC_SUCCESS == result) && (pFciicMasterHandle->tStatus.eChannelStatus == FCIIC_CH_TRANSFER_FINISHED)) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicMasterHandle->tStatus.bUsed = false; if (NULL != pFciicMasterHandle->tSettings.pCallback) { pFciicMasterHandle->tSettings.pCallback(pFciicMasterHandle, FCIIC_SUCCESS); } } /*master callback error function*/ if (FCIIC_CH_ERROR_PRESENT == pFciicMasterHandle->tStatus.eChannelStatus) { u8CurChSts = FCIIC_HWA_GetMSR(pFciic); result |= FCIIC_MasterCheckAndClearError(pFciicMasterHandle, u8CurChSts); FCIIC_MasterTransferAbort(pFciicMasterHandle); if (NULL != pFciicMasterHandle->tSettings.pErrorCallback) { pFciicMasterHandle->tSettings.pErrorCallback(pFciicMasterHandle, result); } pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicMasterHandle->tStatus.bUsed = false; } } else { result = FCIIC_FAIL; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Prepares the DMA channel for I2C master transfer. * * This function prepares the DMA channel for data transfer by configuring the DMA attributes and starting the DMA transfer. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Configures the DMA channel attributes based on the transfer direction (read/write). * - Sets up the DMA source and destination buffers, block size, and other settings. * - Starts the DMA transfer. * - Updates the channel status based on the transfer direction. * - Calls the error callback function if an error occurs during preparation. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterDmaPrepare(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMAPREPARE_ID, FCIIC_E_PARAM_NULLPTR); } else if ((NULL != pFciicMasterHandle) && (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERDMAPREPARE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif DMA_HandleType *pDmaHandle = NULL; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; DMA_ChannelCfgType FCIIC_DmaChannelAttr = {0}; if (FCIIC_DMA_NEXT_STAGE_DATA == pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage || FCIIC_DMA_NEXT_STAGE_DATA == pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage) { FCIIC_DmaChannelAttr.eSrcDataSize = DMA_TRANSFER_SIZE_1B; FCIIC_DmaChannelAttr.eDestDataSize = DMA_TRANSFER_SIZE_1B; FCIIC_DmaChannelAttr.u32BlockSize = 1; FCIIC_DmaChannelAttr.u16BlockCount = pFciicMasterHandle->tStatus.u16DataSize; if (FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection) { FCIIC_DmaChannelAttr.pSrcBuffer = &(pFciicMasterHandle->tSettings.pData[0]); FCIIC_DmaChannelAttr.pDestBuffer = &(pFciic->MTDR); FCIIC_DmaChannelAttr.eSrcIncMode = DMA_INCREMENT_DATA_SIZE ; FCIIC_DmaChannelAttr.eDestIncMode = DMA_INCREMENT_DISABLE; pDmaHandle = pFciicMasterHandle->tSettings.pFciicTxDmaConfig->pDmaHandle; if (FCIIC_INSTANCE_0 == pFciicMasterHandle->eInstance) { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC0_TX; } else { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC1_TX; } } else if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { FCIIC_DmaChannelAttr.pSrcBuffer = &(pFciic->MRDR); FCIIC_DmaChannelAttr.pDestBuffer = &(pFciicMasterHandle->tSettings.pData[0]); FCIIC_DmaChannelAttr.eSrcIncMode = DMA_INCREMENT_DISABLE ; FCIIC_DmaChannelAttr.eDestIncMode = DMA_INCREMENT_DATA_SIZE; pDmaHandle = pFciicMasterHandle->tSettings.pFciicRxDmaConfig->pDmaHandle; if (FCIIC_INSTANCE_0 == pFciicMasterHandle->eInstance) { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC0_RX; } else { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC1_RX; } } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { FCIIC_DmaChannelAttr.pSrcBuffer = &(pFciicMasterHandle->tStatus.u16DmaCmdData[0]); FCIIC_DmaChannelAttr.pDestBuffer = &(pFciic->MTDR); FCIIC_DmaChannelAttr.eSrcDataSize = DMA_TRANSFER_SIZE_2B; FCIIC_DmaChannelAttr.eDestDataSize = DMA_TRANSFER_SIZE_2B; FCIIC_DmaChannelAttr.u32BlockSize = 2; FCIIC_DmaChannelAttr.u16BlockCount = pFciicMasterHandle->tStatus.u8DmaCmdSize; FCIIC_DmaChannelAttr.eSrcIncMode = DMA_INCREMENT_DATA_SIZE ; FCIIC_DmaChannelAttr.eDestIncMode = DMA_INCREMENT_DISABLE; pDmaHandle = pFciicMasterHandle->tSettings.pFciicTxDmaConfig->pDmaHandle; if (FCIIC_INSTANCE_0 == pFciicMasterHandle->eInstance) { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC0_TX; } else { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC1_TX; } } FCIIC_DmaChannelAttr.u8ChannelPriority = pDmaHandle->tSettings.u8Channel; FCIIC_DmaChannelAttr.bSrcBlockOffsetEn = false; FCIIC_DmaChannelAttr.bDestBlockOffsetEn = false; FCIIC_DmaChannelAttr.s32BlockOffset = 0; FCIIC_DmaChannelAttr.bSrcAddrLoopbackEn = false; FCIIC_DmaChannelAttr.bDestAddrLoopbackEn = false; FCIIC_DmaChannelAttr.bAutoStop = true; FCIIC_DmaChannelAttr.bSrcCircularBufferEn = false; FCIIC_DmaChannelAttr.u32SrcCircBufferSize = 0; FCIIC_DmaChannelAttr.bDestCircularBufferEn = false; FCIIC_DmaChannelAttr.u32DestCircBufferSize = 0; FCIIC_DmaChannelAttr.bTransferCompleteIntEn = true; FCIIC_DmaChannelAttr.pTransferCompleteNotify = pDmaHandle->tSettings.callback.pTransferCompleteCallback; FCIIC_DmaChannelAttr.bTransferErrorIntEn = false; FCIIC_DmaChannelAttr.pTransferErrorNotify = NULL; FCIIC_DmaChannelAttr.completedata = NULL; FCIIC_DmaChannelAttr.errdata = NULL; if (FCIIC_CH_IDLE == pFciicMasterHandle->tStatus.eChannelStatus) { if ((FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_IDLE == pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_START_READ; pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_DATA; } else if ((FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_IDLE == pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_DATA; pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_START_WRITE; } else { if (NULL != pFciicMasterHandle->tSettings.pErrorCallback) { pFciicMasterHandle->tSettings.pErrorCallback(pFciicMasterHandle, FCIIC_DMAREQUESTFAIL); } } } DMA_InitChannel(pDmaHandle, &FCIIC_DmaChannelAttr); DMA_StartChannel(pDmaHandle); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Stops the DMA transfer for the I2C master. * * This function stops the DMA transfer by preparing a stop command and updating the DMA configuration. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Sets up the stop command in the DMA command buffer. * - Prepares the DMA for the stop command. * - Updates the channel status to indicate the transfer has been stopped. * - Adjusts the next DMA stage based on the transfer direction. * - Calls the error callback function if an error occurs during the preparation. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterDmaStop(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMASTOP_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERDMASTOP_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif pFciicMasterHandle->tStatus.u16DmaCmdData[0] = (uint16)FCIIC_MTDR_CMD(FCIIC_TX_CMD_STOP); pFciicMasterHandle->tStatus.u8DmaCmdSize = 1; pFciicMasterHandle->tStatus.u8DmaCmdOffset = 0; FCIIC_MasterDmaPrepare(pFciicMasterHandle); pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_CLOSED; if ((FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_STOP == pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_NOTIFICATION; } else if ((FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_STOP == pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_NOTIFICATION; } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Initiates a DMA transmit operation for the I2C master. * * This function initiates the DMA transmit operation by preparing the DMA for transmission and setting the next DMA stage to stop. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Prepares the DMA for the transmit operation. * - Sets the next DMA stage to stop after the transmission. * - Calls the error callback function if an error occurs during preparation. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterDmaTransmit(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMATRANSMIT_ID, FCIIC_E_PARAM_NULLPTR); } else if ((NULL != pFciicMasterHandle) && (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERDMATRANSMIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_MasterDmaPrepare(pFciicMasterHandle); pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_STOP; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Initiates a DMA receive operation for the I2C master. * * This function initiates the DMA receive operation by preparing the DMA for reception and setting the next DMA stage to stop. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * * The function performs the following steps: * - Prepares the DMA for the receive operation. * - Sets the next DMA stage to stop after the reception. * - Calls the error callback function if an error occurs during preparation. * * @note If FCIIC_DEV_ERROR_REPORT is defined as STD_ON, this function will check if the provided pointer is null and report an error accordingly. It also checks if the instance is valid. */ void FCIIC_MasterDmaReceive(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMARECEIVE_ID, FCIIC_E_PARAM_NULLPTR); } else if ((NULL == pFciicMasterHandle) && (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERDMARECEIVE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_MasterDmaPrepare(pFciicMasterHandle); pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_STOP; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Starts the DMA transfer for the FCIIC master. * * This function initializes the DMA command sequence based on the given transfer parameters. * It checks for valid input parameters and then prepares the DMA commands to be sent. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle structure. * @param[in] transfer Pointer to the FCIIC master transfer structure containing transfer details. */ void FCIIC_MasterDmaStart(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransferType *const transfer) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMASTART_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERDMASTART_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif uint8_t *pSubAddr = (uint8_t *)&transfer->subaddress; uint32 i; pFciicMasterHandle->tStatus.u8DmaCmdSize = 0; if (0U != transfer->subaddressSize) { pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)(FCIIC_MTDR_CMD(FCIIC_TX_CMD_STARTANDTRANSMIT) | FCIIC_MTDR_DATA((uint8)( transfer->u8SlaveAddress << 1) | FCIIC_WRITE)); pFciicMasterHandle->tStatus.u8DmaCmdSize++; for (i = transfer->subaddressSize; i > 0 ; --i) { pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)(FCIIC_MTDR_CMD(FCIIC_TX_CMD_TRANSMIT) | FCIIC_MTDR_DATA(pSubAddr[i - 1])); pFciicMasterHandle->tStatus.u8DmaCmdSize++; } if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)(FCIIC_MTDR_CMD(FCIIC_TX_CMD_STARTANDTRANSMIT) | FCIIC_MTDR_DATA(( transfer->u8SlaveAddress << 1) | FCIIC_READ)); pFciicMasterHandle->tStatus.u8DmaCmdSize++; pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)(FCIIC_MTDR_CMD(FCIIC_TX_CMD_RECEIVE) | FCIIC_MTDR_DATA((transfer->u16DataSize - 1))); pFciicMasterHandle->tStatus.u8DmaCmdSize++; } } else { pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)((uint16)FCIIC_MTDR_CMD(FCIIC_TX_CMD_STARTANDTRANSMIT) | (( transfer->u8SlaveAddress << 1) | transfer->eDirection)); pFciicMasterHandle->tStatus.u8DmaCmdSize++; if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { pFciicMasterHandle->tStatus.u16DmaCmdData[pFciicMasterHandle->tStatus.u8DmaCmdSize] = (uint16)(FCIIC_MTDR_CMD(FCIIC_TX_CMD_RECEIVE) | (uint8_t)(transfer->u16DataSize - 1)); pFciicMasterHandle->tStatus.u8DmaCmdSize++; } } FCIIC_MasterDmaPrepare(pFciicMasterHandle); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Handles the notification stage after a DMA transmission. * * This function updates the channel status and triggers a callback if one is registered. * It also manages the next stage of DMA operations based on the direction of the transfer. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterDmaStageNotification(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMASTAGENOTIFICATION_ID, FCIIC_E_PARAM_NULLPTR); } #endif pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; if ((FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_NOTIFICATION == pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } else if ((FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_DMA_NEXT_STAGE_NOTIFICATION == pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if (NULL != pFciicMasterHandle->tSettings.pCallback) { pFciicMasterHandle->tSettings.pCallback(pFciicMasterHandle, FCIIC_SUCCESS); } pFciicMasterHandle->tStatus.bUsed = false; } /** * @brief Handles the data stage of a DMA transmission. * * This function updates the channel status and triggers the data transfer phase * based on the current state and direction of the transfer. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterDmaStageData(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERDMASTAGEDATA_ID, FCIIC_E_PARAM_NULLPTR); } #endif FCIIC_ChannelStatusType eChannelStatus; eChannelStatus = pFciicMasterHandle->tStatus.eChannelStatus; if ((FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_CH_START_WRITE == eChannelStatus) && (FCIIC_DMA_NEXT_STAGE_DATA == pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; FCIIC_MasterDmaTransmit(pFciicMasterHandle); } else if ((FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) && (FCIIC_CH_START_READ == eChannelStatus) && (FCIIC_DMA_NEXT_STAGE_DATA == pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage)) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; FCIIC_MasterDmaReceive(pFciicMasterHandle); } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } /** * @brief DMA interrupt handler for the FCIIC master. * * This function handles DMA interrupts by determining the next stage of the DMA operation, * updating the channel status, and managing error conditions. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_LL_MasterDmaIRQnHandler(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_LL_MASTERDMAIRQNHANDLER_ID, FCIIC_E_PARAM_NULLPTR); } #endif FCIIC_DmaStatusType eDmaNextStage; uint32_t u8CurChSts; FCIIC_ChannelStatusType eChannelStatus = pFciicMasterHandle->tStatus.eChannelStatus; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_StatusType eResult; eDmaNextStage = FCIIC_WRITE == pFciicMasterHandle->tStatus.eDirection ? pFciicMasterHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage : pFciicMasterHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage; eChannelStatus = pFciicMasterHandle->tStatus.eChannelStatus; if ((FCIIC_DMA_NEXT_STAGE_DATA == eDmaNextStage) && ((FCIIC_CH_START_READ == eChannelStatus) || (FCIIC_CH_START_WRITE == eChannelStatus))) { pFciicMasterHandle->tStatus.u8DmaCmdOffset = pFciicMasterHandle->tStatus.u8DmaCmdSize; FCIIC_MasterDmaStageData(pFciicMasterHandle); } else if ((FCIIC_DMA_NEXT_STAGE_STOP == eDmaNextStage) && (FCIIC_CH_TRANSFER_FINISHED == eChannelStatus)) { pFciicMasterHandle->tStatus.u16DataOffset = pFciicMasterHandle->tStatus.u16DataSize; FCIIC_MasterDmaStop(pFciicMasterHandle); } else if ((FCIIC_DMA_NEXT_STAGE_NOTIFICATION == eDmaNextStage) && (FCIIC_CH_CLOSED == eChannelStatus)) { pFciicMasterHandle->tStatus.u8DmaCmdOffset = pFciicMasterHandle->tStatus.u8DmaCmdSize ; FCIIC_MasterDmaStageNotification(pFciicMasterHandle); } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if (FCIIC_CH_ERROR_PRESENT == pFciicMasterHandle->tStatus.eChannelStatus) { u8CurChSts = FCIIC_HWA_GetMSR(pFciic); eResult = FCIIC_MasterCheckAndClearError(pFciicMasterHandle, u8CurChSts); FCIIC_MasterTransferAbort(pFciicMasterHandle); if (NULL != pFciicMasterHandle->tSettings.pErrorCallback) { pFciicMasterHandle->tSettings.pErrorCallback(pFciicMasterHandle, eResult); } } } /** * @brief Initiates a DMA transfer for the FCIIC master. * * This function starts a DMA transfer by configuring the DMA settings and initiating the transfer process. * It checks for valid parameters, ensures the bus is not busy, and configures the DMA accordingly. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. * @param[in] transfer Pointer to the FCIIC master transfer structure containing transfer details. * * @return FCIIC_StatusType The status of the DMA transfer initiation. */ FCIIC_StatusType FCIIC_MasterDmaTransfer(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransferType *const transfer) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle || NULL == transfer) { FCIIC_ReportDevError(FCIIC_MASTERDMATRANSFER_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERDMATRANSFER_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif if ((NULL != pFciicMasterHandle) && (NULL != transfer) && (pFciicMasterHandle->eInstance < FCIIC_INSTANCE_COUNT)) { pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; result = FCIIC_MasterCheckForBusyBus(pFciicMasterHandle); if ((result == FCIIC_BUSY) || (pFciicMasterHandle->tStatus.bUsed == true) || (FCIIC_CH_IDLE != pFciicMasterHandle->tStatus.eChannelStatus)) { return FCIIC_BUSY; } if ((NULL != pFciicMasterHandle->tSettings.pFciicRxDmaConfig) && (NULL != pFciicMasterHandle->tSettings.pFciicTxDmaConfig)) { /* Clear FIFO. */ FCIIC_HWA_MasterResetFIFO(pFciic); FCIIC_HWA_MasterClearStatusFlags(pFciic, FCIIC_MasterClearFlags); FCIIC_HWA_MasterEnableDMA(pFciic, false, false); pFciicMasterHandle->tSettings.pData = transfer->pData; pFciicMasterHandle->tStatus.u16DataSize = transfer->u16DataSize; pFciicMasterHandle->tStatus.eDirection = transfer->eDirection; pFciicMasterHandle->tStatus.u16DataOffset = 0; pFciicMasterHandle->tStatus.u8DmaCmdSize = 0; pFciicMasterHandle->tStatus.u8DmaCmdOffset = 0; pFciicMasterHandle->tStatus.bUsed = true; FCIIC_MasterDmaStart(pFciicMasterHandle, transfer); FCIIC_HWA_MasterEnableDMA(pFciic, true, true); } else { result = FCIIC_DMAREQUESTFAIL; if (NULL != pFciicMasterHandle->tSettings.pErrorCallback) { pFciicMasterHandle->tSettings.pErrorCallback(pFciicMasterHandle, FCIIC_DMAREQUESTFAIL); } } } else { result = FCIIC_FAIL; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Stops the interrupt process for the FCIIC master. * * This function disables all interrupts, updates the channel status, and triggers a callback if the data transfer is complete. * It also handles error conditions if the data offset does not match the expected size. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterInterruptProcessStop(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSSTOP_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSSTOP_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; /* Disable All interrupts */ FCIIC_HWA_MasterDisableInterrupts(pFciic, (uint32_t)FCIIC_MasterIrqFlags); /* Update channel status */ pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicMasterHandle->tStatus.bUsed = false; if (pFciicMasterHandle->tStatus.u16DataOffset == pFciicMasterHandle->tStatus.u16DataSize) { if (NULL != pFciicMasterHandle->tSettings.pCallback) { pFciicMasterHandle->tSettings.pCallback(pFciicMasterHandle, FCIIC_SUCCESS); } } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes the transmit phase in interrupt mode for the FCIIC master. * * This function transmits data and updates the data offset. It stops the transfer and updates the channel status when the data transfer is complete. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterInterruptProcessTransmit(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSTRANSMIT_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSTRANSMIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint16 u16CurIdx; uint8 u8Data; u16CurIdx = pFciicMasterHandle->tStatus.u16DataOffset; if (u16CurIdx != pFciicMasterHandle->tStatus.u16DataSize) { u8Data = pFciicMasterHandle->tSettings.pData[u16CurIdx]; FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_TRANSMIT, u8Data); pFciicMasterHandle->tStatus.u16DataOffset++; if (pFciicMasterHandle->tStatus.u16DataOffset == pFciicMasterHandle->tStatus.u16DataSize) { (void)FCIIC_MasterStop(pFciicMasterHandle); /* Update channel status */ pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes the receive phase in interrupt mode for the FCIIC master. * * This function receives data and updates the data offset. It stops the transfer and updates the channel status when the data reception is complete. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterInterruptProcessReceive(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSRECEIVE_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSRECEIVE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint16 u16CurIdx = pFciicMasterHandle->tStatus.u16DataOffset; if (u16CurIdx != pFciicMasterHandle->tStatus.u16DataSize) { pFciicMasterHandle->tSettings.pData[u16CurIdx] = FCIIC_Master_HWA_Receive(pFciic); pFciicMasterHandle->tStatus.u16DataOffset++; if (pFciicMasterHandle->tStatus.u16DataOffset == pFciicMasterHandle->tStatus.u16DataSize) { (void)FCIIC_MasterStop(pFciicMasterHandle); pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes the start phase in interrupt mode for the FCIIC master. * * This function manages the command transmission and updates the command offset. It transitions the channel status based on the current phase of the transfer. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_MasterInterruptProcessStart(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicMasterHandle) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSSTART_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_MASTERINTERRUPTPROCESSSTART_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; FCIIC_ChannelStatusType eChannelStatus = pFciicMasterHandle->tStatus.eChannelStatus; uint8 u16CurIdx = pFciicMasterHandle->tStatus.u8CmdOffset; if (u16CurIdx != pFciicMasterHandle->tStatus.u8CmdSize) { pFciicMasterHandle->tStatus.u8CmdOffset++; if (pFciicMasterHandle->tStatus.u8CmdOffset == pFciicMasterHandle->tStatus.u8CmdSize) { if (eChannelStatus == FCIIC_CH_START_WRITE) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_SENDING; } else if (eChannelStatus == FCIIC_CH_START_READ) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_RECEIVING; FCIIC_HWA_MasterDisableInterrupts(pFciic, FCIIC_MIER_TDIE); } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } FCIIC_Master_HWA_Transmit(pFciic, pFciicMasterHandle->tStatus.u8Cmd[u16CurIdx], pFciicMasterHandle->tStatus.u8CmdData[u16CurIdx]); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Handles the interrupt for the FCIIC master. * * This function processes various interrupt sources and updates the state of the transfer based on the current channel status. * It also handles errors and calls appropriate callbacks. * * @param[in] pFciicMasterHandle Pointer to the FCIIC master handle. */ void FCIIC_LL_MasterIRQnHandler(FCIIC_MasterHandleType *const pFciicMasterHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicMasterHandle == NULL) { FCIIC_ReportDevError(FCIIC_LL_MASTERIRQNHANDLER_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_LL_MASTERIRQNHANDLER_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; uint32_t u8CurChSts; FCIIC_StatusType eResult = FCIIC_SUCCESS; FCIIC_ChannelStatusType eChannelStatus = pFciicMasterHandle->tStatus.eChannelStatus; u8CurChSts = FCIIC_HWA_GetMSR(pFciic); u8CurChSts &= FCIIC_HWA_GetMIER(pFciic); if ((0 != (u8CurChSts & FCIIC_MasterErrorFlags))) { eResult = FCIIC_MasterCheckAndClearError(pFciicMasterHandle, u8CurChSts); /* Update channel status */ pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } else if ((0 != (u8CurChSts & FCIIC_MSR_TDF)) && ((eChannelStatus == FCIIC_CH_START_WRITE) || (eChannelStatus == FCIIC_CH_START_READ))) { FCIIC_MasterInterruptProcessStart(pFciicMasterHandle); } else if ((0 != (u8CurChSts & FCIIC_MSR_TDF)) && (eChannelStatus == FCIIC_CH_SENDING)) { FCIIC_MasterInterruptProcessTransmit(pFciicMasterHandle); } else if ((0 != (u8CurChSts & FCIIC_MSR_RDF)) && (eChannelStatus == FCIIC_CH_RECEIVING)) { FCIIC_MasterInterruptProcessReceive(pFciicMasterHandle); } else if ((0 != (u8CurChSts & FCIIC_MSR_SDF)) && (eChannelStatus == FCIIC_CH_TRANSFER_FINISHED)) { FCIIC_MasterInterruptProcessStop(pFciicMasterHandle); } else { FCIIC_Master_HWA_Transmit(pFciic, FCIIC_TX_CMD_STOP, 0U); eResult = FCIIC_TRAMSMITORRECEIVEERROR; pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if (FCIIC_CH_ERROR_PRESENT == pFciicMasterHandle->tStatus.eChannelStatus) { FCIIC_MasterTransferAbort(pFciicMasterHandle); if (NULL != pFciicMasterHandle->tSettings.pErrorCallback) { pFciicMasterHandle->tSettings.pErrorCallback(pFciicMasterHandle, eResult); } pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicMasterHandle->tStatus.bUsed = false; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Generates a start command for the FCIIC Master. * * This function initializes the master for transmission by generating the necessary commands for the start of a transfer. * * @param[in] pFciicMasterHandle The FCIIC Master Handle. * @param[in] transfer Pointer to the `FCIIC_MasterTransferType` structure containing the transfer details. * @return void */ void FCIIC_MasterGenerateStartCommand(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransferType *const transfer) { uint8_t *pSubAddr = (uint8_t *)&transfer->subaddress; uint32_t i; if (0U != transfer->subaddressSize) { pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_STARTANDTRANSMIT; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = (uint8_t)((transfer->u8SlaveAddress << 1) | FCIIC_WRITE); pFciicMasterHandle->tStatus.u8CmdSize++; for (i = transfer->subaddressSize; i > 0 ; --i) { pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_TRANSMIT; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = pSubAddr[i - 1]; pFciicMasterHandle->tStatus.u8CmdSize++; } if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_STARTANDTRANSMIT; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = (uint8_t)((transfer->u8SlaveAddress << 1) | FCIIC_READ); pFciicMasterHandle->tStatus.u8CmdSize++; pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_RECEIVE; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = (uint8_t)(transfer->u16DataSize - 1); pFciicMasterHandle->tStatus.u8CmdSize++; } } else { pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_STARTANDTRANSMIT; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = (uint8_t)((transfer->u8SlaveAddress << 1) | pFciicMasterHandle->tStatus.eDirection); pFciicMasterHandle->tStatus.u8CmdSize++; if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { pFciicMasterHandle->tStatus.u8Cmd[pFciicMasterHandle->tStatus.u8CmdSize] = FCIIC_TX_CMD_RECEIVE; pFciicMasterHandle->tStatus.u8CmdData[pFciicMasterHandle->tStatus.u8CmdSize] = (uint8_t)(transfer->u16DataSize - 1); pFciicMasterHandle->tStatus.u8CmdSize++; } } } /** * @brief Initiates a non-blocking I2C Master transfer. * * Sets up and initiates a non-blocking I2C Master transfer, including handling of START, addressing, subaddress (if provided), * data transfer, and STOP conditions. Returns immediately after starting the transfer, and the transfer is managed asynchronously * using interrupts. * * @param[in] pFciicMasterHandle Pointer to the FCIIC Master Handle. * @param[in] transfer Pointer to the `FCIIC_MasterTransferType` structure containing the transfer details. * @return A status code indicating the outcome of the initiation process: * - FCIIC_SUCCESS: The transfer was initiated successfully. * - FCIIC_BSY: Another non-blocking transfer is already in progress. * - Other error codes: Errors encountered during the transfer setup, such as a busy bus. */ FCIIC_StatusType FCIIC_MasterTransferNonBlocking(FCIIC_MasterHandleType *const pFciicMasterHandle, FCIIC_MasterTransferType *const transfer) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic ; #if FCIIC_DEV_ERROR_REPORT == STD_ON if ((NULL == pFciicMasterHandle) || (NULL == transfer)) { FCIIC_ReportDevError(FCIIC_MASTERTRANSFERNONBLOCKING_ID, FCIIC_E_PARAM_NULLPTR); } else if ((pFciicMasterHandle->eInstance >= FCIIC_INSTANCE_COUNT)) { FCIIC_ReportDevError(FCIIC_MASTERTRANSFERNONBLOCKING_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif if ((NULL != pFciicMasterHandle) && (NULL != transfer) && (pFciicMasterHandle->eInstance < FCIIC_INSTANCE_COUNT)) { pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicMasterHandle->eInstance]; if (pFciicMasterHandle->tStatus.bUsed == true) { result = FCIIC_BUSY; } else { result = FCIIC_MasterCheckForBusyBus(pFciicMasterHandle); if ((result == FCIIC_SUCCESS) && (FCIIC_CH_IDLE == pFciicMasterHandle->tStatus.eChannelStatus)) { /* Clear FIFO. */ FCIIC_HWA_MasterResetFIFO(pFciic); /* Clear all flags. */ FCIIC_HWA_MasterClearStatusFlags(pFciic, FCIIC_MasterClearFlags); pFciicMasterHandle->tStatus.bUsed = true; pFciicMasterHandle->tStatus.eDirection = transfer->eDirection; pFciicMasterHandle->tSettings.pData = transfer->pData; pFciicMasterHandle->tStatus.u16DataSize = transfer->u16DataSize; pFciicMasterHandle->tStatus.u16DataOffset = 0; pFciicMasterHandle->tStatus.u8CmdSize = 0; pFciicMasterHandle->tStatus.u8CmdOffset = 0; FCIIC_MasterGenerateStartCommand(pFciicMasterHandle, transfer); if (FCIIC_READ == pFciicMasterHandle->tStatus.eDirection) { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_START_READ; } else { pFciicMasterHandle->tStatus.eChannelStatus = FCIIC_CH_START_WRITE; } FCIIC_HWA_MasterEnableInterrupts(pFciic, FCIIC_MasterIrqFlags); } } } else { result = FCIIC_FAIL; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Initializes the I2C Slave mode. * * Configures the I2C interface for slave mode operation according to the parameters provided. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave Handle. * @param[in] pInitReg Pointer to the `FCIIC_SlaveConfigType` structure containing the initialization settings. * @return void */ void FCIIC_SlaveInit(FCIIC_SlaveHandleType *const pFciicSlaveHandle, const FCIIC_SlaveConfigType *pInitReg) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle || NULL == pInitReg) { FCIIC_ReportDevError(FCIIC_SLAVEINIT_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif uint32 u32TempScr, u32TempScfgr1, u32TempScfgr2, u32TempSamr, u32TempSder; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; u32TempScr = FCIIC_SCR_SEN(pInitReg->bEnableSlave) | FCIIC_SCR_RST(0U) | FCIIC_SCR_FILTEN(pInitReg->bI2cSlaveFilterEnable); u32TempSder = FCIIC_SDER_TDDE(pInitReg->bUsedDMA) | FCIIC_SDER_RDDE(pInitReg->bUsedDMA) | FCIIC_SDER_AVDE(0U); u32TempSamr = FCIIC_SAMR_ADDR1(0U) | FCIIC_SAMR_ADDR0(pInitReg->slaveAddress); u32TempScfgr1 = FCIIC_SCFGR1_ADDRCFG(pInitReg->u8AddrCfg) | FCIIC_SCFGR1_HSMEN(0U) | FCIIC_SCFGR1_IGNACK(0U) | FCIIC_SCFGR1_RXCFG(0U) | FCIIC_SCFGR1_TXCFG(0U) | FCIIC_SCFGR1_SAEN(0U) | FCIIC_SCFGR1_GCEN(0U) | FCIIC_SCFGR1_ACKSTALL(pInitReg->bI2cSlaveAckStall) | FCIIC_SCFGR1_TXDSTALL(pInitReg->bI2cSlaveTxStall) | FCIIC_SCFGR1_RXSTALL(pInitReg->bI2cSlaveRxStall) | FCIIC_SCFGR1_ADRSTALL(pInitReg->bI2cSlaveAdrStall); u32TempScfgr2 = FCIIC_SCFGR2_FILTSDA(pInitReg->u8SdaGlitchFilterWidth) | FCIIC_SCFGR2_FILTSCL(pInitReg->u8SclGlitchFilterWidth) | FCIIC_SCFGR2_DATAVD(pInitReg->u32PinLowTimeout) | FCIIC_SCFGR2_CLKHOLD(pInitReg->u32BusIdleTimeout); FCIIC_HWA_SetSCR(pFciic, u32TempScr); FCIIC_HWA_SetSDER(pFciic, u32TempSder); FCIIC_HWA_SetSCFGR1(pFciic, u32TempScfgr1); FCIIC_HWA_SetSCFGR2(pFciic, u32TempScfgr2); FCIIC_HWA_SetSAMR(pFciic, u32TempSamr); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Start listen in IIC Slave mode. * * * @param[in] pFciicSlaveHandle Pointer to the slave handle structure. * @param[in] transfer Pointer to the I2C transfer parameters. * * @return FCIIC_StatusType indicating the status of the operation. */ FCIIC_StatusType FCIIC_Slavelistening(FCIIC_SlaveHandleType *const pFciicSlaveHandle, FCIIC_SlaveTransferType *const transfer) { FCIIC_StatusType eRetType = FCIIC_FAIL; uint32 u32I2cSlaveDmaStatus, u8CurChSts; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle || NULL == transfer) { FCIIC_ReportDevError(FCIIC_SLAVEINIT_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif if ((NULL != pFciicSlaveHandle) && (NULL != transfer)) { pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; u8CurChSts = FCIIC_HWA_GetSSR(pFciic); eRetType = FCIIC_SlaveCheckForBusyBus(pFciicSlaveHandle); eRetType |= FCIIC_SlaveCheckAndClearError(pFciicSlaveHandle, u8CurChSts); if ((FCIIC_SUCCESS == eRetType) && (FCIIC_CH_IDLE == pFciicSlaveHandle->tStatus.eChannelStatus)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_LISTENING; pFciicSlaveHandle->tStatus.u16DataSize = transfer->u16DataSize; pFciicSlaveHandle->tSettings.pData = transfer->pData; pFciicSlaveHandle->tStatus.u16DataOffset = 0; pFciicSlaveHandle->tStatus.curSubaddressSize = 0; pFciicSlaveHandle->tStatus.subaddressSize = transfer->subaddressSize; FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_TREIE | FCIIC_SIER_BEIE); u32I2cSlaveDmaStatus = FCIIC_HWA_GetSDER(pFciic); /* DMA Priority*/ if ((u32I2cSlaveDmaStatus == (uint32)0x0u) && ((NULL == pFciicSlaveHandle->tSettings.pFciicTxDmaConfig) && (NULL == pFciicSlaveHandle->tSettings.pFciicRxDmaConfig))) { eRetType = FCIIC_SlaveTransferNonBlocking(pFciicSlaveHandle); } else if ((u32I2cSlaveDmaStatus == (uint32)0x3u) && ((NULL != pFciicSlaveHandle->tSettings.pFciicTxDmaConfig) && (NULL != pFciicSlaveHandle->tSettings.pFciicRxDmaConfig))) { eRetType = FCIIC_SlaveTransferDMA(pFciicSlaveHandle); } else { eRetType = FCIIC_FAIL; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { if (NULL != pFciicSlaveHandle->tSettings.pErrorCallback) { pFciicSlaveHandle->tSettings.pErrorCallback(pFciicSlaveHandle); } pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; } } else { eRetType = FCIIC_FAIL; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return eRetType; } /** * @brief Deinitializes the FCIIC slave configuration. * * This function resets the FCIIC slave peripheral to its default state. * It disables the FCIIC slave, clears all registers, and disables interrupts. * * @param pFciicSlaveHandle Pointer to the FCIIC slave handle structure. */ void FCIIC_SlaveDeInit(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEDEINIT_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEDEINIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif uint32 u32PccCgcMask = 0x800000U; uint32 u32PccSelMask = 0x700000U; uint32 u32PccBase = 0x40024000U; uint32 u32IICPccRegOffset[2] = {0x198U, 0x41CU}; FCIIC_Type *const pFciic = s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; uint32 u32TempScr, u32TempSder, u32TempPcc; u32TempScr = FCIIC_SCR_FILTEN(0U) | FCIIC_SCR_RST(0U) | FCIIC_SCR_SEN(0U); /* slave enable */ u32TempSder = FCIIC_SDER_AVDE(0U) | FCIIC_SDER_RDDE(0U) | FCIIC_SDER_TDDE(0U); FCIIC_Slave_HWA_DisableInterrupt(pFciic, FCIIC_SIER_MASK); FCIIC_HWA_SetSDER(pFciic, u32TempSder); /* PRQA S 0306 ++ #Misra-C:2012 Rule-11.4 A conversion should not be performed between a pointer to object and an integer type * Reason: Pointer to register addressing map operation could not be avoid */ u32TempPcc = *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicSlaveHandle->eInstance])); /* Disable PCC gate */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicSlaveHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccCgcMask)); /* Disable function clock */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicSlaveHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccSelMask)); FCIIC_HWA_SetSCR(pFciic, FCIIC_SCR_RST(1U)); FCIIC_HWA_SetSCR(pFciic, u32TempScr); /* Disable PCC gate */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicSlaveHandle->eInstance])) = (uint32)(u32TempPcc & (~u32PccCgcMask)); /* Recover function clock */ *((volatile uint32 *)(u32PccBase + u32IICPccRegOffset[pFciicSlaveHandle->eInstance])) = u32TempPcc; /* PRQA S 0306 -- */ #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Deinitializes the FCIIC slave handle. * * This function resets the FCIIC slave handle to its default state. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. */ void FCIIC_SlaveDeinitHandle(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEDEINITHANDLE_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif pFciicSlaveHandle->tStatus.u16DataSize = 0; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicSlaveHandle->tSettings.pData = NULL; pFciicSlaveHandle->tStatus.u16DataOffset = 0; pFciicSlaveHandle->tStatus.bUsed = false; pFciicSlaveHandle->tStatus.eRunStatus = FCIIC_SUCCESS; pFciicSlaveHandle->tStatus.subaddressSize = 0; pFciicSlaveHandle->tStatus.u32CurSubaddress = 0; pFciicSlaveHandle->tStatus.u32Subaddress = 0; pFciicSlaveHandle->tSettings.pCallback = NULL; pFciicSlaveHandle->tSettings.pUserData = NULL; pFciicSlaveHandle->tSettings.pErrorCallback = NULL; pFciicSlaveHandle->tSettings.pFciicTxDmaConfig = NULL; pFciicSlaveHandle->tSettings.pFciicRxDmaConfig = NULL; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Sends an ACK/NACK signal in IIC Slave mode. * * This function sends an ACK or NACK signal based on the input parameter. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[in] bAck Boolean flag to indicate whether to send ACK (true) or NACK (false). */ void FCIIC_SlaveAck(FCIIC_SlaveHandleType *const pFciicSlaveHandle, boolean bAck) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEACK_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; if ((boolean)TRUE == bAck) { FCIIC_Slave_HWA_NACK(pFciic, FCIIC_STAR_TXNACK(0U)); } else { FCIIC_Slave_HWA_NACK(pFciic, FCIIC_STAR_TXNACK(1U)); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Clears the I2C slave status flag state. * * This function clears the status flags of the I2C slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. */ void FCIIC_SlaveClrStatus(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVECLRSTATUS_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_MASK); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Gets the slave SSR status. * * This function retrieves the current status of the slave SSR register. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * * @return The current SSR status as a 32-bit unsigned integer. */ uint32_t FCIIC_SlaveGetStatus(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { uint32_t u32Status = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEGETSTATUS_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; u32Status = FCIIC_HWA_GetSSR(pFciic); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return u32Status; } /** * @brief Enables the interrupt for the specified FCIIC Slave instance. * * This function configures the interrupt system to handle non-blocking transfers for the given FCIIC Slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[in] pCallback Pointer to a callback function that will be invoked when a non-blocking transfer completes. * @param[in] pErrorCallBack Pointer to a callback function that will be invoked when an error occurs. * @param[in] pUserData Pointer to user-defined data that will be passed back to the callback function when it is called. */ void FCIIC_SlaveEnableInterrupt(FCIIC_SlaveHandleType *const pFciicSlaveHandle, FCIIC_SlaveTransfer_CallbackType pCallback, FCIIC_SlaveError_CallBackType pErrorCallBack, void *pUserData) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEENABLEINTERRUPT_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif pFciicSlaveHandle->tSettings.pCallback = pCallback; pFciicSlaveHandle->tSettings.pUserData = pUserData; pFciicSlaveHandle->tSettings.pErrorCallback = pErrorCallBack; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Checks if the FCIIC bus is busy. * * This function determines if the FCIIC bus is currently busy. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * * @return FCIIC_StatusType indicating the bus status. */ FCIIC_StatusType FCIIC_SlaveCheckForBusyBus(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { FCIIC_StatusType ret = FCIIC_SUCCESS; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEGETSTATUS_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; uint32_t status = FCIIC_HWA_GetSSR(pFciic); if (0U != (status & (uint32_t)FCIIC_SSR_BBF)) { ret = FCIIC_BUSY; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return ret; } /** * @brief Checks for and clears I2C Slave errors. * * This function checks the provided status register for any I2C Slave errors and clears them. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[in] status The current status register value. * * @return FCIIC_StatusType indicating the encountered error or FCIIC_SUCCESS if no error is found. */ FCIIC_StatusType FCIIC_SlaveCheckAndClearError(FCIIC_SlaveHandleType *const pFciicSlaveHandle, uint32_t status) { FCIIC_StatusType result = FCIIC_SUCCESS; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVECHECKANDCLEARERROR_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; status &= (uint32_t)FCIIC_SlaveErrorFlags; if (0U != status) { /* Select the correct error code. Ordered by severity, with bus issues first. */ if (0U != (status & (uint32_t)FCIIC_SSR_TREF)) { result = FCIIC_TRAMSMITORRECEIVEERROR; } else if (0U != (status & (uint32_t)FCIIC_SSR_BEF)) { result = FCIIC_BITERROR; } else { } } /* Clear the flags. */ FCIIC_Slave_HWA_ClrStatus(pFciic, status); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Sets the default configuration for the I2C Slave. * * This function sets the default configuration parameters for the I2C Slave. * * @param[in] slaveConfig Pointer to the configuration structure. * @param[in] bUsedDMA Boolean flag indicating whether DMA is used. */ void FCIIC_SlaveGetDefaultConfig(FCIIC_SlaveConfigType *const slaveConfig, boolean bUsedDMA) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == slaveConfig) { FCIIC_ReportDevError(FCIIC_SLAVEGETDEFAULTCONFIG_ID, FCIIC_E_PARAM_NULLPTR); } else { #endif slaveConfig->bEnableSlave = true; /*!< Enables Slave mode if set to true. */ slaveConfig->bI2cSlaveFilterEnable = false; /*!< Enables Slave mode if set to true. */ slaveConfig->bUsedDMA = bUsedDMA; slaveConfig->u8AddrCfg = 0; slaveConfig->bI2cSlaveAdrStall = false; slaveConfig->bI2cSlaveAckStall = false; slaveConfig->bI2cSlaveTxStall = false; slaveConfig->bI2cSlaveRxStall = false; slaveConfig->u32BusIdleTimeout = 0U; /*!< Bus idle timeout in nanoseconds. Set to 0 to disable timeout. */ slaveConfig->u32PinLowTimeout = 0; /*!< Pin low timeout in nanoseconds. Set to 0 to disable timeout. */ slaveConfig->u8SdaGlitchFilterWidth = 0; /*!< Width of the SDA glitch filter in nanoseconds. Set to 0 to disable. */ slaveConfig->u8SclGlitchFilterWidth = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Receives data in IIC Slave mode. * * This function receives data when polling (not used when RX interrupt is enabled) in Slave mode. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[out] pData Pointer to the data buffer where the received data will be stored. * * @return 0 if fail, non-zero otherwise. */ uint8_t FCIIC_SlaveReceive(FCIIC_SlaveHandleType *const pFciicSlaveHandle, uint8_t *pData) { uint8_t u8RetVal = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVERECEIVE_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVERECEIVE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; /* check slave receive flag */ u8RetVal = FCIIC_Slave_HWA_GetStatus(pFciic, FCIIC_SSR_RDF_STATUS); /* u8RetVal = (pFciic->MRDR & FCIIC_MRDR_RXEMPTY_MASK)>>FCIIC_MRDR_RXEMPTY_SHIFT; */ if (u8RetVal != 0U) { /* get received data */ (*pData) = FCIIC_Slave_HWA_Receive(pFciic); } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return u8RetVal; } /** * @brief Gets the slave error value. * * This function retrieves the current error value of the slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * * @return The current error value as a 32-bit unsigned integer. */ uint32_t FCIIC_SlaveGetError(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { uint32_t u32RetVal = 0; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEGETERROR_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEGETERROR_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic; pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; /* check receive flag */ u32RetVal = FCIIC_Slave_HWA_GetErrorFlag(pFciic); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return u32RetVal; } /** * @brief Clears the slave error value. * * This function clears the error value of the slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. */ void FCIIC_SlaveClrError(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVECLRERROR_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVECLRERROR_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic; pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; /* clear receive flag */ FCIIC_Slave_HWA_ClrErrorFlag(pFciic); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Gets the current direction of the slave. * * This function retrieves the current direction (read/write) of the slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * * @return The current direction as an FCIIC_DirectionType enum value. */ FCIIC_DirectionType FCIIC_SlaveGetDir(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { FCIIC_DirectionType direction = FCIIC_DIRNOCONFIG; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEGETDIR_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEGETDIR_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; direction = (FCIIC_DirectionType)(FCIIC_HWA_GetSASR(pFciic) & 0x1); #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return direction; } /** * @brief Processes the IIC Slave AM0F interrupt. * * This function processes the Address Match 0 Flag interrupt for the IIC Slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[in] u32IsrStatus The status of the SSR flags. */ void FCIIC_SlaveInterruptProcessAddressMatch(FCIIC_SlaveHandleType *const pFciicSlaveHandle, uint32 u32IsrStatus) { (void)u32IsrStatus; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSADDRESSMATCH_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSADDRESSMATCH_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; FCIIC_ChannelStatusType u8CurChSts; uint32 u32I2cSlaveDmaStatus = FCIIC_HWA_GetSDER(pFciic); uint32 u32Raddr = FCIIC_HWA_GetSASR(pFciic); uint32 u32SlaveStatus = FCIIC_HWA_GetSSR(pFciic); u8CurChSts = pFciicSlaveHandle->tStatus.eChannelStatus; /*subAddressSize !=0x00u,only support Interrupt*/ if (((uint8)0X0U != pFciicSlaveHandle->tStatus.subaddressSize) && ((uint32)0x0U == u32I2cSlaveDmaStatus)) { /*firstly match device address when the master want to read and */ if ((FCIIC_CH_LISTENING == u8CurChSts) && (pFciicSlaveHandle->tStatus.curSubaddressSize != pFciicSlaveHandle->tStatus.subaddressSize) && (0 == (u32SlaveStatus & FCIIC_SSR_RSF_MASK))) { if ((FCIIC_WRITE == (u32Raddr & FCIIC_DIR_MASK))) { FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_RDIE_MASK); FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_LISTENING_READ; } else { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_SENDING; if ((NULL != pFciicSlaveHandle->tSettings.pSubAddressSendingCallback)) { pFciicSlaveHandle->tSettings.pSubAddressSendingCallback(pFciicSlaveHandle); } uint16 u16CurIdx = pFciicSlaveHandle->tStatus.u16DataOffset; FCIIC_Slave_HWA_Transmit(pFciic, pFciicSlaveHandle->tSettings.pData[u16CurIdx]); pFciicSlaveHandle->tStatus.u16DataOffset++; FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_TDIE_MASK); } } /*secondly match adddress when the master read and subAddressSize more than 0*/ else if ((FCIIC_CH_LISTENING_READ == u8CurChSts) && (pFciicSlaveHandle->tStatus.curSubaddressSize == pFciicSlaveHandle->tStatus.subaddressSize) && (0 != (u32SlaveStatus & FCIIC_SSR_RSF_MASK))) { FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_RSF_STATUS); if (FCIIC_READ == (u32Raddr & FCIIC_DIR_MASK)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_SENDING; FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); if ((NULL != pFciicSlaveHandle->tSettings.pSubAddressSendingCallback)) { pFciicSlaveHandle->tSettings.pSubAddressSendingCallback(pFciicSlaveHandle); } uint16 u16CurIdx = pFciicSlaveHandle->tStatus.u16DataOffset; FCIIC_Slave_HWA_Transmit(pFciic, pFciicSlaveHandle->tSettings.pData[u16CurIdx]); pFciicSlaveHandle->tStatus.u16DataOffset++; FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_TDIE_MASK); } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_FIFOERROR; FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_STATEMACHINEERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } /*subAddressSize ==0x00u,for support Interrupt*/ else if (((uint32)0x0U == u32I2cSlaveDmaStatus) && ((uint8)0X0U == pFciicSlaveHandle->tStatus.subaddressSize)) { /*slave interrupt and subAddressSize=0 */ if ((FCIIC_CH_LISTENING == u8CurChSts || FCIIC_CH_IDLE == u8CurChSts)) { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); if ((FCIIC_READ == (u32Raddr & FCIIC_DIR_MASK))) { FCIIC_Slave_HWA_Transmit(pFciic, pFciicSlaveHandle->tSettings.pData[pFciicSlaveHandle->tStatus.u16DataOffset]); pFciicSlaveHandle->tStatus.u16DataOffset++; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_SENDING; FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_TDIE_MASK); } else if ((FCIIC_WRITE == (u32Raddr & FCIIC_DIR_MASK))) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_RECEIVING; FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_RDIE_MASK); } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_STATEMACHINEERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); } } /*unknown error */ else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes the IIC Slave RDF interrupt. * * This function processes the Receive Data Flag interrupt for the IIC Slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC slave handle structure. * @param[in] u8CurChSts The status of the SSR flags. */ void FCIIC_SlaveInterruptProcessReceive(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSRECEIVE_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSRECEIVE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; uint16 u16CurIdx; uint8 u8SubAddrTotalLen; uint8 u8SubAddrCurIdx; uint8 u8ShiftWidth; uint8 u8Data; u8SubAddrTotalLen = pFciicSlaveHandle->tStatus.subaddressSize; u8SubAddrCurIdx = pFciicSlaveHandle->tStatus.curSubaddressSize; u16CurIdx = pFciicSlaveHandle->tStatus.u16DataOffset; if (0x0U != pFciicSlaveHandle->tStatus.subaddressSize) { /*If the subaddress is fully received, change the state machine to FCIIC_CH_RECEIVING to prepare to send data */ if ((FCIIC_CH_LISTENING_READ == pFciicSlaveHandle->tStatus.eChannelStatus) && (pFciicSlaveHandle->tStatus.curSubaddressSize == pFciicSlaveHandle->tStatus.subaddressSize)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_RECEIVING; if ((NULL != pFciicSlaveHandle->tSettings.pSubAddressReceivingCallback)) { pFciicSlaveHandle->tSettings.pSubAddressReceivingCallback(pFciicSlaveHandle); } } /*receive subAddress data*/ if ((FCIIC_CH_LISTENING_READ == pFciicSlaveHandle->tStatus.eChannelStatus) && (u8SubAddrCurIdx < u8SubAddrTotalLen)) { if(pFciicSlaveHandle->tStatus.curSubaddressSize == 0x0U) { pFciicSlaveHandle->tStatus.u32CurSubaddress = 0x0U; } u8ShiftWidth = (uint8)((u8SubAddrTotalLen - u8SubAddrCurIdx - (uint8) 0X1U) << 0x3U); u8Data = FCIIC_Slave_HWA_Receive(pFciic); pFciicSlaveHandle->tStatus.u32CurSubaddress |= (uint32)(u8Data << u8ShiftWidth); pFciicSlaveHandle->tStatus.curSubaddressSize = (uint8)(pFciicSlaveHandle->tStatus.curSubaddressSize + 1u); FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); } /*receive data */ else if ((FCIIC_CH_RECEIVING == pFciicSlaveHandle->tStatus.eChannelStatus) && (u8SubAddrCurIdx == u8SubAddrTotalLen)) { u16CurIdx = pFciicSlaveHandle->tStatus.u16DataOffset; FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); if (u16CurIdx < pFciicSlaveHandle->tStatus.u16DataSize) { pFciicSlaveHandle->tSettings.pData[u16CurIdx] = FCIIC_Slave_HWA_Receive(pFciic); pFciicSlaveHandle->tStatus.u16DataOffset = (uint16)(u16CurIdx + 1u); } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_OVERFLOWERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; (void)FCIIC_Slave_HWA_Receive(pFciic); FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); } } else { if ((FCIIC_CH_RECEIVING == pFciicSlaveHandle->tStatus.eChannelStatus)) { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); if (u16CurIdx < pFciicSlaveHandle->tStatus.u16DataSize) { pFciicSlaveHandle->tSettings.pData[u16CurIdx] = FCIIC_Slave_HWA_Receive(pFciic); pFciicSlaveHandle->tStatus.u16DataOffset = (uint16)(u16CurIdx + 1u); } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_OVERFLOWERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; (void)FCIIC_Slave_HWA_Receive(pFciic); FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes IIC Slave TDF interrupt. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_SlaveInterruptProcessTransmit(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSTRANSMIT_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSTRANSMIT_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; uint16 u16CurIdx = pFciicSlaveHandle->tStatus.u16DataOffset; if ((FCIIC_CH_SENDING == pFciicSlaveHandle->tStatus.eChannelStatus)) { if (u16CurIdx <= pFciicSlaveHandle->tStatus.u16DataSize) { FCIIC_Slave_HWA_Transmit(pFciic, pFciicSlaveHandle->tSettings.pData[u16CurIdx]); pFciicSlaveHandle->tStatus.u16DataOffset = (uint16)(u16CurIdx + 1u); } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_OVERFLOWERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { FCIIC_Slave_HWA_Transmit(pFciic, 0x00); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_STATEMACHINEERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Processes IIC Slave SDF interrupt. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_SlaveInterruptProcessStop(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSSTOP_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEINTERRUPTPROCESSSTOP_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; FCIIC_ChannelStatusType eChannelStatus = pFciicSlaveHandle->tStatus.eChannelStatus; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_SDF_STATUS); if (eChannelStatus == FCIIC_CH_SENDING || eChannelStatus == FCIIC_CH_RECEIVING) { /*Interrupt receive Successfully*/ pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } else { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_STATEMACHINEERROR; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if ((FCIIC_CH_TRANSFER_FINISHED == pFciicSlaveHandle->tStatus.eChannelStatus)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicSlaveHandle->tStatus.eRunStatus = FCIIC_SUCCESS; FCIIC_Slave_HWA_DisableInterrupt(pFciic, FCIIC_SIER_RDIE | FCIIC_SIER_TDIE); if (0 != pFciicSlaveHandle->tStatus.subaddressSize) { pFciicSlaveHandle->tSettings.pData = NULL; pFciicSlaveHandle->tStatus.curSubaddressSize = 0; } if (NULL != pFciicSlaveHandle->tSettings.pCallback) { pFciicSlaveHandle->tSettings.pCallback(pFciicSlaveHandle); } } else { if (NULL != pFciicSlaveHandle->tSettings.pErrorCallback) { pFciicSlaveHandle->tSettings.pErrorCallback(pFciicSlaveHandle); } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief I2C Slave Interrupt Service Routine (ISR). * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_LL_SlaveIRQnHandler(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (pFciicSlaveHandle == NULL) { FCIIC_ReportDevError(FCIIC_LL_SLAVEIRQNHANDLER_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_LL_SLAVEIRQNHANDLER_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif uint32_t u8CurChSts, u32I2cSlaveDmaStatus; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; uint32_t u32ErrorValue; u8CurChSts = FCIIC_HWA_GetSSR(pFciic); u8CurChSts &= FCIIC_HWA_GetSIER(pFciic); u32I2cSlaveDmaStatus = FCIIC_HWA_GetSDER(pFciic); if (0 != (u8CurChSts & FCIIC_SlaveErrorFlags)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } else if (((uint32_t)0x03 != u32I2cSlaveDmaStatus)) { if (0 != (u8CurChSts & FCIIC_SSR_AM0F)) { FCIIC_SlaveInterruptProcessAddressMatch(pFciicSlaveHandle, u8CurChSts); } else if ((0 != (u8CurChSts & FCIIC_SSR_RDF))) { FCIIC_SlaveInterruptProcessReceive(pFciicSlaveHandle); } else if ((0 != (u8CurChSts & FCIIC_SSR_TDF))) { FCIIC_SlaveInterruptProcessTransmit(pFciicSlaveHandle); } else if ((0 != (u8CurChSts & FCIIC_SSR_SDF))) { FCIIC_SlaveInterruptProcessStop(pFciicSlaveHandle); } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else if ((u32I2cSlaveDmaStatus==0x03)&&((NULL != pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->pDmaHandle)) && (NULL != pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->pDmaHandle)) { if (0 != (u8CurChSts & FCIIC_SSR_AM0F)) { FCIIC_SlaveStartDMA(pFciicSlaveHandle); } else if (0 != (u8CurChSts & FCIIC_SSR_SDF)) { FCIIC_SlaveDMAStageNotification(pFciicSlaveHandle); } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if (FCIIC_CH_ERROR_PRESENT == pFciicSlaveHandle->tStatus.eChannelStatus) { u32ErrorValue = FCIIC_SlaveGetError(pFciicSlaveHandle); if ((u32ErrorValue != 0U)) { FCIIC_SlaveClrError(pFciicSlaveHandle); } if ((NULL != pFciicSlaveHandle->tSettings.pErrorCallback)) { pFciicSlaveHandle->tSettings.pErrorCallback(pFciicSlaveHandle); } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Starts accepting slave transfers in non-blocking mode. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. * * @return FCIIC_StatusType Status indicating whether the start was successful. */ FCIIC_StatusType FCIIC_SlaveTransferNonBlocking(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { FCIIC_StatusType result = FCIIC_SUCCESS; FCIIC_Type *pFciic; #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVETRANSFERNONBLOCKING_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVETRANSFERNONBLOCKING_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif if ((NULL != pFciicSlaveHandle) && (pFciicSlaveHandle->eInstance < FCIIC_INSTANCE_COUNT)) { pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; if (true == pFciicSlaveHandle->tStatus.bUsed) /* Check if the I2C bus is idle - if not return busy status. */ { result = FCIIC_BUSY; } else { pFciicSlaveHandle->tStatus.bUsed = true; FCIIC_Slave_HWA_DisableInterrupt(pFciic, FCIIC_SlaveIrqFlags); FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SlaveClearFlags); FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_AM0IE | FCIIC_SIER_SDIE); /* Enable I2C internal IRQ sources */ pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_LISTENING; } } else { result = FCIIC_FAIL; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return result; } /** * @brief Prepares DMA configuration for IIC Slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_SlaveDmaPrepare(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEDMAPREPARE_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEDMAPREPARE_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif DMA_HandleType *pDmaHandle = NULL; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; DMA_ChannelCfgType FCIIC_DmaChannelAttr = {0}; FCIIC_DmaChannelAttr.eSrcDataSize = DMA_TRANSFER_SIZE_1B; FCIIC_DmaChannelAttr.eDestDataSize = DMA_TRANSFER_SIZE_1B; FCIIC_DmaChannelAttr.u32BlockSize = (uint32_t)0x1u; FCIIC_DmaChannelAttr.u16BlockCount = (uint16_t)pFciicSlaveHandle->tStatus.u16DataSize; FCIIC_DmaChannelAttr.bSrcBlockOffsetEn = false; FCIIC_DmaChannelAttr.bDestBlockOffsetEn = false; FCIIC_DmaChannelAttr.s32BlockOffset = 0; FCIIC_DmaChannelAttr.bSrcAddrLoopbackEn = true; FCIIC_DmaChannelAttr.bDestAddrLoopbackEn = false; FCIIC_DmaChannelAttr.bAutoStop = true; FCIIC_DmaChannelAttr.bSrcCircularBufferEn = false; FCIIC_DmaChannelAttr.u32SrcCircBufferSize = 0; FCIIC_DmaChannelAttr.bDestCircularBufferEn = false; FCIIC_DmaChannelAttr.u32DestCircBufferSize = 0; FCIIC_DmaChannelAttr.bTransferCompleteIntEn = true; FCIIC_DmaChannelAttr.bTransferErrorIntEn = false; FCIIC_DmaChannelAttr.pTransferErrorNotify = NULL; FCIIC_DmaChannelAttr.completedata = NULL; FCIIC_DmaChannelAttr.errdata = NULL; if (NULL != pFciicSlaveHandle->tSettings.pFciicTxDmaConfig) { FCIIC_DmaChannelAttr.pSrcBuffer = &(pFciicSlaveHandle->tSettings.pData[0]); FCIIC_DmaChannelAttr.pDestBuffer = &(pFciic->STDR); FCIIC_DmaChannelAttr.eSrcIncMode = DMA_INCREMENT_DATA_SIZE ; FCIIC_DmaChannelAttr.eDestIncMode = DMA_INCREMENT_DISABLE; pDmaHandle = pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->pDmaHandle; FCIIC_DmaChannelAttr.u8ChannelPriority = pDmaHandle->tSettings.u8Channel; FCIIC_DmaChannelAttr.pTransferCompleteNotify = pDmaHandle->tSettings.callback.pTransferCompleteCallback; if (FCIIC_INSTANCE_0 == pFciicSlaveHandle->eInstance) { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC0_TX; } else { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC1_TX; } DMA_InitChannel(pDmaHandle, &FCIIC_DmaChannelAttr); pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } if (NULL != pFciicSlaveHandle->tSettings.pFciicRxDmaConfig) { FCIIC_DmaChannelAttr.pSrcBuffer = &(pFciic->SRDR); FCIIC_DmaChannelAttr.pDestBuffer = &(pFciicSlaveHandle->tSettings.pData[0]); FCIIC_DmaChannelAttr.eSrcIncMode = DMA_INCREMENT_DISABLE ; FCIIC_DmaChannelAttr.eDestIncMode = DMA_INCREMENT_DATA_SIZE; pDmaHandle = pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->pDmaHandle; FCIIC_DmaChannelAttr.u8ChannelPriority = pDmaHandle->tSettings.u8Channel; FCIIC_DmaChannelAttr.pTransferCompleteNotify = pDmaHandle->tSettings.callback.pTransferCompleteCallback; if (FCIIC_INSTANCE_0 == pFciicSlaveHandle->eInstance) { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC0_RX; } else { FCIIC_DmaChannelAttr.eTriggerSrc = DMA_REQ_FCIIC1_RX; } DMA_InitChannel(pDmaHandle, &FCIIC_DmaChannelAttr); pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Initiates an IIC Slave Asynchronous DMA transfer. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. * * @return FCIIC_StatusType Status indicating whether the DMA transfer was successful. */ FCIIC_StatusType FCIIC_SlaveTransferDMA(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVETRANSFERDMA_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVETRANSFERDMA_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; if (true == pFciicSlaveHandle->tStatus.bUsed) /* Check if the I2C bus is idle - if not return busy status. */ { return FCIIC_BUSY; } else { pFciicSlaveHandle->tStatus.bUsed = true; FCIIC_Slave_HWA_DisableInterrupt(pFciic, FCIIC_SlaveIrqFlags); FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SlaveClearFlags); FCIIC_SlaveDmaPrepare(pFciicSlaveHandle); /*When using DMA, the AM0IE interrupt is used to match the address and open the corresponding DMA request, * and then the SDIE interrupt is used to process the logic after the DMA handling is completed.*/ FCIIC_Slave_HWA_EnableInterrupt(pFciic, FCIIC_SIER_AM0IE | FCIIC_SIER_SDIE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_LISTENING; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif return FCIIC_SUCCESS; } /** * @brief Starts DMA for IIC Slave in asynchronous mode. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_SlaveDMAStageNotification(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVEDMASTAGENOTIFICATION_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVEDMASTAGENOTIFICATION_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif DMA_StatusType ret; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; FCIIC_ChannelStatusType eChannelStatus = pFciicSlaveHandle->tStatus.eChannelStatus; FCIIC_DmaConfigType *pFciicRxDmaConfig = pFciicSlaveHandle->tSettings.pFciicRxDmaConfig; FCIIC_DmaConfigType *pFciicTxDmaConfig = pFciicSlaveHandle->tSettings.pFciicTxDmaConfig; DMA_Type *aDma[] = DMA_BASE_PTRS; DMA_Type *const pDma = aDma[pFciicTxDmaConfig->pDmaHandle->tSettings.pInstance->tSettings.u8Instance]; uint32_t u32FciicTxSrcAddr = DMA_HWA_GetSrcAddr(pDma, pFciicTxDmaConfig->pDmaHandle->tSettings.u8Channel); uint32_t u32FciicRxDstAddr = DMA_HWA_GetDestAddr(pDma, pFciicRxDmaConfig->pDmaHandle->tSettings.u8Channel) - pFciicSlaveHandle->tStatus.u16DataSize; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_SDF_STATUS); if ((eChannelStatus == FCIIC_CH_SENDING) && (FCIIC_DMA_NEXT_STAGE_DATA == pFciicTxDmaConfig->u8I2cDmaNextStage)) { /*DMA less send,But more bytes are required to transfer,*/ pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_TREF_STATUS); ret = DMA_ModifyAddress(pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->pDmaHandle, (const volatile void *)pFciicSlaveHandle->tSettings.pData, (const volatile void *)(pFciic->STDR)); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_SLAVEDMANUMBERERROR; } /*DMA less receive,But not all bytes are transferred completely*/ else if ((eChannelStatus == FCIIC_CH_RECEIVING) && (FCIIC_DMA_NEXT_STAGE_DATA == pFciicRxDmaConfig->u8I2cDmaNextStage)) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_TREF_STATUS); ret = DMA_ModifyAddress(pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->pDmaHandle, (const volatile void *)(pFciic->SRDR), (const volatile void *)pFciicSlaveHandle->tSettings.pData); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_SLAVEDMANUMBERERROR; } /*DMA more send error*/ else if ((eChannelStatus == FCIIC_CH_TRANSFER_FINISHED) && (pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage == FCIIC_DMA_NEXT_STAGE_STOP)) { if ((u32FciicTxSrcAddr == ((uint32)pFciicSlaveHandle->tSettings.pData))) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_NOTIFICATION; } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_TREF_STATUS); ret = DMA_ModifyAddress(pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->pDmaHandle, pFciicSlaveHandle->tSettings.pData, (const volatile void *)(pFciic->STDR)); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_SLAVEDMANUMBERERROR; } } /*DMA more receive error*/ else if ((eChannelStatus == FCIIC_CH_TRANSFER_FINISHED) && (pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage == FCIIC_DMA_NEXT_STAGE_STOP)) { if ((u32FciicRxDstAddr == ((uint32)pFciicSlaveHandle->tSettings.pData))) { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_IDLE; pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_NOTIFICATION; } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; FCIIC_Slave_HWA_ClrStatus(pFciic, FCIIC_SSR_TREF_STATUS); pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_SLAVEDMANUMBERERROR; ret = DMA_ModifyAddress(pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->pDmaHandle, (const volatile void *)(pFciic->SRDR), pFciicSlaveHandle->tSettings.pData); } } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if ((ret == DMA_STATUS_BUSY)) { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_DMAREQUESTFAIL; } if ((FCIIC_CH_IDLE == pFciicSlaveHandle->tStatus.eChannelStatus)) { if(pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage == FCIIC_DMA_NEXT_STAGE_NOTIFICATION) { pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } if(pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage == FCIIC_DMA_NEXT_STAGE_NOTIFICATION) { pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_IDLE; } pFciicSlaveHandle->tStatus.bUsed = false; pFciicSlaveHandle->tStatus.eRunStatus = FCIIC_SUCCESS; if (NULL != pFciicSlaveHandle->tSettings.pCallback) { pFciicSlaveHandle->tSettings.pCallback(pFciicSlaveHandle); } } else { if (NULL != pFciicSlaveHandle->tSettings.pErrorCallback) { pFciicSlaveHandle->tSettings.pErrorCallback(pFciicSlaveHandle); } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief Starts DMA for IIC Slave in asynchronous mode. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_SlaveStartDMA(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_SLAVESTARTDMA_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_SLAVESTARTDMA_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif FCIIC_DmaStatusType eDmaNextStage; FCIIC_Type *pFciic = (FCIIC_Type *)s_aFCIIC_InstanceTable[pFciicSlaveHandle->eInstance]; FCIIC_ChannelStatusType eChannelStatus; FCIIC_DirectionType eDirection = (FCIIC_DirectionType)(FCIIC_HWA_GetSASR(pFciic)& FCIIC_DIR_MASK); pFciicSlaveHandle->tStatus.eChannelStatus = eDirection == FCIIC_READ ? FCIIC_CH_LISTENING : FCIIC_CH_LISTENING_READ; eDmaNextStage = FCIIC_READ == eDirection ? pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage : pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage; eChannelStatus = pFciicSlaveHandle->tStatus.eChannelStatus; if ((FCIIC_WRITE == eDirection) && (FCIIC_CH_LISTENING_READ == eChannelStatus) && (eDmaNextStage == FCIIC_DMA_NEXT_STAGE_IDLE)) { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_RECEIVING; pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_DATA; DMA_StartChannel(pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->pDmaHandle); } else if ((FCIIC_READ == eDirection) && (FCIIC_CH_LISTENING == eChannelStatus) && (eDmaNextStage == FCIIC_DMA_NEXT_STAGE_IDLE)) { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)TRUE); pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_SENDING; pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_DATA; DMA_StartChannel(pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->pDmaHandle); } else { FCIIC_SlaveAck(pFciicSlaveHandle, (boolean)FALSE); if(eDmaNextStage != FCIIC_DMA_NEXT_STAGE_IDLE) { pFciicSlaveHandle->tStatus.eRunStatus |= FCIIC_STATEMACHINEERROR; } pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } /** * @brief DMA handler for IIC Slave. * * @param[in] pFciicSlaveHandle Pointer to the FCIIC Slave handle. */ void FCIIC_LL_SlaveDmaIRQnHandler(FCIIC_SlaveHandleType *const pFciicSlaveHandle) { #if FCIIC_DEV_ERROR_REPORT == STD_ON if (NULL == pFciicSlaveHandle) { FCIIC_ReportDevError(FCIIC_LL_SLAVEDMAIRQNHANDLER_ID, FCIIC_E_PARAM_NULLPTR); } else if (pFciicSlaveHandle->eInstance >= FCIIC_INSTANCE_COUNT) { FCIIC_ReportDevError(FCIIC_LL_SLAVEDMAIRQNHANDLER_ID, FCIIC_E_PARAM_INSTANCE); } else { #endif if ((FCIIC_DMA_NEXT_STAGE_DATA == pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage) && (FCIIC_CH_RECEIVING == pFciicSlaveHandle->tStatus.eChannelStatus)) { pFciicSlaveHandle->tSettings.pFciicRxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_STOP; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } else if ((FCIIC_DMA_NEXT_STAGE_DATA == pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage) && (FCIIC_CH_SENDING == pFciicSlaveHandle->tStatus.eChannelStatus)) { pFciicSlaveHandle->tSettings.pFciicTxDmaConfig->u8I2cDmaNextStage = FCIIC_DMA_NEXT_STAGE_STOP; pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_TRANSFER_FINISHED; } else { pFciicSlaveHandle->tStatus.eChannelStatus = FCIIC_CH_ERROR_PRESENT; } if (pFciicSlaveHandle->tStatus.eChannelStatus == FCIIC_CH_ERROR_PRESENT) { FCIIC_SlaveGetError(pFciicSlaveHandle); if ((NULL != pFciicSlaveHandle->tSettings.pErrorCallback)) { FCIIC_SlaveClrError(pFciicSlaveHandle); pFciicSlaveHandle->tSettings.pErrorCallback(pFciicSlaveHandle); } } #if FCIIC_DEV_ERROR_REPORT == STD_ON } #endif } #endif