/*==================================================================================================
*   Project              : RTD AUTOSAR 4.7
*   Platform             : CORTEXM
*   Peripheral           : LPSPI
*   Dependencies         : 
*
*   Autosar Version      : 4.7.0
*   Autosar Revision     : ASR_REL_4_7_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 5.0.0
*   Build Version        : S32K3_RTD_5_0_0_D2408_ASR_REL_4_7_REV_0000_20241002
*
*   Copyright 2020 - 2024 NXP
*
*   NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be
*   used strictly in accordance with the applicable license terms. By expressly
*   accepting such terms or by downloading, installing, activating and/or otherwise
*   using the software, you are agreeing that you have read, and that you agree to
*   comply with and are bound by, such license terms. If you do not agree to be
*   bound by the applicable license terms, then you may not retain, install,
*   activate or otherwise use the software.
==================================================================================================*/
/**
*   @file    Dspi_Ip.c
*   @implements     Dspi_Ip.c_Artifact
*
*   @brief   SPI low-level driver implementations.
*   @details SPI low-level driver implementations.
*
*   @addtogroup DSPI_IP_DRIVER Dspi Ip Driver
*   @{
*/

#ifdef __cplusplus
extern "C"
{
#endif


/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "Mcal.h"
#include "Dspi_Ip.h"
#include "Dspi_Ip_Cfg.h"
#include "OsIf.h"
#if (STD_ON == DSPI_IP_ENABLE)
#if (DSPI_IP_DMA_USED == STD_ON)
    #include "Dma_Ip.h"
    #include "Dma_Ip_Hw_Access.h"
#endif
#if (STD_ON == DSPI_IP_ENABLE_USER_MODE_SUPPORT)
   #define USER_MODE_REG_PROT_ENABLED    (DSPI_IP_ENABLE_USER_MODE_SUPPORT)
   #include "RegLockMacros.h"
#endif
#include "SchM_Spi.h"
#if (STD_ON == DSPI_IP_DEV_ERROR_DETECT)
    #include "Devassert.h"
#endif

/*==================================================================================================
*                                       SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define DSPI_IP_VENDOR_ID_C                      43
#define DSPI_IP_AR_RELEASE_MAJOR_VERSION_C       4
#define DSPI_IP_AR_RELEASE_MINOR_VERSION_C       7
#define DSPI_IP_AR_RELEASE_REVISION_VERSION_C    0
#define DSPI_IP_SW_MAJOR_VERSION_C               5
#define DSPI_IP_SW_MINOR_VERSION_C               0
#define DSPI_IP_SW_PATCH_VERSION_C               0
/*==================================================================================================
*                                     FILE VERSION CHECKS
==================================================================================================*/
#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
    /* Check if current file and Mcal header file are of the same Autosar version */
    #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != MCAL_AR_RELEASE_MAJOR_VERSION) || \
         (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != MCAL_AR_RELEASE_MINOR_VERSION))
    #error "AutoSar Version Numbers of Dspi_Ip.c and Mcal.h are different"
    #endif

    #if (DSPI_IP_DMA_USED == STD_ON)
        /* Check if current file and Dma_Ip header file are of the same Autosar version */
        #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != DMA_IP_AR_RELEASE_MAJOR_VERSION) || \
             (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != DMA_IP_AR_RELEASE_MINOR_VERSION))
        #error "AutoSar Version Numbers of Dspi_Ip.c and Dma_Ip.h are different"
        #endif
    #endif

    #if (STD_ON == DSPI_IP_ENABLE_USER_MODE_SUPPORT)
        #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != REGLOCKMACROS_AR_RELEASE_MAJOR_VERSION) || \
             (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != REGLOCKMACROS_AR_RELEASE_MINOR_VERSION))
        #error "AutoSar Version Numbers of Dspi_Ip.c and RegLockMacros.h are different"
        #endif
    #endif

    /* Check if the current file and SchM_Spi.h header file are of the same version */
    #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != SCHM_SPI_AR_RELEASE_MAJOR_VERSION) || \
         (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != SCHM_SPI_AR_RELEASE_MINOR_VERSION) \
        )
        #error "AutoSar Version Numbers of Dspi_Ip.c and SchM_Spi.h are different"
    #endif

    /* Check if the current file and OsIf.h header file are of the same version */
    #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != OSIF_AR_RELEASE_MAJOR_VERSION) || \
         (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != OSIF_AR_RELEASE_MINOR_VERSION) \
        )
        #error "AutoSar Version Numbers of Dspi_Ip.c and OsIf.h are different"
    #endif
#endif

#if (STD_ON == DSPI_IP_DEV_ERROR_DETECT)
    #ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
        /* Check if Dspi_Ip source file and Devassert.h header file are of the same release version */
        #if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_C != DEVASSERT_AR_RELEASE_MAJOR_VERSION) || \
             (DSPI_IP_AR_RELEASE_MINOR_VERSION_C != DEVASSERT_AR_RELEASE_MINOR_VERSION)    \
            )
            #error "AutoSar Version Numbers of Dspi_Ip.c and Devassert.h are different"
        #endif
    #endif
#endif /* (STD_ON == DSPI_IP_DEV_ERROR_DETECT) */

/* Check if Dspi_Ip.h and Dspi_Ip.c are of the same vendor */
#if (DSPI_IP_VENDOR_ID != DSPI_IP_VENDOR_ID_C)
    #error "Dspi_Ip.h and Dspi_Ip.c have different vendor ids"
#endif
/* Check if Dspi_Ip.h file and Dspi_Ip.c file are of the same Autosar version */
#if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION != DSPI_IP_AR_RELEASE_MAJOR_VERSION_C) || \
     (DSPI_IP_AR_RELEASE_MINOR_VERSION != DSPI_IP_AR_RELEASE_MINOR_VERSION_C) || \
     (DSPI_IP_AR_RELEASE_REVISION_VERSION != DSPI_IP_AR_RELEASE_REVISION_VERSION_C))
#error "AutoSar Version Numbers of Dspi_Ip.h and Dspi_Ip.c are different"
#endif
#if ((DSPI_IP_SW_MAJOR_VERSION != DSPI_IP_SW_MAJOR_VERSION_C) || \
     (DSPI_IP_SW_MINOR_VERSION != DSPI_IP_SW_MINOR_VERSION_C) || \
     (DSPI_IP_SW_PATCH_VERSION != DSPI_IP_SW_PATCH_VERSION_C))
#error "Software Version Numbers of Dspi_Ip.h and Dspi_Ip.c are different"
#endif

/* Check if Dspi_Ip_Cfg.h and Dspi_Ip.c are of the same vendor */
#if (DSPI_IP_VENDOR_ID_CFG != DSPI_IP_VENDOR_ID_C)
    #error "Dspi_Ip_Cfg.h and Dspi_Ip.c have different vendor ids"
#endif
/* Check if Dspi_Ip_Cfg.h file and Dspi_Ip.c file are of the same Autosar version */
#if ((DSPI_IP_AR_RELEASE_MAJOR_VERSION_CFG != DSPI_IP_AR_RELEASE_MAJOR_VERSION_C) || \
     (DSPI_IP_AR_RELEASE_MINOR_VERSION_CFG != DSPI_IP_AR_RELEASE_MINOR_VERSION_C) || \
     (DSPI_IP_AR_RELEASE_REVISION_VERSION_CFG != DSPI_IP_AR_RELEASE_REVISION_VERSION_C))
#error "AutoSar Version Numbers of Dspi_Ip_Cfg.h and Dspi_Ip.c are different"
#endif
#if ((DSPI_IP_SW_MAJOR_VERSION_CFG != DSPI_IP_SW_MAJOR_VERSION_C) || \
     (DSPI_IP_SW_MINOR_VERSION_CFG != DSPI_IP_SW_MINOR_VERSION_C) || \
     (DSPI_IP_SW_PATCH_VERSION_CFG != DSPI_IP_SW_PATCH_VERSION_C))
#error "Software Version Numbers of Dspi_Ip_Cfg.h and Dspi_Ip.c are different"
#endif
/*==================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/
/*==================================================================================================
*                                       LOCAL MACROS
==================================================================================================*/
#if (DSPI_IP_DMA_USED == STD_ON)
/* the maximum of Major loop when Minor loop Channel Linking Disabled */
    #define DSPI_IP_DMA_MAX_ITER_CNT_U16    ((uint16)0x7FFFu)
#endif

/* Maximum value of CTARE[DTCP] */
#define DSPI_IP_CTARE_DTCP_MAX_U16          (DSPI_CTARE_DTCP_MASK >> DSPI_CTARE_DTCP_SHIFT)
/* Pushr CONT mask to be used for CMD field which is uint16  */
#define DSPI_IP_PUSHR_CONT_MASK_U16         ((uint16)(DSPI_PUSHR_CONT_MASK >> 16))
/*  Maximum number of bytes that can be written in a FIFO entry */
#define DSPI_TX_WORD_SIZE                   (DSPI_TXFR_TXDATA_WIDTH / 8U)
/*  Maximum number of bytes that can be read from a FIFO entry */
#define DSPI_RX_WORD_SIZE                   (DSPI_RXFR_RXDATA_WIDTH / 8U)
/*==================================================================================================
*                                       LOCAL CONSTANTS
==================================================================================================*/
#define SPI_START_SEC_CONST_UNSPECIFIED
#include "Spi_MemMap.h"

static DSPI_Type* const Dspi_Ip_apxBases[DSPI_INSTANCE_COUNT] = IP_DSPI_BASE_PTRS;

#define SPI_STOP_SEC_CONST_UNSPECIFIED
#include "Spi_MemMap.h"
/*==================================================================================================
*                                       LOCAL VARIABLES
==================================================================================================*/

#if (DSPI_IP_DMA_USED == STD_ON)
    #define SPI_START_SEC_VAR_CLEARED_32_NO_CACHEABLE
    #include "Spi_MemMap.h"
static uint32 Dspi_Ip_u32DiscardData;
    #define SPI_STOP_SEC_VAR_CLEARED_32_NO_CACHEABLE
    #include "Spi_MemMap.h"
#endif

#define SPI_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Spi_MemMap.h"

static Dspi_Ip_StateStructureType Dspi_Ip_axStateStructure[DSPI_IP_NUMBER_OF_INSTANCES];
static Dspi_Ip_StateStructureType* Dspi_Ip_apxStateStructureArray[DSPI_INSTANCE_COUNT];

#define SPI_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Spi_MemMap.h"

/*==================================================================================================
*                                      GLOBAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
                                    GLOBAL VARIABLES
==================================================================================================*/
/*==================================================================================================
*                                  LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define SPI_START_SEC_CODE
#include "Spi_MemMap.h"

static void Dspi_Ip_TransferProcess(uint8 Instance);

#if (DSPI_IP_DMA_USED == STD_ON)
static void Dspi_Ip_CmdDmaTcdSGInit(uint8 Instance);

#if (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
static void Dspi_Ip_CmdDmaTcdSGConfig(uint8 Instance,
                                      uint8 TCDSGId,
                                      uint32 CmdAdd,
                                      uint16 Iter,
                                      uint8 DisHwReq);

static void Dspi_Ip_DmaFastConfig(uint8 Instance,
                                  const Dspi_Ip_FastTransferType *FastTransferCfg,
                                  uint8 NumberOfTransfer);

static void Dspi_Ip_RxDmaTcdSGConfig(uint8 Instance,
                                     uint8 TCDSGIndex,
                                     uint8 DisHwReq);

static void Dspi_Ip_RxDmaTcdSGInit(uint8 Instance);

static void Dspi_Ip_TxDmaTcdSGConfig(uint8 Instance,
                                     uint8 TCDSGIndex,
                                     uint8 DisHwReq);

static void Dspi_Ip_TxDmaTcdSGInit(uint8 Instance);

#endif /* if (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON) */
#endif /* if (DSPI_IP_DMA_USED == STD_ON) */
#if (STD_ON == DSPI_IP_ENABLE_USER_MODE_SUPPORT)
void Dspi_Ip_SetUserAccess(uint8 Instance);

static void Dspi_Ip_SetUserAccessAllowed(uint8 Instance);

#endif /* DSPI_IP_ENABLE_USER_MODE_SUPPORT */

static void Dspi_Ip_WriteTxFifo(uint16 NumberOfWrites,
                                uint8 Instance);

static void Dspi_Ip_ReceiveData(uint16 NumberOfReads,
                                uint8 Instance);

static void Dspi_Ip_ChannelFinished(uint8 Instance,
                                    boolean ErrorFlag);

#if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
static void Dspi_Ip_CheckValidParameters(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                         uint16 Length,
                                         uint32 TimeOut);

#endif
/*==================================================================================================
*                                      LOCAL FUNCTIONS
==================================================================================================*/
/**
* @brief   Fill CMD FIFO
* @details Write PushrCmds to CMD FIFO
*
* @param[in]     State      State of the current transfer
* @param[in]     Base       Base address of the instance regs to be updated
* @return none
*/
static uint16 Dspi_Ip_WriteCmdFifo(Dspi_Ip_StateStructureType* State,
                                   DSPI_Type *Base)
{
    uint16 NumberOfCmdWrites = 0u;
    uint16 i;

    NumberOfCmdWrites = (uint16)((Base->SREX) & DSPI_SREX_CMDCTR_MASK) >> DSPI_SREX_CMDCTR_SHIFT;
    if (NumberOfCmdWrites <= DSPI_IP_FIFO_SIZE_U16)
    {
        NumberOfCmdWrites = DSPI_IP_FIFO_SIZE_U16 - NumberOfCmdWrites;
    }
    else
    {
        /* Handle hw error on bits. Ceil CMDCTR and calculate result: DSPI_IP_FIFO_SIZE_U16 - DSPI_IP_FIFO_SIZE_U16 */
        NumberOfCmdWrites = 0;
    }
    if (NumberOfCmdWrites > State->ExpectedCmdFifoWrites)
    {
        NumberOfCmdWrites = State->ExpectedCmdFifoWrites;
    }

    for (i = 0; i < NumberOfCmdWrites; i++)
    {
        if (State->Pushr0RepeatIndex < State->Pushr0Repeat)
        {
            State->Pushr0RepeatIndex++;
        }
        else
        {
            State->NbCmdsIndex++;
        }

#if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
        DevAssert(State->NbCmdsIndex < 3u);
#endif
        Base->PUSHR.FIFO.CMD = State->PushrCmds[State->NbCmdsIndex];
        State->ExpectedCmdFifoWrites--;
    }

    return NumberOfCmdWrites;
}

/**
* @brief   This function is called by Dspi_Ip_IrqHandler or Dspi_Ip_ManageBuffers. It will process transfer in interrupt mode and polling mode.
* @details This function will fill data into TX FIFO and read data in RX FIFO fill to Rx Buffers.
*
* @param[in]     Instance      Index of the hardware instance.
*/
static void Dspi_Ip_TransferProcess(uint8 Instance)
{
    DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    uint32 SrStatusRegister;
    uint16 NumberOfReads;
    boolean ErrorFlag = (boolean)FALSE;

    if (DSPI_IP_BUSY == State->Status)
    {
        /* Read Status and clear all flags. */
        SrStatusRegister = Base->SR;
        Base->SR &= 0xFFFF0000u;

        /* DSPI do not support error flag? it will be enabled if those bits are availabe */
        if ((0u != (SrStatusRegister & DSPI_SR_RFOF_MASK)))
        {
            /* mark error flag */
            ErrorFlag = (boolean)TRUE;
        }
        else
        {
            /* Read all data available in receive HW fifo. */
            NumberOfReads = (uint16)(((Base->SR) & DSPI_SR_RXCTR_MASK) >> DSPI_SR_RXCTR_SHIFT);
            if (NumberOfReads > DSPI_IP_FIFO_SIZE_U16)
            {
                NumberOfReads = DSPI_IP_FIFO_SIZE_U16;
            }
            if (NumberOfReads != 0u)
            {
                /* Read data from RX FIFO */
                Dspi_Ip_ReceiveData(NumberOfReads, Instance);
            }

#if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
            if ((boolean)FALSE == State->PhyUnitConfig->SlaveMode)
#endif
            {
                if (State->ExpectedCmdFifoWrites != 0u)
                {
                    (void)Dspi_Ip_WriteCmdFifo(State, Base);
                }
            }

            /* Push data until HW fifo is full or transfer is done. */
            /* After driver code read all frames in RX FIFO, if there are still some frames in TX FIFO, at the time before driver code check number of frames available in TX FIFO to prepare
            to fill TX FIFO. At that time, another interrupt occurred and preemptive current interrupt, and the time to process that interrupt is longer than the time to transfer all frames
            in TX FIFO. So TX FIFO will be empty and some frames received in RX FIFO, then the program is returned from that interrupt and fill TX FIFO until full and exist SPI interrupt function.
            And if there is a interrupt occurred with higher priority of SPI interrupt and the time to process that interrupt is longer than the time to transfer all frames in TX FIFO.
            So, RX FIFO can be overflow due to SPI interrupt function is not serviced to read RX FIFO.
            To avoid this, limitation total of frames in TX FIFO and RX FIFO is lower than FIFO's size(considered that maybe there is an frame on going). */
            if (State->CurrentTxFifoSlot > (State->ExpectedFifoWrites - State->TxIndex))
            {
                State->CurrentTxFifoSlot = State->ExpectedFifoWrites - State->TxIndex;
            }

            if (State->CurrentTxFifoSlot != 0u)
            {
                Dspi_Ip_WriteTxFifo(State->CurrentTxFifoSlot, Instance);
                /* Update current TX FIFO slot can be written */
                State->CurrentTxFifoSlot = 0u;
            }
        }

        /* End of transfer if all of frames are received or has error */
        if ((State->RxIndex == State->ExpectedFifoReads) || ((boolean)TRUE == ErrorFlag))
        {
            /* Only set HALT bit to stop transfer when there is a error or request to de-assert CS at the end of transfers sequence */
            if (((boolean)TRUE == ErrorFlag) || ((boolean)FALSE == State->KeepCs))
            {
                                SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_12();
                                  /* Stop Transfer */
                Base->MCR |= DSPI_MCR_HALT_MASK;
                                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_12();
                              }

            /* Disable interrupts and DMA requests. */
            Base->RSER = 0U;
            /* Channel finished */
            Dspi_Ip_ChannelFinished(Instance, ErrorFlag);
        }
    }
}

static void Dspi_Ip_CalculateFifoWords(uint16 FrameSize,
                                       uint16 NbBytes,
                                       uint16 *Frames,
                                       uint16 *TxBytesPerWord,
                                       uint16 *RxBytesPerWord)
{
    uint16 BytesPerWord;
    uint16 BytesPerFrame;

    /* Calculate value of BytesPerWord and BytesPerFrame based on FrameSize */
    if (FrameSize > 16u)
    {
        BytesPerWord = 4u;
        BytesPerFrame = FrameSize / 32u * BytesPerWord;
        /* E.g. 72-bit frame -> 3 words (32,32,8) bits */
        if (0u != (FrameSize % 32u))
        {
            BytesPerFrame += BytesPerWord;
        }
    }
    else if (FrameSize > 8u)
    {
        BytesPerWord = 2u;
        BytesPerFrame = BytesPerWord;
    }
    else
    {
        BytesPerWord = 1u;
        BytesPerFrame = BytesPerWord;
    }

    *Frames = NbBytes / BytesPerFrame;

    /* Return maximum bytes that fits in TX FIFO */
    if (BytesPerWord < DSPI_TX_WORD_SIZE)
    {
        *TxBytesPerWord = BytesPerWord;
    }
    else
    {
        *TxBytesPerWord = DSPI_TX_WORD_SIZE;
    }

    /* Return by maximum bytes that fits in RX FIFO */
    if (BytesPerWord < DSPI_RX_WORD_SIZE)
    {
        *RxBytesPerWord = BytesPerWord;
    }
    else
    {
        *RxBytesPerWord = DSPI_RX_WORD_SIZE;
    }
}

static void Dspi_Ip_UpdateCtarAndPushr(Dspi_Ip_StateStructureType* State,
                                       DSPI_Type *Base)
{
    const Dspi_Ip_ExternalDeviceType *Dev = State->ExternalDevice;
    uint32 PushrCmd32 = ((uint32)Dev->PushrCmd) << 16u;
    uint16 CtarFrameSize;
    uint16 CtareFrameSize;
    uint32 CtarSrc;
    uint16 i;

#if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State->NbCmds > 0u);
#endif

#if (DSPI_IP_DUAL_CLOCK_MODE == STD_ON)
    CtarSrc = Dev->Ctar[State->ClockMode];
#else
    CtarSrc = Dev->Ctar;
#endif

    CtarFrameSize = (uint16)Dev->DeviceParams->FrameSize - 1u;
    CtareFrameSize = (CtarFrameSize >> 4u) & 0x1u;
#if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
    if (State->PhyUnitConfig->SlaveMode)
    {
        Base->MODE.CTAR_SLAVE[0] = CtarSrc | DSPI_CTAR_SLAVE_FMSZ(CtarFrameSize);
    }
    else
#endif
    {
        for (i = 0u; i < State->NbCmds; i++)
        {
            Base->MODE.CTAR[i] = CtarSrc |
                                 DSPI_CTAR_FMSZ(CtarFrameSize) |
                                 DSPI_CTAR_LSBFE(Dev->DeviceParams->Lsb ? 1u : 0u);
            Base->CTARE[i] = Dev->Ctare |
                             DSPI_CTARE_FMSZE(CtareFrameSize) |
                             DSPI_CTARE_DTCP(State->DTCPValue[i]);
            State->PushrCmds[i] = (uint16)(((PushrCmd32 & (~DSPI_PUSHR_CTAS_MASK)) |
                                            DSPI_PUSHR_CTAS(i)) >> 16u);
        }

        /* Update last pushr to clear CS if needed */
        if ((State->PushrCmds[i - 1u] & DSPI_IP_PUSHR_CONT_MASK_U16) != 0u)
        {
            State->PushrCmds[i - 1u] &= ~DSPI_IP_PUSHR_CONT_MASK_U16;
        }
    }
}

/**
* @brief   Init State and update CTAR, CTARE and PUSHR
* @details DSPI_IP_CTARE_DTCP_MAX_U16  will be repeated the needed number of times.
*          Remaining bytes will be sent with a new DTCP
*          If CONT needs to be used, an other DTCP is configured and the last updated
*          Write CTAR, CTARE and prepare PUSHR values.
*          Prepare PushrCmd values based on DTCPs and CONT.
*
* @param[in]     State      State of the current transfer
* @param[in]     Base       Base address of the instance regs to be updated
* @param[in]     NbBytes    Number of bytes of the transfer
* @return void
*/
static void Dspi_Ip_PrepareTransfer(Dspi_Ip_StateStructureType* State,
                                    DSPI_Type *Base,
                                    uint16 NbBytes)
{
    uint16 Frames;
    uint16 TxBytesPerWord;
    uint16 RxBytesPerWord;

    Dspi_Ip_CalculateFifoWords(State->ExternalDevice->DeviceParams->FrameSize, NbBytes,
                               &Frames, &TxBytesPerWord, &RxBytesPerWord);

    /*
     * How a transfer works using DTCP feature:
     * Transfer is split in up to 3 commands, each one using a different CTAR with its own DTCP value.
     *  Case 1: CS_TOGGLE and Frames < DSPI_IP_CTARE_DTCP_MAX_U16
     *    - CMD0 uses CTAR0 with DTCP = Frames -> One command sends all frames.
     *
     *  Case 2: CS_TOGGLE and Frames > DTCP_MAX
     *    - CMD0 uses CTAR0 with DTCP = DTCP_MAX -> CMD0 is sent until (repeated) remaining frames < DTCP_MAX
     *    - CMD1 uses CTAR1 with DTCP = remaining frames -> CMD1 is sent after all CMD0 are sent to send remaining frames
     *
     *  Case 3: CS_KEEP_ASSERTED and Keep_CS = True and Frames < DSPI_IP_CTARE_DTCP_MAX_U16
     *    - CMD0 uses CTAR0 with DTCP = Frames - 1
     *    - CMD1 uses CTAR1 with DTCP = 1 (Unset CONT bit)
     *
     *  Case 4: CS_KEEP_ASSERTED and Keep_CS = True and Frames > DSPI_IP_CTARE_DTCP_MAX_U16
     *    - CMD0 uses CTAR0 as in case 2
     *    - CMD1 uses CTAR1 with DTCP = remaining frames - 1
     *    - CMD2 uses CTAR2 with DTCP = 1 (Unset CONT bit)
     */
    State->RxIndex = 0u;
    State->TxIndex = 0u;
    State->NbCmdsIndex = 0;
    State->Pushr0RepeatIndex = 0;
    State->NbCmds = 1u;
#if DSPI_IP_SLAVE_SUPPORT == STD_ON
    if ((boolean)FALSE == State->PhyUnitConfig->SlaveMode)
#endif
    {
        if (TRUE == State->KeepCs)
        {
            /* Can't use CTARE[DTCP] if CS is active between transfers.
             * DTCP might be different for the next transfer and CTARE can't be updated
             * in the running state
             */
            State->DTCPValue[0] = 1;
            State->Pushr0Repeat = Frames;
            State->ExpectedCmdFifoWrites = State->Pushr0Repeat;

            if (((State->ExternalDevice->PushrCmd & DSPI_IP_PUSHR_CONT_MASK_U16) != 0u) && (Frames > 1u))
            {
                State->Pushr0Repeat--;
                State->DTCPValue[1] = 1;
                State->NbCmds++;
            }
        }
        else
        {
            if (Frames < DSPI_IP_CTARE_DTCP_MAX_U16)
            {
                /* Max DTCP value is enough to send Frames. Set 1 CMD to be pushed 1 time */
                State->DTCPValue[0] = Frames % DSPI_IP_CTARE_DTCP_MAX_U16;
                State->Pushr0Repeat = 1u;
                State->DTCPValue[1] = 0u;
            }
            else
            {
                /*
                * Max DTCP value is not enough to send Frames
                * Use 2 CMDs:
                *  1: Set DTCP to Max DTCP value. To be pushed Frames / DTCP_MAX times
                *  2: Set DTCP to remaining frames. To be pushed 1 time.
                */
                State->DTCPValue[0] = DSPI_IP_CTARE_DTCP_MAX_U16;
                State->Pushr0Repeat = Frames / DSPI_IP_CTARE_DTCP_MAX_U16;
                State->DTCPValue[1] = Frames % DSPI_IP_CTARE_DTCP_MAX_U16;
                State->NbCmds++;
            }

            /*
            * Split last CMD in 2 if:
            *   - KeepCs and CS Keep asserted are set and
            *   - Last calculated command DTCP is greater then 1.
            * Last CMD DTCP will become DTCP - 1.
            * New CMD is created with DTCP = 1 disabling CONT
            */
            if (State->DTCPValue[State->NbCmds - 1u] > 1u)
            {
                State->DTCPValue[State->NbCmds - 1u]--;
                State->DTCPValue[State->NbCmds] = 1u;
                State->NbCmds++;
            }

            /* Cmd 0 is repeated Pushr0Repeat times and then each cmd 1 time */
            State->ExpectedCmdFifoWrites = State->Pushr0Repeat + State->NbCmds - 1u;
        }
    }

    State->ExpectedFifoWrites = NbBytes / TxBytesPerWord;
    State->ExpectedFifoReads = NbBytes / RxBytesPerWord;

    Dspi_Ip_UpdateCtarAndPushr(State, Base);
}

#if (DSPI_IP_DMA_USED == STD_ON)
/**
* @brief   This function will initialize all software TCDs Scatter Gather for Command DMA channel.
*          And load software TCD Scatter Gather 0 into hardware TCD.
*
* @param[in]     Instance      Index of the hardware instance.
*/
static void Dspi_Ip_CmdDmaTcdSGInit(uint8 Instance)
{
    const DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    const Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelScatterGatherListType DmaTcdList[9u];
    uint8 TCDSGIndex = 0u;

    /* initialze configuration software TCD Scatter Gather for Cmd DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;

    DmaTcdList[0u].Value = 0u; /* dummy src address read, it will be updated later */
    DmaTcdList[1u].Value = (Dma_Ip_uintPtrType)&Base->PUSHR.FIFO.CMD;    /* dest address write*/
    DmaTcdList[2u].Value = 0u;    /* no src offset */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes dest transfer size */
    DmaTcdList[5u].Value = 2u; /* bytes to transfer for each request */
    DmaTcdList[6u].Value = 0u;    /* no dest offset */
    DmaTcdList[7u].Value = 0u;    /* dummy iteration count will be updated later */
    DmaTcdList[8u].Value = 1u;   /* dummy disable hardware request when major loop complete, will be updated latter in the case of Scatter Gather
                                  * enabled */

    for (TCDSGIndex = 0u; TCDSGIndex < State->PhyUnitConfig->NumTxCmdDmaSGId; TCDSGIndex++)
    {
        /* Update software TCD Scatter Gather */
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxCmdDmaChannel, State->PhyUnitConfig->TxCmdDmaSGId[TCDSGIndex], DmaTcdList, 9u);
    }

    /* Load software TCD Scatter Gather 0 into hardware TCD */
    (void)Dma_Ip_SetLogicChannelScatterGatherConfig(State->PhyUnitConfig->TxCmdDmaChannel, State->PhyUnitConfig->TxCmdDmaSGId[0u]);
}

#if (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
static void Dspi_Ip_TxDmaTcdSGInit(uint8 Instance)
{
    const DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    const Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[10u];
    uint8 TCDSGIndex = 0u;

    /* initialze configuration software TCD Scatter Gather for Tx DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[9u].Param = DMA_IP_CH_SET_SOURCE_MODULO;

    DmaTcdList[1u].Value = (Dma_Ip_uintPtrType) & Base->PUSHR.FIFO.TX;    /* dest address write*/
    DmaTcdList[2u].Value = 1u;  /* dummy src offset is 1 byte, will be updated latter according to frame size and transfer default data */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* dummy 1 byte src transfer size, will be updated latter according to frame size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* dummy 1 byte dest transfer size, will be updated latter according to frame size */
    DmaTcdList[5u].Value = 1u;   /* dummy bytes to transfer for each request, will be updated latter according to frame size */
    DmaTcdList[6u].Value = 0u; /* no dest offset */
    DmaTcdList[7u].Value = 0u; /* dummy iteration count, will be updated latter according to number of frames */
    DmaTcdList[8u].Value = 1u; /* dummy disable hardware request when major loop complete, will be updated latter according to last transfer or not */
    DmaTcdList[9u].Value = 0u;  /* dummy no src address modulo, will be updated latter Base on transfer default data or not */
    DmaTcdList[0u].Value = 0u; /* dummy src address read, will be updated latter Base on TxBuffer */

    for (TCDSGIndex = 0u; TCDSGIndex < State->PhyUnitConfig->MaxNumOfFastTransfer; TCDSGIndex++)
    {
        /* Update software TX DMA TCD Scatter Gather */
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxDmaChannel, State->PhyUnitConfig->TxDmaFastSGId[TCDSGIndex], DmaTcdList, 10u);
    }
}

static void Dspi_Ip_TxDmaTcdSGConfig(uint8 Instance,
                                     uint8 TCDSGIndex,
                                     uint8 DisHwReq)
{
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[8u];

    /* Update buffers index */
    State->TxIndex = State->ExpectedFifoWrites;

    /* configure TX DMA TCD Scatter Gather */
    /* No need to configure dest address and dest offset due to they are already set by Dspi_Ip_TxDmaTcdSGInit */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_SOURCE_MODULO;

    if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
    {
        DmaTcdList[1u].Value = 1u;  /* src offset is 1 byte */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[4u].Value = 1u;   /* bytes to transfer for each request */
    }
    else
    {
        DmaTcdList[1u].Value = 2u;  /* src offset is 2 bytes */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[4u].Value = 2u;   /* bytes to transfer for each request */
    }

    DmaTcdList[5u].Value = State->ExpectedFifoWrites; /* iteration count */
    DmaTcdList[6u].Value = DisHwReq; /* disable hardware request when major loop complete */
    DmaTcdList[7u].Value = 0u;  /* no src address modulo */
    if (NULL_PTR == State->TxBuffer)
    {
        /* send default data */
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)&State->PhyUnitConfig->CmdDmaFast[TCDSGIndex].DefaultData; /* src address read */
        if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
        {
            DmaTcdList[1u].Value = 0u;  /* src offset is 0 byte */
        }
        else
        {
            DmaTcdList[7u].Value = 2u;  /* data is 4 bytes, src address modulo is 2 bits */
        }
    }
    else
    {
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)State->TxBuffer; /* src address read */
    }

    /* Update software TX DMA TCD Scatter Gather */
    (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxDmaChannel, State->PhyUnitConfig->TxDmaFastSGId[TCDSGIndex], DmaTcdList, 8u);
}

static void Dspi_Ip_RxDmaTcdSGInit(uint8 Instance)
{
    const DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    const Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[9u];
    uint8 TCDSGIndex = 0u;

    /* initialze configuration software TCD Scatter Gather for Rx DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;

    DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)&Base->POPR; /* src address read */
    DmaTcdList[2u].Value = 0u;  /* no src offset */
    DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* dummy 1 byte src transfer size, will be updated latter Base on frame size */
    DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* dummy 1 byte dest transfer size, will be updated latter Base on frame size */
    DmaTcdList[5u].Value = 1u;   /* dummy 1 byte to transfer for each request, will be updated latter Base on frame size */
    DmaTcdList[6u].Value = 1u; /* dummy dest offset is 1 byte, will be updated latter Base on frame size and discard info */
    DmaTcdList[1u].Value = 0u;    /* dummy dest address write, will be updated latter Base on RxBuffer */
    DmaTcdList[7u].Value = 0u; /* dummy iteration count, will be updated latter Base on number of frames */
    DmaTcdList[8u].Value = 1u; /* dummy disable hardware request when major loop complete, will be updated latter according to last transfer or not */

    for (TCDSGIndex = 0u; TCDSGIndex < State->PhyUnitConfig->MaxNumOfFastTransfer; TCDSGIndex++)
    {
        /* Update software RX DMA TCD Scatter Gather */
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->RxDmaChannel, State->PhyUnitConfig->RxDmaFastSGId[TCDSGIndex], DmaTcdList, 9u);
    }
}

static void Dspi_Ip_RxDmaTcdSGConfig(uint8 Instance,
                                     uint8 TCDSGIndex,
                                     uint8 DisHwReq)
{
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[8u];

    /* Update buffers index */
    State->RxIndex = State->ExpectedFifoReads;

    /* configure RX DMA TCD Scatter Gather */
    /* No need to configure src address and src offset due to they are already set by Dspi_Ip_RxDmaTcdSGInit */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;

    if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[3u].Value = 1u;   /* 1 byte to transfer for each request */
        DmaTcdList[4u].Value = 1u; /* dest offset is 1 bytes */
    }
    else if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[3u].Value = 2u;   /* 2 bytes to transfer for each request */
        DmaTcdList[4u].Value = 2u; /* dest offset is 2 bytes */
    }
    else
    {
        DmaTcdList[1u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[2u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[3u].Value = 4u;   /* 4 bytes to transfer for each request */
        DmaTcdList[4u].Value = 4u; /* dest offset is 4 bytes */
    }

    if (NULL_PTR == State->RxBuffer)
    {
        /* Discard data */
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)&Dspi_Ip_u32DiscardData;    /* dest address write*/
        DmaTcdList[4u].Value = 0u; /* dest offset is 0 bytes */
    }
    else
    {
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)State->RxBuffer;    /* dest address write*/
    }

    DmaTcdList[5u].Value = State->ExpectedFifoReads; /* iteration count */
    DmaTcdList[6u].Value = DisHwReq; /* disable hardware request when major loop complete */
    DmaTcdList[7u].Value = DisHwReq; /* Enable Major interrupt at the end of transfer sequence(meanning when DisHwReq = 1u) */

    /* Update software RX DMA TCD Scatter Gather */
    (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->RxDmaChannel, State->PhyUnitConfig->RxDmaFastSGId[TCDSGIndex], DmaTcdList, 8u);
}

/**
* @brief   This function will configure TCD Scatter Gather for the CMD DMA channel
*/
static void Dspi_Ip_CmdDmaTcdSGConfig(uint8 Instance,
                                      uint8 TCDSGId,
                                      uint32 CmdAdd,
                                      uint16 Iter,
                                      uint8 DisHwReq)
{
    const Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dma_Ip_LogicChannelTransferListType DmaTcdList[3u];

    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_MAJORLOOP_COUNT;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;

    /* configure TCD Scatter Gather for Cmd DMA channel */
    DmaTcdList[0u].Value = CmdAdd; /* src address read */
    DmaTcdList[1u].Value = Iter;    /* iteration count */
    DmaTcdList[2u].Value = DisHwReq;    /* disable hardware request when major loop complete */
    /* Update software TCD Scatter Gather */
    (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxCmdDmaChannel, TCDSGId, DmaTcdList, 3u);
}

#endif /* if (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON) */

/**
* @brief   This function will configure hardware TCDs for the channels CMD DMA
*          according to current transfer configuration.
*
* @param[in]     State      State of the current transfer
* @return void
*/
static void Dspi_Ip_DmaCmdConfigAndStart(const Dspi_Ip_StateStructureType* State)
{
    Dma_Ip_LogicChannelTransferListType Tcds[4u] = {
        [0] = { DMA_IP_CH_SET_SOURCE_ADDRESS, (Dma_Ip_uintPtrType)&State->PushrCmds[0] },
        [1] = { DMA_IP_CH_SET_MAJORLOOP_COUNT, State->Pushr0Repeat },
        [2] = { DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST, 1u},
        [3] = { DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ, 0u}
    };

    /*
     * State->Pushr0Repeat will always be less than SPI_IP_DMA_MAX_ITER_CNT_U16 because DMA
     * slave is not implemented.
     * For master, the maximum value can be MAX_U16(FFFF)/MAX_DTCP(7FF) = 0x20
     */

    /* Use while 0 to use break on error to end the block faster */
    if (State->NbCmds > 1u)
    {
        Tcds[2].Value = 0u; /* Enable HW Request */
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxCmdDmaChannel,
                                                      State->PhyUnitConfig->TxCmdDmaSGId[0],
                                                      Tcds,
                                                      3u);
        /* Load software TCD Scatter Gather 0 into hardware TCD with ESG bit already set
            * in software TCD */
        (void)Dma_Ip_SetLogicChannelScatterGatherConfig(State->PhyUnitConfig->TxCmdDmaChannel, State->PhyUnitConfig->TxCmdDmaSGId[0u]);

        Tcds[0].Value = (Dma_Ip_uintPtrType)&State->PushrCmds[1]; /* SOURCE_ADDRESS */
        Tcds[1].Value = (uint32)State->NbCmds - 1u;   /* MAJORLOOP */
        Tcds[2].Value = 1u;                           /* Disable HW Request */
        Tcds[3].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
        Tcds[3].Value = 2;
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->TxCmdDmaChannel,
                                                      State->PhyUnitConfig->TxCmdDmaSGId[1],
                                                      Tcds,
                                                      4u);
    }
    else
    {
        Tcds[2].Value = 1u; /* Disable HW Request */
        (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->TxCmdDmaChannel,
                                                 Tcds, 4u);
    }

    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxCmdDmaChannel,
                                        DMA_IP_CH_SET_HARDWARE_REQUEST);
}

/**
* @brief   This function will configure hardware TCDs for the channels TX DMA, RX DMA
*          according to current transfer configuration.
*
* @param[in]     State      State of the current transfer
* @param[in]     Base       Base address of the instance regs to be updated
* @return void
*/
static void Dspi_Ip_DmaConfig(const Dspi_Ip_StateStructureType* State,
                              const DSPI_Type *Base)
{
    Dma_Ip_LogicChannelTransferListType DmaTcdList[11u];

    /* configure TX DMA channel */
    DmaTcdList[0u].Param = DMA_IP_CH_SET_SOURCE_ADDRESS;
    DmaTcdList[1u].Param = DMA_IP_CH_SET_DESTINATION_ADDRESS;
    DmaTcdList[2u].Param = DMA_IP_CH_SET_SOURCE_SIGNED_OFFSET;
    DmaTcdList[3u].Param = DMA_IP_CH_SET_SOURCE_TRANSFER_SIZE;
    DmaTcdList[4u].Param = DMA_IP_CH_SET_DESTINATION_TRANSFER_SIZE;
    DmaTcdList[5u].Param = DMA_IP_CH_SET_MINORLOOP_SIZE;
    DmaTcdList[6u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_OFFSET;
    DmaTcdList[7u].Param = DMA_IP_CH_SET_CONTROL_DIS_AUTO_REQUEST;
    DmaTcdList[8u].Param = DMA_IP_CH_SET_SOURCE_MODULO;

    DmaTcdList[1u].Value = (Dma_Ip_uintPtrType)&Base->PUSHR.FIFO.TX;    /* dest address write*/
    if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
    {
        DmaTcdList[2u].Value = 1u;  /* src offset is 1 byte */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[5u].Value = 1u;   /* bytes to transfer for each request */
    }
    else
    {
        DmaTcdList[2u].Value = 2u;  /* src offset is 2 bytes */
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[5u].Value = 2u;   /* bytes to transfer for each request */
    }

    DmaTcdList[6u].Value = 0u; /* no dest offset */
    DmaTcdList[7u].Value = 1u; /* disable hardware request when major loop complete */
    DmaTcdList[8u].Value = 0u;  /* no src address modulo */
    if (NULL_PTR == State->TxBuffer)
    {
        /* send default data */
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType) & State->ExternalDevice->DeviceParams->DefaultData; /* src address read */
        if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
        {
            DmaTcdList[2u].Value = 0u;  /* src offset is 0 byte */
        }
        else
        {
            DmaTcdList[8u].Value = 2u;  /* data is 4 bytes, src address modulo is 2 bits */
        }
    }
    else
    {
        DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)State->TxBuffer; /* src address read */
    }

    /* Set DESTINATION_SIGNED_LAST_ADDR_ADJ = 0 to avoid the case it still stored from previous TCD Scatter Gather */
    DmaTcdList[9u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ;
    DmaTcdList[9u].Value = 0u;    /* No adjust DADD when major loop completed */
    /* write TCD for TX DMA channel */
    (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->TxDmaChannel, DmaTcdList, 10u);

    /* configure RX DMA channel */
    DmaTcdList[0u].Value = (Dma_Ip_uintPtrType)&Base->POPR; /* src address read */
    DmaTcdList[2u].Value = 0u;  /* no src offset */
    if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE; /* 1 byte src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_1_BYTE;    /* 1 byte dest transfer size */
        DmaTcdList[5u].Value = 1u;   /* 1 byte to transfer for each request */
        DmaTcdList[6u].Value = 1u; /* dest offset is 1 bytes */
    }
    else if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE; /* 2 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_2_BYTE;    /* 2 bytes dest transfer size */
        DmaTcdList[5u].Value = 2u;   /* 2 bytes to transfer for each request */
        DmaTcdList[6u].Value = 2u; /* dest offset is 2 bytes */
    }
    else
    {
        DmaTcdList[3u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE; /* 4 bytes src transfer size */
        DmaTcdList[4u].Value = DMA_IP_TRANSFER_SIZE_4_BYTE;    /* 4 bytes dest transfer size */
        DmaTcdList[5u].Value = 4u;   /* 4 bytes to transfer for each request */
        DmaTcdList[6u].Value = 4u; /* dest offset is 4 bytes */
    }

    if (NULL_PTR == State->RxBuffer)
    {
        /* Discard data */
        DmaTcdList[1u].Value = (Dma_Ip_uintPtrType) & Dspi_Ip_u32DiscardData;    /* dest address write*/
        DmaTcdList[6u].Value = 0u; /* dest offset is 0 bytes */
    }
    else
    {
        DmaTcdList[1u].Value = (Dma_Ip_uintPtrType)State->RxBuffer;    /* dest address write*/
    }

    DmaTcdList[7u].Value = 1u; /* disable hardware request when major loop complete */
    /* Set DESTINATION_SIGNED_LAST_ADDR_ADJ = 0 to avoid the case it still stored from previous TCD Scatter Gather */
    DmaTcdList[8u].Param = DMA_IP_CH_SET_DESTINATION_SIGNED_LAST_ADDR_ADJ;
    DmaTcdList[8u].Value = 0u;    /* No adjust DADD when major loop completed */
    /* write TCD for RX DMA channel */
    (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->RxDmaChannel, DmaTcdList, 9u);
}

/**
* @brief   This function will configure buffers in hardware TCDs for the channels TX DMA, RX DMA
*           and it will trigger the transfer
*
* @param[in]     State      State of the current transfer
* @return void
*/
static void Dspi_Ip_DmaTxRxUpdateLoop(Dspi_Ip_StateStructureType* State)
{
    uint16 NumberDmaIterWrite = State->ExpectedFifoWrites - State->TxIndex;
    uint16 NumberDmaIterRead;

    Dma_Ip_LogicChannelTransferListType Tcd = {
        .Param = DMA_IP_CH_SET_MAJORLOOP_COUNT
    };

    /* Limits number of major count */
    if (DSPI_IP_DMA_MAX_ITER_CNT_U16 < NumberDmaIterWrite)
    {
        NumberDmaIterWrite = DSPI_IP_DMA_MAX_ITER_CNT_U16;
    }

    NumberDmaIterRead = NumberDmaIterWrite;
    if (State->ExternalDevice->DeviceParams->FrameSize > 16u)
    {
        NumberDmaIterRead = NumberDmaIterWrite / 2u;
        if (0u != (NumberDmaIterWrite % 2u))
        {
            NumberDmaIterWrite = NumberDmaIterRead;
        }
    }

    State->TxIndex += NumberDmaIterWrite;
    State->RxIndex += NumberDmaIterRead;

    Tcd.Value = NumberDmaIterWrite;
    (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->TxDmaChannel, &Tcd, 1u);

    Tcd.Value = NumberDmaIterRead;
    (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->RxDmaChannel, &Tcd, 1u);

    /* Enable HW request for RX DMA channel before TX DMA channel */
    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->RxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
}

/**
* @brief   Configures and starts a DMA transfer
*
* @param[in]     State      State of the current transfer
* @param[in]     Base       Base address of the instance regs to be updated
* @param[in]     IrqEn      Enable DMA major loop interrupt.
* @return void
*/
static void Dspi_Ip_DmaAsyncStart(Dspi_Ip_StateStructureType* State,
                                  DSPI_Type *Base,
                                  uint32 IrqEn)
{
    Dma_Ip_LogicChannelTransferListType Tcd = {
        .Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT,
        .Value = IrqEn
    };

    (void)Dma_Ip_SetLogicChannelTransferList(State->PhyUnitConfig->RxDmaChannel, &Tcd, 1u);
    #if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
    if ((boolean)FALSE == State->PhyUnitConfig->SlaveMode)
    #endif
    {
        Dspi_Ip_DmaCmdConfigAndStart(State);
    }

    /* Config RX and TX channels */
    Dspi_Ip_DmaConfig(State, Base);
    /* Enable RX and TX channels */
    Dspi_Ip_DmaTxRxUpdateLoop(State);

    /* Enable SPI interrupts and set them to trigger DMA */
    Base->RSER = DSPI_RSER_CMDFFF_RE(1) | DSPI_RSER_CMDFFF_DIRS(1) |
                 DSPI_RSER_TFFF_RE(1) | DSPI_RSER_TFFF_DIRS(1) |
                 DSPI_RSER_RFDF_RE(1) | DSPI_RSER_RFDF_DIRS(1);
}

#endif /*(DSPI_IP_DMA_USED == STD_ON)*/

/**
* @brief   This function will write data to TX FIFO.
* @details This function will write data to TX FIFO.
*
* @param[in]     NumberOfReads   Number of bytes data will be wrote to TX FIFO .
* @param[in]     Instance         Index of the hardware instance.
* @return none
*/
static void Dspi_Ip_WriteTxFifo(uint16 NumberOfWrites,
                                uint8 Instance)
{
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    uint32 Idx;
    uint32 LastIdx;
    uint32 Factor;
    uint16 Count;
    uint16 Data = 0u;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NumberOfWrites <= DSPI_IP_FIFO_SIZE_U16);
    #endif
    if (NULL_PTR != State->TxBuffer)
    {
        if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
        {
            Factor = 1u;
        }
        else
        {
            Factor = 2u;
        }

        LastIdx = ((uint32)State->TxIndex + NumberOfWrites) * Factor;
        for (Idx = State->TxIndex * Factor; Idx < LastIdx; Idx += Factor)
        {
            if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
            {
                Data = State->TxBuffer[Idx];
            }
            else
            {
                Data = *((const uint16*)&State->TxBuffer[Idx]);
            }

            Base->PUSHR.FIFO.TX = Data;
        }
    }
    else
    {
        for (Count = 0; Count < NumberOfWrites; Count++)
        {
            if (State->ExternalDevice->DeviceParams->FrameSize > 16u)
            {
                /* get first or second word (2 bytes) based on TxIndex */
                Factor = (uint16)((Count % 2u) * 16u);
                Data = (uint16)(State->ExternalDevice->DeviceParams->DefaultData >> Factor);
            }
            else
            {
                Data = (uint16)State->ExternalDevice->DeviceParams->DefaultData;
            }

            Base->PUSHR.FIFO.TX = Data;
        }
    }

    State->TxIndex += NumberOfWrites;
}

/**
* @brief   This function will read data from RX FIFO in Asynchronous mode.
* @details This function will read data from RX FIFO in Asynchronous mode.
*
* @param[in]     NumberOfReads    Number of bytes in RX FIFO will be read.
* @param[in]     Instance       Index of the hardware instance.
* @return none
*/
static void Dspi_Ip_ReceiveData(uint16 NumberOfReads,
                                uint8 Instance)
{
    Dspi_Ip_StateStructureType* const State = Dspi_Ip_apxStateStructureArray[Instance];
    const DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    uint16 LimitedNumberOfReads = NumberOfReads;
    uint32 Data;
    uint32 Idx;
    uint32 LastIdx;
    uint32 Factor;

    if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
    {
        Factor = 1u;
    }
    else if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
    {
        Factor = 2u;
    }
    else
    {
        Factor = 4u;
    }

    /* Limits to remaining frames. */
    if (LimitedNumberOfReads > (State->ExpectedFifoReads - State->RxIndex))
    {
        LimitedNumberOfReads = State->ExpectedFifoReads - State->RxIndex;
    }

    if (NULL_PTR != State->RxBuffer)
    {
        LastIdx = ((uint32)State->RxIndex + LimitedNumberOfReads) * Factor;
        for (Idx = State->RxIndex * Factor; Idx < LastIdx; Idx += Factor)
        {
            Data = Base->POPR;
            if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
            {
                State->RxBuffer[Idx] = (uint8)Data;
            }
            else if (State->ExternalDevice->DeviceParams->FrameSize < 17u)
            {
                *((uint16*)&State->RxBuffer[Idx]) = (uint16)Data;
            }
            else
            {
                *((uint32*)&State->RxBuffer[Idx]) = Data;
            }
        }
    }
    else
    {
        /* Discard data */
        for (Idx = 0; Idx < (uint32)LimitedNumberOfReads; Idx++)
        {
            (void)Base->POPR;
        }
    }

    State->RxIndex += LimitedNumberOfReads;

    /* Update current TX FIFO slot */
    if (State->ExternalDevice->DeviceParams->FrameSize > 16u)
    {
        State->CurrentTxFifoSlot += LimitedNumberOfReads * 2u;
    }
    else
    {
        State->CurrentTxFifoSlot += LimitedNumberOfReads;
    }
}

/**
* @brief   This function will finish transfer of a channel.
* @details This function will finish transfer of a channel.
*
* @param[in]     Instance            Index of the hardware instance.
* @param[in]     ErrorFlag           Save the status of transfer error flags
*/
static void Dspi_Ip_ChannelFinished(uint8 Instance,
                                    boolean ErrorFlag)
{
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    Dspi_Ip_EventType EventState = DSPI_IP_EVENT_FAULT;

    if (TRUE == ErrorFlag)
    {
        State->Status = DSPI_IP_FAULT;
        EventState = DSPI_IP_EVENT_FAULT;
    }
    else
    {
        State->Status = DSPI_IP_IDLE;
        EventState = DSPI_IP_EVENT_END_TRANSFER;
    }

    if (NULL_PTR != State->Callback)
    {
        State->Callback(Instance, EventState);
    }
    else
    {
        (void)EventState;
    }
}

/**
* @brief   Write to FIFOs to start Async Transfer
* @details Write TX and TXCMD
*
* @param[in]     State      State of the current transfer
* @param[in]     Base       Base address of the instance regs to be updated
* @return void
*/
static void Dspi_Ip_AsyncStart(Dspi_Ip_StateStructureType* State,
                               DSPI_Type *Base)
{
    #if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
    uint16 NumberOfWrites = 0u;
    #endif

    /* Enable interrupts. */
    Base->RSER = DSPI_RSER_TCF_RE(1) | DSPI_RSER_RFOF_RE(1);
    /* Fill data into TX FIFO to trigger TCF interrupt */
    /* Write to CMD field first*/
    #if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
    if ((boolean)FALSE == State->PhyUnitConfig->SlaveMode)
    #endif
    {
        (void)Dspi_Ip_WriteCmdFifo(State, Base);
        /* Limits to remaining frames. */
        if (State->CurrentTxFifoSlot > (State->ExpectedFifoWrites - State->TxIndex))
        {
            State->CurrentTxFifoSlot = State->ExpectedFifoWrites - State->TxIndex;
        }

        if (State->CurrentTxFifoSlot > 0u)
        {
            Dspi_Ip_WriteTxFifo(State->CurrentTxFifoSlot, State->ExternalDevice->Instance);
            /* Update current TX FIFO slot can be written */
            State->CurrentTxFifoSlot = 0u;
        }
    }

    #if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
    else
    {
        /* In slave mode, TXFIFO will be wrote full first before Master device performs transmision */
        NumberOfWrites = (uint16)((Base->SR) & DSPI_SR_TXCTR_MASK) >> DSPI_SR_TXCTR_SHIFT;
        if (NumberOfWrites < DSPI_IP_FIFO_SIZE_U16)
        {
            NumberOfWrites = DSPI_IP_FIFO_SIZE_U16 - NumberOfWrites;
        }
        else
        {
            /* Handle hw error on bits. Ceil CMDCTR and calculate result: DSPI_IP_FIFO_SIZE_U16 - DSPI_IP_FIFO_SIZE_U16 */
            NumberOfWrites = 0u;
        }

        /* Limits to remaining frames. */
        if (NumberOfWrites > (State->ExpectedFifoWrites - State->TxIndex))
        {
            NumberOfWrites = State->ExpectedFifoWrites - State->TxIndex;
        }

        #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
        DevAssert(NumberOfWrites < DSPI_IP_FIFO_SIZE_U16);
        #endif
        /* Write to TXFIFO*/
        Dspi_Ip_WriteTxFifo(NumberOfWrites, State->ExternalDevice->Instance);
        /* Update current TX FIFO available */
        State->CurrentTxFifoSlot -= NumberOfWrites;
    }
    #endif /* if (DSPI_IP_SLAVE_SUPPORT == STD_ON) */
}

#if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
/**
* @brief   This function will verify the validation of some input parameters of transmision functions.
* @details This function will verify the validation of some input parameters of transmision functions.
*
* @param[in]     ExternalDevice   Pointer to the external device where data is transmitted.
* @param[in]     Length         Number of bytes to be sent.
* @return        DSPI_IP_STATUS_SUCCESS: Don't have any errors was found.
*                DSPI_IP_STATUS_FAIL: Transmission command has not been accepted.
*/
static void Dspi_Ip_CheckValidParameters(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                         uint16 Length,
                                         uint32 TimeOut)
{
    DevAssert(ExternalDevice != NULL_PTR);
    DevAssert(0u != Length);
    DevAssert(0u != TimeOut);
    if (ExternalDevice->DeviceParams->FrameSize > 16u)
    {
        DevAssert((Length % 4u) == 0u);
    }
    else if (ExternalDevice->DeviceParams->FrameSize > 8u)
    {
        DevAssert((Length % 2u) == 0u);
    }
    else
    {
        /* do nothing */
    }

    DevAssert(Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance] != NULL_PTR);
}

#endif /* if (DSPI_IP_DEV_ERROR_DETECT == STD_ON) */
/*==================================================================================================
*                                      GLOBAL FUNCTIONS
==================================================================================================*/
#if (DSPI_IP_DMA_USED == STD_ON)
/**
* @brief   This function will process DMA transfer complete interrupt.
* @details This function will process continue transfer or end of transfer via DMA.
*
* @param[in]     Instance      Index of the hardware instance.
* @implements Dspi_Ip_IrqDmaHandler_Activity
*/
void Dspi_Ip_IrqDmaHandler(uint8 Instance)
{
    DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    uint32 SrStatusRegister = 0u;
    boolean ErrorFlag = (boolean)FALSE;
    boolean EndOfTransferFlag = (boolean)FALSE;

    if ((NULL_PTR != State) && (DSPI_IP_BUSY == State->Status))
    {
        /* Read Status and clear all flags. */
        SrStatusRegister = Base->SR;
        Base->SR &= 0xFFFF0000u;
        /* DSPI do not support error flag? it will be enabled if those bits are availabe */
        if ((0u != (SrStatusRegister & DSPI_SR_RFOF_MASK)))
        {
            /* mark error flag */
            ErrorFlag = (boolean)TRUE;
        }
        else
        {
            if (State->ExpectedFifoReads != State->RxIndex)
            {
                Dspi_Ip_DmaTxRxUpdateLoop(State);
            }
            else
            {
                EndOfTransferFlag = (boolean)TRUE;
            }
        }

        if (((boolean)TRUE == EndOfTransferFlag) || ((boolean)TRUE == ErrorFlag))
        {
            /* Only set HALT bit to stop transfer when there is a error or request to de-assert CS at the end of transfers sequence */
            if (((boolean)TRUE == ErrorFlag) || ((boolean)FALSE == State->KeepCs))
            {
                                       SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_13();
                                         /* Stop Transfer */
                Base->MCR |= DSPI_MCR_HALT_MASK;
                                       SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_13();
                                     }

            /* Disable interrupts and DMA requests. */
            Base->RSER = 0U;

            if ((boolean)TRUE == ErrorFlag)
            {
                State->Status = DSPI_IP_FAULT;
            }
            else
            {
                State->Status = DSPI_IP_IDLE;
            }

            if (State->Callback != NULL_PTR)
            {
                if ((boolean)TRUE == ErrorFlag)
                {
                    State->Callback(Instance, DSPI_IP_EVENT_FAULT);
                }
                else
                {
                    State->Callback(Instance, DSPI_IP_EVENT_END_TRANSFER);
                }
            }
        }
    }
    else
    {
        /* Driver is initialized but there was no poll request*/
        /* nothing to do */
    }
}

#endif /* (DSPI_IP_DMA_USED == STD_ON) */

#if (STD_ON == DSPI_IP_ENABLE_USER_MODE_SUPPORT)
/**
* @brief This function will set UAA bit in REG_PROT for SPI unit
*/
void Dspi_Ip_SetUserAccess(uint8 Instance)
{
    DSPI_Type* Base = Dspi_Ip_apxBases[Instance];

    SET_USER_ACCESS_ALLOWED((uint32)Base, DSPI_IP_PROT_MEM_U32);
}

/**
* @brief This function will enable writing all SPI registers under protection in User mode by configuring REG_PROT
*/
static void Dspi_Ip_SetUserAccessAllowed(uint8 Instance)
{
    OsIf_Trusted_Call1param(Dspi_Ip_SetUserAccess, Instance);
}

#endif /* DSPI_IP_ENABLE_USER_MODE_SUPPORT */
/*================================================================================================*/
Dspi_Ip_StatusType Dspi_Ip_Init(const Dspi_Ip_ConfigType *PhyUnitConfigPtr)
{
    DSPI_Type* Base;
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;
    uint8 Instance = 0u;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(PhyUnitConfigPtr != NULL_PTR);
    #endif
    Instance = PhyUnitConfigPtr->Instance;
    State = Dspi_Ip_apxStateStructureArray[Instance];
    Base = Dspi_Ip_apxBases[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State == NULL_PTR);
    #endif
    Dspi_Ip_apxStateStructureArray[Instance] = &Dspi_Ip_axStateStructure[PhyUnitConfigPtr->StateIndex];
    State = Dspi_Ip_apxStateStructureArray[Instance];
    State->PhyUnitConfig = PhyUnitConfigPtr;
    #if (STD_ON == DSPI_IP_ENABLE_USER_MODE_SUPPORT)
    Dspi_Ip_SetUserAccessAllowed(Instance);
    #endif
    /* Halt before update other fields */
    Base->MCR |= DSPI_MCR_HALT_MASK;
    Base->MCR = PhyUnitConfigPtr->Mcr;

    #if (DSPI_IP_DUAL_CLOCK_MODE == STD_ON)
    State->ClockMode = DSPI_IP_NORMAL_CLOCK;
    #endif
    State->KeepCs = (boolean)FALSE;
    #if (DSPI_IP_DMA_USED == STD_ON)
    #if (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)
    Dspi_Ip_TxDmaTcdSGInit(Instance);
    Dspi_Ip_RxDmaTcdSGInit(Instance);
    #endif
    if ((boolean)TRUE == State->PhyUnitConfig->DmaUsed)
    {
        Dspi_Ip_CmdDmaTcdSGInit(Instance);
    }

    #endif
    /* set State to idle */
    Status = Dspi_Ip_UpdateTransferMode(Instance, PhyUnitConfigPtr->TransferMode);
    if (DSPI_IP_STATUS_SUCCESS == Status)
    {
        State->Status = DSPI_IP_IDLE;
    }

    return Status;
}

/*================================================================================================*/
Dspi_Ip_StatusType Dspi_Ip_DeInit(uint8 Instance)
{
    DSPI_Type* Base;
    const Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    Base = Dspi_Ip_apxBases[Instance];
    State = Dspi_Ip_apxStateStructureArray[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    if (State->Status == DSPI_IP_BUSY)
    {
        Status = DSPI_IP_STATUS_FAIL;
    }
    else
    {
        /* Halt before update other fields */
        Base->MCR |= DSPI_MCR_HALT_MASK;
        /* Reset FIFOs */
        Base->MCR |= DSPI_MCR_CLR_TXF_MASK | DSPI_MCR_CLR_RXF_MASK;
        Base->MCR = 0x4001u;
        Base->MODE.CTAR[0] = 0x78000000u;
        Base->SR = 0xFFFF0000u;
        Base->RSER = 0u;
        Base->CTARE[0] = 0x1u;

        Dspi_Ip_apxStateStructureArray[Instance] = NULL_PTR;
    }

    return Status;
}

static Dspi_Ip_StatusType Dspi_Ip_IntoBusyState(Dspi_Ip_StateStructureType* State)
{
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;
               SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_09();
                 if (DSPI_IP_BUSY == State->Status)
    {
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_09();
                  Status = DSPI_IP_STATUS_FAIL;
    }
    else
    {
        /* Mark the hardware as busy. */
        State->Status = DSPI_IP_BUSY;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_09();
              }

    return Status;
}

/* Iteration of reading and writing the FIFO. Returns true if something action was taken inside the iteration */
static boolean Dspi_Ip_SyncReadWriteStep(Dspi_Ip_StateStructureType *State,
                                         DSPI_Type *Base,
                                         uint8 Instance)
{
    boolean StepDone = FALSE;
    uint16 NumberOfReads;

    /* SEND CMD */
    if (State->ExpectedCmdFifoWrites != 0u)
    {
        if (Dspi_Ip_WriteCmdFifo(State, Base) != 0u)
        {
            StepDone = TRUE;
        }
    }

    /* TRANSMIT */

    /* Push data until HW fifo is full or transfer is done. */
    /* After driver code read all frames in RX FIFO, if there are still some frames in TX FIFO, at the time before driver code check number of frames available in TX FIFO
    to prepare to fill TX FIFO. At that time, interrupt occurred, and the time to process interrupt is longer than the time to transfer all frames in TX FIFO.
    So TX FIFO will be empty and some frames received in RX FIFO, then the program is returned from interrupt and fill TX FIFO until full.
    And there is a interrupt occurred after that before read all frames in RX FIFO, and the time to process interrupt is longer than the time to transfer all frames in TX FIFO.
    So, RX FIFO can be overflow. To avoid this, limits total of frames in TX FIFO and RX FIFO must be lower than FIFO size.
    State->CurrentTxFifoSlot variable is used to hanlde number of frames are "on bus transfer". They are always less than FIFO size */

    /* Limits to remaining frames. */
    if (State->CurrentTxFifoSlot > (State->ExpectedFifoWrites - State->TxIndex))
    {
        State->CurrentTxFifoSlot = State->ExpectedFifoWrites - State->TxIndex;
    }

    if (State->CurrentTxFifoSlot != 0u)
    {
        Dspi_Ip_WriteTxFifo(State->CurrentTxFifoSlot, Instance);
        /* Update current TX FIFO slot can be written */
        State->CurrentTxFifoSlot = 0u;
        StepDone = TRUE;
        /* Clear Halt bit, then transfer */
        if (((Base->MCR) & DSPI_MCR_HALT_MASK) == DSPI_MCR_HALT_MASK)
        {
            Base->MCR &= ~DSPI_MCR_HALT_MASK;
        }
    }

    /* RECEIVE */
    /* Read all data available in receive HW fifo. */
    NumberOfReads = (uint16)(((Base->SR) & DSPI_SR_RXCTR_MASK) >> DSPI_SR_RXCTR_SHIFT);
    if (NumberOfReads > DSPI_IP_FIFO_SIZE_U16)
    {
        NumberOfReads = DSPI_IP_FIFO_SIZE_U16;
    }
    if (NumberOfReads != 0u)
    {
        /* Read data from RX FIFO */
        Dspi_Ip_ReceiveData(NumberOfReads, Instance);
        StepDone = TRUE;
    }

    return StepDone;
}

/*================================================================================================*/
Dspi_Ip_StatusType Dspi_Ip_SyncTransmit(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                        const uint8 *TxBuffer,
                                        uint8 *RxBuffer,
                                        uint16 Length,
                                        uint32 TimeOut)
{
    DSPI_Type *Base;
    Dspi_Ip_StateStructureType *State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;
    uint32 TimeoutTicks = OsIf_MicrosToTicks(TimeOut, DSPI_IP_TIMEOUT_METHOD);
    uint32 CurrentTicks = 0u; /* initialize current counter */
    uint32 ElapsedTicks = 0u; /* elapsed will give timeout */
    uint8 Instance = 0u;
    boolean StepDone;

    #if (STD_ON == DSPI_IP_DEV_ERROR_DETECT)
    Dspi_Ip_CheckValidParameters(ExternalDevice, Length, TimeOut);
    #endif
    Instance = ExternalDevice->Instance;
    State = Dspi_Ip_apxStateStructureArray[Instance];

    Base = Dspi_Ip_apxBases[Instance];
    Status = Dspi_Ip_IntoBusyState(State);
    if (DSPI_IP_STATUS_SUCCESS == Status)
    {
        /* Make sure that FIFOs will be empty before start new transfer session */
        Base->MCR |= DSPI_MCR_CLR_TXF_MASK | DSPI_MCR_CLR_RXF_MASK;
        /* Reset Flags */
        Base->SR = 0xFFFF0000u;

        State->TxBuffer = TxBuffer;
        State->RxBuffer = RxBuffer;
        State->ExternalDevice = ExternalDevice;

        Dspi_Ip_PrepareTransfer(State, Base, Length);

        CurrentTicks = OsIf_GetCounter(DSPI_IP_TIMEOUT_METHOD); /* initialize current counter */

        /* Get current FIFO slots are available.*/
        State->CurrentTxFifoSlot = DSPI_IP_FIFO_SIZE_U16;
        while (DSPI_IP_STATUS_SUCCESS == Status)
        {
            /* Read and write FIFO registers */
            StepDone = Dspi_Ip_SyncReadWriteStep(State, Base, Instance);
            if (StepDone)
            {
                /* Finish the transfer if all frames have received */
                if (State->RxIndex == State->ExpectedFifoReads)
                {
                    break;
                }

                ElapsedTicks = 0u;
            }

            /* Check if errors like overflow or underflow are reported in Status register or timeout error */
            ElapsedTicks += OsIf_GetElapsed(&CurrentTicks, DSPI_IP_TIMEOUT_METHOD);
            if (ElapsedTicks >= TimeoutTicks)
            {
                Status = DSPI_IP_TIMEOUT;
            }
        }

        /* Only set HALT bit to stop transfer when there is a error or request to de-assert CS at the end of transfers sequence */
        if ((DSPI_IP_STATUS_SUCCESS != Status) || ((boolean)FALSE == State->KeepCs))
        {
            /* Stop transfer */
            Base->MCR |= DSPI_MCR_HALT_MASK;
        }

        /* Channel finished */
        Dspi_Ip_ChannelFinished(Instance, FALSE);
    }

    return Status;
}

Dspi_Ip_StatusType Dspi_Ip_AsyncTransmit(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                         const uint8 *TxBuffer,
                                         uint8 *RxBuffer,
                                         uint16 Length,
                                         Dspi_Ip_CallbackType EndCallback)
{
    DSPI_Type* Base;
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (STD_ON == DSPI_IP_DEV_ERROR_DETECT)
    Dspi_Ip_CheckValidParameters(ExternalDevice, Length, 1u);
    #endif
    State = Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance];
    Base = Dspi_Ip_apxBases[ExternalDevice->Instance];
    Status = Dspi_Ip_IntoBusyState(State);
    if (DSPI_IP_STATUS_SUCCESS == Status)
    {
        /* Update State structure. */
        State->TxBuffer = TxBuffer;
        State->RxBuffer = RxBuffer;
        State->Callback = EndCallback;
        State->CurrentTxFifoSlot = DSPI_IP_FIFO_SIZE_U16;
        State->ExternalDevice = ExternalDevice;

        Dspi_Ip_PrepareTransfer(State, Base, Length);
        /* Make sure that FIFOs will be empty before start new transfer session */
        Base->MCR |= DSPI_MCR_CLR_TXF_MASK | DSPI_MCR_CLR_RXF_MASK;
        /* Clear all flags. */
        Base->SR &= 0xFFFF0000u;
        #if (DSPI_IP_DMA_USED == STD_ON)
        if ((boolean)FALSE == State->PhyUnitConfig->DmaUsed)
        #endif
        {
            if (State->TransferMode == DSPI_IP_POLLING)
            {
                /* Disable interrupts and DMA requests. */
                Base->RSER = 0U;
            }
            else
            {
                /* Interrupt mode */
                Dspi_Ip_AsyncStart(State, Base);
            }
        }

        #if (DSPI_IP_DMA_USED == STD_ON)
        else
        {
            Dspi_Ip_DmaAsyncStart(State, Base, (State->TransferMode == DSPI_IP_POLLING) ? 0u : 1u);
        }
        #endif
                SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_11();
                  /* Clear Halt bit before transfer */
        Base->MCR &= ~DSPI_MCR_HALT_MASK;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_11();
              }

    return Status;
}

#if ((DSPI_IP_DMA_USED == STD_ON) && (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON))
Dspi_Ip_StatusType Dspi_Ip_AsyncTransmitFast(const Dspi_Ip_FastTransferType *FastTransferCfg,
                                             uint8 NumberOfTransfer,
                                             Dspi_Ip_CallbackType EndCallback)
{
    DSPI_Type* Base;
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;
    uint8 Instance = 0u;
    uint32 LsbValue = 0u;
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    uint8 Count = 0u;

    DevAssert(NULL_PTR != FastTransferCfg);
    DevAssert(NULL_PTR != FastTransferCfg[0u].ExternalDevice);

    State = Dspi_Ip_apxStateStructureArray[FastTransferCfg[0u].ExternalDevice->Instance];

    DevAssert(NULL_PTR != State);
    DevAssert(State->TransferMode == DSPI_IP_INTERRUPT);
    DevAssert(NumberOfTransfer <= State->PhyUnitConfig->MaxNumOfFastTransfer);

    for (Count = 0u; Count < NumberOfTransfer; Count++)
    {
        DevAssert(NULL_PTR != FastTransferCfg[Count].ExternalDevice);
        DevAssert(0u != FastTransferCfg[Count].Length);
        if (FastTransferCfg[0u].ExternalDevice->DeviceParams->FrameSize > 16u)
        {
            DevAssert((FastTransferCfg[Count].Length % 4u) == 0u);
        }
        else if (FastTransferCfg[0u].ExternalDevice->DeviceParams->FrameSize > 8u)
        {
            DevAssert((FastTransferCfg[Count].Length % 2u) == 0u);
        }
        else
        {
            DevAssert(DSPI_IP_DMA_MAX_ITER_CNT_U16 >= FastTransferCfg[Count].Length);
        }
    }

    #endif /* if (DSPI_IP_DEV_ERROR_DETECT == STD_ON) */
    Instance = FastTransferCfg[0u].ExternalDevice->Instance;
    Base = Dspi_Ip_apxBases[Instance];
    State = Dspi_Ip_apxStateStructureArray[Instance];
        SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_14();
          if (DSPI_IP_BUSY == State->Status)
    {
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_14();
                  Status = DSPI_IP_STATUS_FAIL;
    }
    else
    {
        /* Mark the hardware as busy. */
        State->Status = DSPI_IP_BUSY;
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_14();
          
        /* Make sure that FIFOs will be empty before start new transfer session */
        Base->MCR |= DSPI_MCR_CLR_TXF_MASK | DSPI_MCR_CLR_RXF_MASK;
        /* Clear all flags. */
        Base->SR &= 0xFFFF0000u;

        /* Update State structure. */
        /* For Dma Fast transfer, All transfers use the same HWUnit and in Master mode only. Only some parameters can be changed as Continuous CS, PCS.
        Some parameters such as Baudrate, Clock Polarity, Clock Phase, Delays timming configuration, Bit Order, Frame Size
        must be the same between transfers. So, make sure they are configured the same in each External Device allocated for Dma Fast Transfers.
        And all those attributes can be got from first transfer in FastTransferCfg */
        State->ExternalDevice = FastTransferCfg[0u].ExternalDevice;
        /* Get Lsb value */
        LsbValue = State->ExternalDevice->DeviceParams->Lsb ? 1UL : 0UL;
        State->Callback = EndCallback;
        /* Stop transfer at the end of transfers sequence by set HALT bit in Dspi_Ip_IrqDmaHandler */
        State->KeepCs = (boolean)FALSE;

        /* Configure external device parameters  like: frane size, clock phase, clock polarity. */
        #if (DSPI_IP_DUAL_CLOCK_MODE == STD_ON)
        Base->MODE.CTAR[0u] = FastTransferCfg[0u].ExternalDevice->Ctar[State->ClockMode] | DSPI_CTAR_FMSZ(((uint32)State->ExternalDevice->DeviceParams->FrameSize - 1u) & 0xFu) | DSPI_CTAR_LSBFE(LsbValue);
        #else
        Base->MODE.CTAR[0u] = FastTransferCfg[0u].ExternalDevice->Ctar | DSPI_CTAR_FMSZ(((uint32)State->ExternalDevice->DeviceParams->FrameSize - 1u) & (uint32)0xFu) | DSPI_CTAR_LSBFE(LsbValue);
        #endif
        Base->CTARE[0u] = FastTransferCfg[0u].ExternalDevice->Ctare | DSPI_CTARE_FMSZE((((uint32)State->ExternalDevice->DeviceParams->FrameSize - 1u) >> 4u) & (uint32)0x1u);
        /* Config and Enable DMA request. */
        Dspi_Ip_DmaFastConfig(Instance, FastTransferCfg, NumberOfTransfer);
        Base->RSER = DSPI_RSER_CMDFFF_RE(1u) | DSPI_RSER_CMDFFF_DIRS(1u) | DSPI_RSER_TFFF_RE(1u) | DSPI_RSER_TFFF_DIRS(1u) | DSPI_RSER_RFDF_RE(1u) | DSPI_RSER_RFDF_DIRS(1u);

        /* Clear Halt bit before transfer */
        Base->MCR &= ~DSPI_MCR_HALT_MASK;
    }

    return Status;
}

/**
* @brief   This function will configure Scatter/Gather TCDs for the channels TX DMA, RX DMA and CMD DMA
*          according to Dma Fast transfers configuration. DMA channels will be started at the end of the function.
*/
static void Dspi_Ip_DmaFastConfig(uint8 Instance,
                                  const Dspi_Ip_FastTransferType *FastTransferCfg,
                                  uint8 NumberOfTransfer)
{
    Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    boolean ClearCS = (boolean)FALSE;
    uint8 DisHwRequest = 0u;
    uint8 Count = 0u;
    uint8 CmdTCDSGIndex = 0u;
    Dma_Ip_LogicChannelTransferListType DmaTcdList[1u];

    DmaTcdList[0u].Param = DMA_IP_CH_SET_CONTROL_EN_MAJOR_INTERRUPT;
    DmaTcdList[0u].Value = 1u;

    for (Count = 0u; Count < NumberOfTransfer; Count++)
    {
        /* Update State structure. */
        State->RxIndex = 0u;
        State->TxIndex = 0u;
        State->TxBuffer = FastTransferCfg[Count].TxBuffer;
        State->RxBuffer = FastTransferCfg[Count].RxBuffer;
        if (State->ExternalDevice->DeviceParams->FrameSize < 9u)
        {
            State->ExpectedFifoWrites = FastTransferCfg[Count].Length;
        }
        else
        {
            State->ExpectedFifoWrites = FastTransferCfg[Count].Length / 2u;
        }

        State->ExpectedFifoReads = State->ExpectedFifoWrites;
        if (State->ExternalDevice->DeviceParams->FrameSize > 16u)
        {
            State->ExpectedFifoReads = State->ExpectedFifoWrites / 2u;
        }

        State->ExpectedCmdFifoWrites = State->ExpectedFifoReads;
        State->PhyUnitConfig->CmdDmaFast[Count].DefaultData = FastTransferCfg[Count].DefaultData;
        State->PhyUnitConfig->CmdDmaFast[Count].DmaFastPushrCmd = FastTransferCfg[Count].ExternalDevice->PushrCmd;
        State->PhyUnitConfig->CmdDmaFast[Count].DmaFastPushrCmdLast = FastTransferCfg[Count].ExternalDevice->PushrCmd & (~((uint16)((DSPI_PUSHR_CONT_MASK | DSPI_PUSHR_PP_MCSC_MASK) >> 16u)));

        /* CS will be cleared for last transfer or depend on KeepCs if not last transfer.
        Disable DMA HW request at the end of transfer. */
        if (Count == (NumberOfTransfer - 1u))
        {
            ClearCS = (boolean)TRUE;
            DisHwRequest = 1u;
        }
        else
        {
            if ((boolean)FALSE == FastTransferCfg[Count].KeepCs)
            {
                ClearCS = (boolean)TRUE;
            }
            else
            {
                ClearCS = (boolean)FALSE;
            }

            DisHwRequest = 0u;
        }

        /* Configure software TCDs Scatter Gather for CMD DMA channel */
        if ((boolean)TRUE == ClearCS)
        {
            if (State->ExpectedCmdFifoWrites > 1u)
            {
                Dspi_Ip_CmdDmaTcdSGConfig(Instance,
                                          State->PhyUnitConfig->TxCmdDmaSGId[CmdTCDSGIndex],
                                          (Dma_Ip_uintPtrType)&State->PhyUnitConfig->CmdDmaFast[Count].DmaFastPushrCmd,
                                          State->ExpectedCmdFifoWrites - 1u,
                                          0u    /* not disable dma hw request, the transfer will be continued after next software TCD Scatter Gather
                                                 * loaded */
                                         );
                CmdTCDSGIndex++;
            }

            Dspi_Ip_CmdDmaTcdSGConfig(Instance,
                                      State->PhyUnitConfig->TxCmdDmaSGId[CmdTCDSGIndex],
                                      (Dma_Ip_uintPtrType)&State->PhyUnitConfig->CmdDmaFast[Count].DmaFastPushrCmdLast,
                                      1u,   /* transfer last command to clear CS */
                                      DisHwRequest
                                     );
            CmdTCDSGIndex++;
        }
        else
        {
            Dspi_Ip_CmdDmaTcdSGConfig(Instance,
                                      State->PhyUnitConfig->TxCmdDmaSGId[CmdTCDSGIndex],
                                      (Dma_Ip_uintPtrType)&State->PhyUnitConfig->CmdDmaFast[Count].DmaFastPushrCmd,
                                      State->ExpectedCmdFifoWrites,
                                      DisHwRequest
                                     );
            CmdTCDSGIndex++;
        }

        State->ExpectedCmdFifoWrites = 0u;

        /* Configure software TCDs Scatter Gather for TX DMA channel */
        Dspi_Ip_TxDmaTcdSGConfig(Instance, Count, DisHwRequest);

        /* Configure software TCDs Scatter Gather for RX DMA channel */
        Dspi_Ip_RxDmaTcdSGConfig(Instance, Count, DisHwRequest);
    }

    /* When all transfers session are completed and next TCD ScatterGather is loaded to HW. If next TCD ScatterGather loaded has INTMAJOR=0 then
    Dma_Ip interrupt function will not call Spi Dma notification due to it understood as spurious interrupt(Done flag = 1, INTMAJOR=0).
    So, the workaround is set INTMAJOR=1 for next TCD ScatterGather. */
    if (NumberOfTransfer < State->PhyUnitConfig->NumberRxSG)
    {
        /* Set INTMAJOR=1 for next RX TCD ScatterGather */
        (void)Dma_Ip_SetLogicChannelScatterGatherList(State->PhyUnitConfig->RxDmaChannel, State->PhyUnitConfig->RxDmaFastSGId[NumberOfTransfer], DmaTcdList, 1u);
    }

    /* Load first software TCD to hardware TCD for CMD DMA channel */
    (void)Dma_Ip_SetLogicChannelScatterGatherConfig(State->PhyUnitConfig->TxCmdDmaChannel, State->PhyUnitConfig->TxCmdDmaSGId[0u]);
    /* Load first software TCD to hardware TCD for TX DMA channel */
    (void)Dma_Ip_SetLogicChannelScatterGatherConfig(State->PhyUnitConfig->TxDmaChannel, State->PhyUnitConfig->TxDmaFastSGId[0u]);
    /* Load first software TCD to hardware TCD for RX DMA channel */
    (void)Dma_Ip_SetLogicChannelScatterGatherConfig(State->PhyUnitConfig->RxDmaChannel, State->PhyUnitConfig->RxDmaFastSGId[0u]);

    /* Enable HW request for RX DMA channel before TX DMA channel */
    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->RxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxCmdDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
    (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxDmaChannel, DMA_IP_CH_SET_HARDWARE_REQUEST);
}

#endif /* if ((DSPI_IP_DMA_USED == STD_ON) && (DSPI_IP_ENABLE_DMAFASTTRANSFER_SUPPORT == STD_ON)) */

void Dspi_Ip_ManageBuffers(uint8 Instance)
{
    const Dspi_Ip_StateStructureType* State;
    #if (DSPI_IP_DMA_USED == STD_ON)
    Dma_Ip_LogicChannelStatusType DmaChannelStatus;
    #endif

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    State = Dspi_Ip_apxStateStructureArray[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    if (DSPI_IP_POLLING == State->TransferMode)
    {
        #if (DSPI_IP_DMA_USED == STD_ON)
        if ((boolean)FALSE == State->PhyUnitConfig->DmaUsed)
        #endif
        {
            Dspi_Ip_TransferProcess(Instance);
        }

        #if (DSPI_IP_DMA_USED == STD_ON)
        else
        {
            DmaChannelStatus.Done = FALSE;
            (void)Dma_Ip_GetLogicChannelStatus(State->PhyUnitConfig->RxDmaChannel, &DmaChannelStatus);
            if ((boolean)TRUE == DmaChannelStatus.Done)
            {
                /* Clear DONE bit */
                (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->RxDmaChannel, DMA_IP_CH_CLEAR_DONE);
                Dspi_Ip_IrqDmaHandler(Instance);
            }
        }
        #endif /* if (DSPI_IP_DMA_USED == STD_ON) */
    }
}

/*================================================================================================*/
Dspi_Ip_StatusType Dspi_Ip_UpdateTransferParam(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                               const Dspi_Ip_TransferAdjustmentType *Param)
{
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != ExternalDevice);
    DevAssert(NULL_PTR != Param);
    DevAssert(NULL_PTR != Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance]);
    #endif

    State = Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance];
        SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_08();
          if (State->Status != DSPI_IP_BUSY)
    {
        State->KeepCs = Param->KeepCs;
        if (Param->DeviceParams != NULL_PTR)
        {
            ExternalDevice->DeviceParams->DefaultData = Param->DeviceParams->DefaultData;
            ExternalDevice->DeviceParams->FrameSize = Param->DeviceParams->FrameSize;
            ExternalDevice->DeviceParams->Lsb = Param->DeviceParams->Lsb;
        }

                       SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_08();
                     }
    else
    {
                SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_08();
                  Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

Dspi_Ip_StatusType Dspi_Ip_UpdateFrameSize(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                           uint8 FrameSize)
{
    const Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(ExternalDevice != NULL_PTR);
    DevAssert(DSPI_IP_FRAMESIZE_MAX_U8 >= FrameSize);
    DevAssert(DSPI_IP_FRAMESIZE_MIN_U8 <= FrameSize);
    #endif
    State = Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    /* Frame size can be changed when no transfers are in progress. */
    if (State->Status != DSPI_IP_BUSY)
    {
        ExternalDevice->DeviceParams->FrameSize = FrameSize;
    }
    else
    {
        Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

Dspi_Ip_StatusType Dspi_Ip_UpdateLsb(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                     boolean Lsb)
{
    const Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(ExternalDevice != NULL_PTR);
    #endif
    State = Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    /* Bite order can be changed when no transfers are in progress. */
    if (State->Status != DSPI_IP_BUSY)
    {
        ExternalDevice->DeviceParams->Lsb = Lsb;
    }
    else
    {
        Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

Dspi_Ip_StatusType Dspi_Ip_UpdateDefaultTransmitData(const Dspi_Ip_ExternalDeviceType *ExternalDevice,
                                                     uint32 DefaultData)
{
    const Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(ExternalDevice != NULL_PTR);
    #endif
    State = Dspi_Ip_apxStateStructureArray[ExternalDevice->Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    /* Bite order can be changed when no transfers are in progress. */
    if (State->Status != DSPI_IP_BUSY)
    {
        ExternalDevice->DeviceParams->DefaultData = DefaultData;
    }
    else
    {
        Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

Dspi_Ip_StatusType Dspi_Ip_UpdateTransferMode(uint8 Instance,
                                              Dspi_Ip_ModeType Mode)
{
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    State = Dspi_Ip_apxStateStructureArray[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    /* Transfer mode can be changed when no transfers are in progress. */
    if (State->Status != DSPI_IP_BUSY)
    {
        State->TransferMode = Mode;
    }
    else
    {
        Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

void Dspi_Ip_Cancel(uint8 Instance)
{
    DSPI_Type* Base;
    Dspi_Ip_StateStructureType* State;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    Base = Dspi_Ip_apxBases[Instance];
    State = Dspi_Ip_apxStateStructureArray[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
               SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_10();
                 if (DSPI_IP_BUSY == State->Status)
    {
        /* Halt before update RSER */
        Base->MCR |= DSPI_MCR_HALT_MASK;
        /* Disable interrupts and DMA requests. */
        Base->RSER = 0U;
        #if (DSPI_IP_DMA_USED == STD_ON)
        if ((boolean)TRUE == State->PhyUnitConfig->DmaUsed)
        {
            /* Disable all HW request */
            (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->RxDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
            #if (DSPI_IP_SLAVE_SUPPORT == STD_ON)
            if ((boolean)FALSE == State->PhyUnitConfig->SlaveMode)
            #endif
            {
                (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxCmdDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
            }

            (void)Dma_Ip_SetLogicChannelCommand(State->PhyUnitConfig->TxDmaChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST);
        }

        #endif /* if (DSPI_IP_DMA_USED == STD_ON) */
        /* Clear FIFO */
        Base->MCR |= (DSPI_MCR_CLR_RXF_MASK | DSPI_MCR_CLR_TXF_MASK);
        /* set State to idle */
        State->Status = DSPI_IP_IDLE;
    }

        SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_10();
      }

/**
* @brief   This function is called by SPI ISRs.
* @details This function will process activities for flags TCF
*
* @param[in]     Instance            Instance of the hardware unit.
*
* @implements Dspi_Ip_IrqHandler_Activity
*/
void Dspi_Ip_IrqHandler(uint8 Instance)
{
    DSPI_Type* Base = Dspi_Ip_apxBases[Instance];
    const Dspi_Ip_StateStructureType* State = Dspi_Ip_apxStateStructureArray[Instance];
    uint32 IrqFlags = 0u;

    if (NULL_PTR != State)
    {
        /* the driver has been initialized */
        IrqFlags = Base->SR & (DSPI_SR_TCF_MASK | DSPI_SR_RFOF_MASK);
        IrqFlags &= Base->RSER & (DSPI_RSER_TCF_RE_MASK | DSPI_RSER_RFOF_RE_MASK);
        if (0u != IrqFlags)
        {
            Dspi_Ip_TransferProcess(Instance);
        }
        else
        {
            /* Do nothing - Return immediately */
        }
    }
    else
    {
        /* the driver has not been initialized */
        /* clear all flags */
        Base->SR &= 0xFFFF0000u;
    }
}

/* Dspi_Ip_GetStatus */
Dspi_Ip_HwStatusType Dspi_Ip_GetStatus(uint8 Instance)
{
    const Dspi_Ip_StateStructureType* State;
    Dspi_Ip_HwStatusType Status = DSPI_IP_UNINIT;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    State = Dspi_Ip_apxStateStructureArray[Instance];
    if (State != NULL_PTR)
    {
        Status = State->Status;
    }

    return Status;
}

#if (DSPI_IP_DUAL_CLOCK_MODE == STD_ON)
Dspi_Ip_StatusType Dspi_Ip_SetClockMode(uint8 Instance,
                                        Dspi_Ip_DualClockModeType ClockMode)
{
    Dspi_Ip_StateStructureType* State;
    Dspi_Ip_StatusType Status = DSPI_IP_STATUS_SUCCESS;

    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < DSPI_INSTANCE_COUNT);
    #endif
    State = Dspi_Ip_apxStateStructureArray[Instance];
    #if (DSPI_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(State != NULL_PTR);
    #endif
    /* Clock mode can be changed when no transfers are in progress. */
    if (State->Status != DSPI_IP_BUSY)
    {
        State->ClockMode = ClockMode;
    }
    else
    {
        Status = DSPI_IP_STATUS_FAIL;
    }

    return Status;
}

#endif /* if (DSPI_IP_DUAL_CLOCK_MODE == STD_ON) */

#define SPI_STOP_SEC_CODE
#include "Spi_MemMap.h"

#endif /*(STD_ON == DSPI_IP_ENABLE)*/

#ifdef __cplusplus
}
#endif

/** @} */
