/*!
* @file     Spi_Hw.c
*
* @version  1.0.0
*
* @brief    The source file of the SPI driver.This source file contains the API specification and other variables of the Common SPI driver.
*
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_15-Nov-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

/*
* MISRA-C:2012 compliance checks
*
*     Spi_Hw_c_MISRA_REF1
*          Breaks the required Rule-18.4 of MISRA 2012 guidelines, 
*          The +, -, += and -= operators should not be applied to an expression of pointer type.
*
*     Spi_Hw_c_MISRA_REF2
*          Breaks the required Rule-11.3 of MISRA 2012 guidelines, 
*          A conversion shall not be performed between a pointer to object type and a pointer to a different object type.
*
*     Spi_Hw_c_MISRA_REF3
*          Breaks the required Rule-11.8 of MISRA 2012 guidelines, 
*          A cast shall not remove any const or volatile qualification from the type pointed to by a pointer.
*
*/

#ifdef __cplusplus
extern "C"
{
#endif

#include "Mcal.h"
#include "Spi.h"
#include "Spi_Hw.h"
#if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)
    #include "Dem.h"
#endif
#include "Spi_Reg.h"
#include "Mcu_RcmTypes.h"
#if (STD_ON == SPI_DMA_SUPPORT)
    #include "CDD_Pdl.h"
    #include "Pdl_DmaTypes.h"
#endif
/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup SPI_Driver
  * @brief SPI driver modules
  @{
*/

/** @defgroup SPI_Macros
  @{
*/
/**************************************************************************
                  VENDOR ID & AUTOSAR VERSION INFO
**************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define SPI_HW_VENDOR_ID                        0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_HW_AR_RELEASE_MAJOR_VERSION         0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_HW_AR_RELEASE_MINOR_VERSION         0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_HW_AR_RELEASE_REVISION_VERSION      0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_HW_SW_MAJOR_VERSION                 0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_HW_SW_MINOR_VERSION                 0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_HW_SW_PATCH_VERSION                 0x00U

/**************************************************************************
                    VERSION INFOMATION VERIFICATION
**************************************************************************/

#ifdef ENABLE_INTERMODULE_MCAL_CHECK

    /* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and Mcal.h */
    #if (SPI_HW_AR_RELEASE_MAJOR_VERSION != MCAL_H_AR_RELEASE_MAJOR_VERSION) 
        #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and Mcal.h"
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and Mcal.h */
    #if (SPI_HW_AR_RELEASE_MINOR_VERSION != MCAL_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and Mcal.h"
    #endif
    
    #if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)
        /* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and Dem.h */
        #if (SPI_HW_AR_RELEASE_MAJOR_VERSION != DEM_H_AR_RELEASE_MAJOR_VERSION) 
            #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and Dem.h"
        #endif
        /* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and Dem.h */
        #if (SPI_HW_AR_RELEASE_MINOR_VERSION != DEM_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and Dem.h"
        #endif
    #endif
  
    #if (STD_ON == SPI_DMA_SUPPORT)
        /* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and CDD_Pdl.h */
        #if (SPI_HW_AR_RELEASE_MAJOR_VERSION != CDD_PDL_H_AR_RELEASE_MAJOR_VERSION) 
            #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and CDD_Pdl.h"
        #endif
        /* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and CDD_Pdl.h */
        #if (SPI_HW_AR_RELEASE_MINOR_VERSION != CDD_PDL_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and CDD_Pdl.h"
        #endif
    #endif

#endif

/* Make sure the vendor id is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_VENDOR_ID != SPI_REG_H_VENDOR_ID)
    #error "Vendor id mismatch between Spi_Drv.c and Spi_Reg.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_AR_RELEASE_MAJOR_VERSION != SPI_REG_H_AR_RELEASE_MAJOR_VERSION) 
    #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif
/* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_AR_RELEASE_MINOR_VERSION != SPI_REG_H_AR_RELEASE_MINOR_VERSION) 
    #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif
/* Make sure the AUTOSAR revision version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_AR_RELEASE_REVISION_VERSION != SPI_REG_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif
/* Make sure the software major version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_SW_MAJOR_VERSION != SPI_REG_H_SW_MAJOR_VERSION) 
    #error "Software Major Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif
/* Make sure the software minor version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_SW_MINOR_VERSION != SPI_REG_H_SW_MINOR_VERSION) 
    #error "Software Minor Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif
/* Make sure the software patch version number is the same between Spi_Drv.c and Spi_Reg.h */
#if (SPI_HW_SW_PATCH_VERSION != SPI_REG_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Spi_Drv.c and Spi_Reg.h "
#endif

/* Make sure the vendor id is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_VENDOR_ID != SPI_HW_H_VENDOR_ID)
    #error "Vendor id mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_AR_RELEASE_MAJOR_VERSION != SPI_HW_H_AR_RELEASE_MAJOR_VERSION) 
    #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_AR_RELEASE_MINOR_VERSION != SPI_HW_H_AR_RELEASE_MINOR_VERSION) 
    #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_AR_RELEASE_REVISION_VERSION != SPI_HW_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the software major version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_SW_MAJOR_VERSION != SPI_HW_H_SW_MAJOR_VERSION) 
    #error "Software Major Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the software minor version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_SW_MINOR_VERSION != SPI_HW_H_SW_MINOR_VERSION) 
    #error "Software Minor Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif
/* Make sure the software patch version number is the same between Spi_Drv.c and Spi_Drv.h */
#if (SPI_HW_SW_PATCH_VERSION != SPI_HW_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Spi_Drv.c and Spi_Drv.h"
#endif

/* Make sure the vendor id is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_VENDOR_ID != SPI_H_VENDOR_ID)
    #error "Vendor id mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_AR_RELEASE_MAJOR_VERSION != SPI_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR Major Version Number mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_AR_RELEASE_MINOR_VERSION != SPI_H_AR_RELEASE_MINOR_VERSION) 
    #error "AUTOSAR Minor Version Number mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_AR_RELEASE_REVISION_VERSION != SPI_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the software major version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_SW_MAJOR_VERSION != SPI_H_SW_MAJOR_VERSION) 
    #error "Software Major Version Number mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the software minor version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_SW_MINOR_VERSION != SPI_H_SW_MINOR_VERSION) 
    #error "Software Minor Version Number mismatch between Spi_Drv.c and Spi.h"
#endif
/* Make sure the software patch version number is the same between Spi_Drv.c and Spi.h */
#if (SPI_HW_SW_PATCH_VERSION != SPI_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Spi_Drv.c and Spi.h"
#endif

/**************************************************************************
                    LOCAL MACRO DEFINITION
**************************************************************************/
#if ( LEVEL1 != SPI_LEVEL_DELIVERED )
    #define SPI_NORMAL_SYNCTRANS 0u
    #define SPI_FAST_SYNCTRANS   1u
#endif
/**@} end of group SPI_Macros */
/**************************************************************************
                    LOCAL VARIABLE
**************************************************************************/
/** @defgroup SPI_Variable
  @{
*/
#define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

#if (LEVEL1 != SPI_LEVEL_DELIVERED) 
    /**  Synchronous transmission state */
    static VAR(Spi_SyncProcessStateType, SPI_VAR) s_SpiSyncTransState[SPI_HWUNITCFG_NUM];
    #if (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE)
        /**  Cached information of OPTIMIZED SEQUENCE */
        static VAR(Spi_CachedSeqAttrType, SPI_VAR) s_spiSeqAttr[SPI_ONEJOBSEQ_BUFFER_SIZE];
        /**  Cached information of OPTIMIZED CHANNEL */
        static VAR(Spi_CachedChannelAttrType, SPI_VAR) s_spiChannelAttr[SPI_ONEJOBSEQCHANNEL_BUFFER_SIZE];
    #endif
#endif  

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    #if (STD_ON == SPI_DMA_SUPPORT)
        /**  DMA TCD Attributes descriptor */
        static VAR(Pdl_DmaChHwConfigType, SPI_VAR) s_SpiDmaChHwConfigPtr;
    #endif
#endif 

#define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

/**************************************************************************
                    CONSTANT DEFINITION
**************************************************************************/
#define SPI_START_SEC_CONST_32
#include "Spi_MemMap.h"
 
/**  Base address mapping of HardWare Unit */
CONST(uint32, SPI_CONST) SPI_BASEADDRESS[SPI_HWUNITCFG_NUM] = {SPI1_BASEADDR};

#if (STD_OFF != SPI_DMA_SUPPORT)
    /**  Channel x Transfer Complete interrupt flag */
    const Pdl_DmaChFlagType dmaTfFlags[] = {
        DMA1_FLAG_TF1,
        DMA1_FLAG_TF2,
        DMA1_FLAG_TF3,
        DMA1_FLAG_TF4,
        DMA1_FLAG_TF5
    };
#endif

#define SPI_STOP_SEC_CONST_32
#include "Spi_MemMap.h"

/**************************************************************************
                    GLOBAL VARIABLE
**************************************************************************/
#define SPI_START_SEC_VAR_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

#if (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE)
    /** Pointer table to the cached information structure for the sequences having only one job */
    P2VAR(Spi_CachedSeqAttrType, SPI_VAR, SPI_APPL_DATA) spiSingleJobSeqOptPtr[SPI_SEQCFG_NUM] = 
    {NULL_PTR};
#endif

#define SPI_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

#define SPI_START_SEC_VAR_NO_INIT_32
#include "Spi_MemMap.h"

/** Used to abandon data */
static VAR(volatile uint32, SPI_VAR) s_SpiReadAbandon;

#define SPI_STOP_SEC_VAR_NO_INIT_32
#include "Spi_MemMap.h"

#if (STD_ON == SPI_DMA_SUPPORT) 
    #if LEVEL0 != SPI_LEVEL_DELIVERED
        #define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED_NO_CACHEABLE
        #include "Spi_MemMap.h"
        
        /** Used to store SPI HWUnit state */
        VAR(Spi_HwStateType, SPI_VAR) g_SpiHwUnitState[SPI_HWUNITCFG_NUM];
        
        #define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED_NO_CACHEABLE
        #include "Spi_MemMap.h"
    #else
        #define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
        #include "Spi_MemMap.h"
        
        /** Used to store SPI HWUnit state */
        VAR(Spi_HwStateType, SPI_VAR) g_SpiHwUnitState[SPI_HWUNITCFG_NUM];
        
        #define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
        #include "Spi_MemMap.h"
    #endif
#else
    #define SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
    #include "Spi_MemMap.h"
    
    /** Used to store SPI HWUnit state */
    VAR(Spi_HwStateType, SPI_VAR) g_SpiHwUnitState[SPI_HWUNITCFG_NUM];
    
    #define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
    #include "Spi_MemMap.h"
#endif 
/**@} end of group SPI_Variable */
/**************************************************************************
                    LOCAL FUNCTION DECLARATION
**************************************************************************/
/** @defgroup SPI_Fuctions
  @{
*/
#define SPI_START_SEC_CODE
#include "Spi_MemMap.h"

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
LOCAL_INLINE FUNC(boolean, SPI_CODE) Spi_Hw_IsAsyncPhyUnit \
    (P2CONST(Spi_HwStateType, AUTOMATIC, SPI_APPL_CONST) HwStatePtr)
{
    return (boolean)((uint32)SPI_PHYUNIT_ASYNC_U32
        == (uint32)HwStatePtr->spiHwUnitCfgPtr->syncMode);
}

LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_InitRuntimeState \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr)
{
    HwStatePtr->spiAsyncMode = SPI_POLLING_MODE;
    HwStatePtr->spiCurrentJobPtr = NULL_PTR;
    HwStatePtr->spiCurTxChanIndexListPtr = NULL_PTR;
    HwStatePtr->spiCurRxChanIndexListPtr = NULL_PTR;
    HwStatePtr->spiCurrentTxBufPtr = NULL_PTR;
    HwStatePtr->spiCurrentRxBufPtr = NULL_PTR;
    HwStatePtr->spiRemainTxChannels = 0u;
    HwStatePtr->spiRemainRxChannels = 0u;
    HwStatePtr->spiRemainFrames = 0u;
    HwStatePtr->spiReceivedData = 0u;
    HwStatePtr->spiIsEndJob = (boolean)FALSE;
    HwStatePtr->spiIsTxPollReq = 0u;
    HwStatePtr->spiIsRxPollReq = 0u;
}
#endif

#if (LEVEL1 != SPI_LEVEL_DELIVERED)
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_SyncFlushRxFifo(void)
{
    VAR(uint32, AUTOMATIC) sts = 0u;
    VAR(sint32, AUTOMATIC) guard = (sint32)SPI_TIMEOUT_NUMBER;

    while (guard > (sint32)0)
    {
        sts = REG_READ32(SPI_STS_ADDRESS_U32);
        if (((sts & SPI_STS_RXBNEFLG) == 0u) && ((sts & SPI_STS_FRLSEL) == 0u))
        {
            break;
        }
        (void)REG_READ8(SPI_DATA_ADDRESS_U32);
        guard--;
    }
    if ((sts & SPI_STS_OVRFLG) != 0u)
    {
        REG_BIT_CLEAR32(SPI_STS_ADDRESS_U32, SPI_STS_OVRFLG);
    }
}

#if (STD_ON == SPI_SLAVE_SUPPORT)
LOCAL_INLINE FUNC(boolean, SPI_CODE) Spi_Hw_SyncIsSlaveJob \
    (P2CONST(Spi_SyncProcessStateType, AUTOMATIC, SPI_APPL_CONST) SyncTransmitStatePtr)
{
    return (boolean)(0u == (SyncTransmitStatePtr->spiJobCmd & SPI_CTRL1_MSMCFG));
}

LOCAL_INLINE FUNC(boolean, SPI_CODE) Spi_Hw_SyncIsSlaveIdleWait \
    (P2CONST(Spi_SyncProcessStateType, AUTOMATIC, SPI_APPL_CONST) SyncTransmitStatePtr,
     VAR(Std_ReturnType, AUTOMATIC) TxStatus,
     VAR(Std_ReturnType, AUTOMATIC) RxStatus)
{
    VAR(uint32, AUTOMATIC) stsVal;

    if ((boolean)FALSE == Spi_Hw_SyncIsSlaveJob(SyncTransmitStatePtr))
    {
        return (boolean)FALSE;
    }
    if (((Std_ReturnType)E_OK == TxStatus) || ((Std_ReturnType)E_OK == RxStatus))
    {
        return (boolean)FALSE;
    }
    if ((0u == SyncTransmitStatePtr->spiTxLength) && (0u == SyncTransmitStatePtr->spiRxLength))
    {
        return (boolean)FALSE;
    }

    stsVal = REG_READ32(SPI_STS_ADDRESS_U32);
    if ((0u == (stsVal & SPI_STS_FRLSEL)) && (0u == (stsVal & SPI_STS_RXBNEFLG)))
    {
        /* No RX yet: waiting for master SCK (TX may still be pending in SW or HW) */
        return (boolean)TRUE;
    }
    if ((SyncTransmitStatePtr->spiTxLength > 0u) && (0u == (stsVal & SPI_STS_TXBEFLG)))
    {
        /* Next TX byte cannot load until current one shifts out */
        return (boolean)TRUE;
    }
    return (boolean)FALSE;
}
#endif
#endif

#if ((STD_ON == SPI_DMA_SUPPORT) && (LEVEL0 != SPI_LEVEL_DELIVERED))
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaIrqCfg \
   (P2CONST(Spi_HwStateType, AUTOMATIC, SPI_APPL_CONST) HwStatePtr, VAR(Spi_AsyncModeType, AUTOMATIC) AsyncMode);
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaChanTXInit \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaChanRXInit \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_JobDmaTXContinue \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_JobDmaRXContinue \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr );
#endif

#if (LEVEL0 != SPI_LEVEL_DELIVERED )
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_ChanTXTransFifoInit \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr,VAR(Spi_ChannelType, AUTOMATIC) Channel);
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_ChanRXTransFifoInit \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr,VAR(Spi_ChannelType, AUTOMATIC) Channel);
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_GetFifoData \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_FillTransFifo \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_SetTxFifo \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(uint8, AUTOMATIC) JobEndFlg );
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_TransStatus \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr,VAR(uint32, AUTOMATIC) TxIsrStatus, \
     VAR(uint32, AUTOMATIC) RxIsrStatus);
#endif

#if (LEVEL1 != SPI_LEVEL_DELIVERED)
LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTXTrans
    ( P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr );
LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncRXTrans
    ( P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr, VAR(uint8, AUTOMATIC) SyncType);
static FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTransJob
    ( P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr );
#endif

/**************************************************************************
                    LOCAL FUNCTION
**************************************************************************/
/*!
* @brief    Initializes function of the SPI driver.
* 
* @param[in]      HwUnitId    HWUnit ID
* @param[in]      StatusPtr   pointer to HWUnit State
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_Init
    (VAR(Spi_HWUnitType, AUTOMATIC) HwUnitId,P2VAR(Spi_StatusType, AUTOMATIC, SPI_APPL_DATA) StatusPtr)
{
    P2CONST(Spi_DeviceAttrCfgType, AUTOMATIC, SPI_APPL_CONST) devAttrCfgPtr = NULL_PTR;
    P2CONST(Spi_HWUnitConfigType, AUTOMATIC, SPI_APPL_CONST) spiHwUnitCfgPtr = &g_spiCfgPtr->pcHWUnitCfgPtr[HwUnitId];
    VAR(uint32, AUTOMATIC) jobId = 0;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr;
    /* Initializes the pcs chip inactive states as high */
    VAR(uint32, AUTOMATIC) pcsCRCPOLY = (SPI_CRCPOLY_DEFAULT); 
    /* Get the specific HWUnit state and pointer to them */
    P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) hwStatePtr = &g_SpiHwUnitState[HwUnitId];

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    /* g_SpiHwUnitState is NO_INIT when DMA is enabled */
    Spi_Hw_InitRuntimeState(hwStatePtr);
#endif

    /* cache the specific HWUnit base address */
    hwStatePtr->spiBaseAddress = SPI_GET_BASE_ADDR32;
    
    /* Disable poll request */
    hwStatePtr->spiIsPollReqEn = 0u;

    /* cache the specific register address */
    hwStatePtr->spiCtrl1Addr = SPI_CTRL1_ADDRESS_U32;
    hwStatePtr->spiCtrl2Addr = SPI_CTRL2_ADDRESS_U32;
    hwStatePtr->spiStsAddr  = SPI_STS_ADDRESS_U32;
    hwStatePtr->spiDataAddr = SPI_DATA_ADDRESS_U32;
    hwStatePtr->spiCrcPolyAddr = SPI_CRCPOLY_ADDRESS_U32;
    hwStatePtr->spiRxCrcAddr = SPI_RXCRC_ADDRESS_U32;
    hwStatePtr->spiTxCrcAddr = SPI_TXCRC_ADDRESS_U32;
    
    /* Get the specific HWUnit configuration and pointer to them */
    hwStatePtr->spiHwUnitCfgPtr = spiHwUnitCfgPtr;
    hwStatePtr->spiStatusPtr = StatusPtr;

    /* Get the pcs chip configuration status */
    while(jobId <= (uint32)(g_spiCfgPtr->maxJob))
    {
        jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
        if (jobCfgPtr->jobHWUnit == HwUnitId)
        {
            /* Get external device attributes configuration and status */
            devAttrCfgPtr = (g_spiCfgPtr->pcAttrCfgPtr->spiDevAttrCfgPtr)[jobCfgPtr->extDevType];
            pcsCRCPOLY = (uint32)(pcsCRCPOLY | (devAttrCfgPtr->cfgCRCPOLY));
        }
        /* Un-Used HwUnit */
        else 
        {
            /* No Operation */
        }
        jobId++;
    }
    /* Set the SPI HWUnit registers according to the configuration */
    REG_WRITE32(SPI_CRCPOLY_ADDRESS_U32, (pcsCRCPOLY & SPI_CRCPOLY_BITS_MASK));
    
    if(devAttrCfgPtr != NULL_PTR)
    {
        REG_WRITE32(SPI_CTRL2_ADDRESS_U32, (devAttrCfgPtr->cfgCTRL2 & SPI_CTRL2_BITS_MASK));
    }
    else 
    {
        /* No Operation */
    }
#if ((LEVEL0 != SPI_LEVEL_DELIVERED) && (STD_ON == SPI_DMA_SUPPORT))
    /* Un-Used DMA */
    if ((uint16)FALSE == spiHwUnitCfgPtr->useDma) 
    {
        /* No Operation */
    }
    /* initialize SPI DMA related fields */
    else 
    {
        /* Get the txDma Channel adress of the Transfer Control Descriptor (TCD) */
        hwStatePtr->spiTxDmaTcdPtr = (uint32 *)g_spiCfgPtr->pcChannelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr;
        /* Get the rxDma Channel adress of the Transfer Control Descriptor (TCD) */
        hwStatePtr->spiRxDmaTcdPtr = &(hwStatePtr->spiDataAddr);
        /* Config the DMA channel of TX */
        /* source address to read */
        s_SpiDmaChHwConfigPtr.memAddr = (uint32)(hwStatePtr->spiTxDmaTcdPtr);
        /* destination address */ 
        s_SpiDmaChHwConfigPtr.periphAddr = hwStatePtr->spiDataAddr;
#if (SPI_DATASIZE_CONFIG_8 == STD_ON)
        /* 8-bit SPI frame: DMA moves one byte per minor transfer */
        s_SpiDmaChHwConfigPtr.periphDataWidth = DMA_PERIPHERAL_DATASIZE_BYTE;
        s_SpiDmaChHwConfigPtr.memDataWidth = DMA_MEMORY_DATASIZE_BYTE;
        if (SPI_TRANS_ONCE_LENGTH > SPI_MAX_ROUND_CNT_OF_DMA)
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_MAX_ROUND_CNT_OF_DMA;
        }
        else
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_TRANS_ONCE_LENGTH;
        }
#else
        /* 16-bit SPI frame: DMA minor transfer must be half-word (matches framesCnt in DmaChanTXInit) */
        s_SpiDmaChHwConfigPtr.periphDataWidth = DMA_PERIPHERAL_DATASIZE_HALFWORD;
        s_SpiDmaChHwConfigPtr.memDataWidth = DMA_MEMORY_DATASIZE_HALFWORD;
        if ((SPI_TRANS_ONCE_LENGTH / 2u) > SPI_MAX_ROUND_CNT_OF_DMA)
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_MAX_ROUND_CNT_OF_DMA;
        }
        else
        {
            s_SpiDmaChHwConfigPtr.bufSize = (SPI_TRANS_ONCE_LENGTH / 2u);
        }
#endif
        /* Memory Address Increment Mode */
        s_SpiDmaChHwConfigPtr.memInc  = DMA_MEMORY_INC_ENABLE;
        /* Peripheral Address Increment Mode */
        s_SpiDmaChHwConfigPtr.periphInc  = DMA_PERIPHERAL_INC_DISABLE;
        /* Circular Mode */
        s_SpiDmaChHwConfigPtr.circularMode  = DMA_CIRCULAR_DISABLE;
        /* Channel Priority Level Configure */
        s_SpiDmaChHwConfigPtr.priority  = DMA_PRIORITY_LEVEL_HIGHT;
        /* Memory to memory disable */
        s_SpiDmaChHwConfigPtr.mem2Mem = DMA_M2M_DISABLE;
        /* Data Transfer Direction Configure */
        s_SpiDmaChHwConfigPtr.dir  = DMA_DIR_MEMORY;
        /* configure the DMA channel */
        Pdl_TopDmaChConfig(spiHwUnitCfgPtr->txDmaChannel, &s_SpiDmaChHwConfigPtr);
        /* Clear channelx Transfer Complete interrupt flag */
        Pdl_TopDmaChStsFlagClr(dmaTfFlags[spiHwUnitCfgPtr->txDmaChannel - 1]);
        
        /* Config the DMA channel of RX */
        /* source address to read */
        s_SpiDmaChHwConfigPtr.memAddr = (uint32 )g_spiCfgPtr->pcChannelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr;
        /* destination address */
        s_SpiDmaChHwConfigPtr.periphAddr = hwStatePtr->spiDataAddr;
#if (SPI_DATASIZE_CONFIG_8 == STD_ON)
        s_SpiDmaChHwConfigPtr.periphDataWidth = DMA_PERIPHERAL_DATASIZE_BYTE;
        s_SpiDmaChHwConfigPtr.memDataWidth = DMA_MEMORY_DATASIZE_BYTE;
        if (SPI_TRANS_ONCE_LENGTH > SPI_MAX_ROUND_CNT_OF_DMA)
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_MAX_ROUND_CNT_OF_DMA;
        }
        else
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_TRANS_ONCE_LENGTH;
        }
#else
        s_SpiDmaChHwConfigPtr.periphDataWidth = DMA_PERIPHERAL_DATASIZE_HALFWORD;
        s_SpiDmaChHwConfigPtr.memDataWidth = DMA_MEMORY_DATASIZE_HALFWORD;
        if ((SPI_TRANS_ONCE_LENGTH / 2u) > SPI_MAX_ROUND_CNT_OF_DMA)
        {
            s_SpiDmaChHwConfigPtr.bufSize = SPI_MAX_ROUND_CNT_OF_DMA;
        }
        else
        {
            s_SpiDmaChHwConfigPtr.bufSize = (SPI_TRANS_ONCE_LENGTH / 2u);
        }
#endif
        /* Memory Address Increment Mode */
        s_SpiDmaChHwConfigPtr.memInc  = DMA_MEMORY_INC_ENABLE;
        /* Peripheral Address Increment Mode */
        s_SpiDmaChHwConfigPtr.periphInc  = DMA_PERIPHERAL_INC_DISABLE; 
        /* Circular Mode */
        s_SpiDmaChHwConfigPtr.circularMode  = DMA_CIRCULAR_DISABLE;
        /* Channel Priority Level Configure */
        s_SpiDmaChHwConfigPtr.priority  = DMA_PRIORITY_LEVEL_HIGHT; 
        /* Memory to memory disable */
        s_SpiDmaChHwConfigPtr.mem2Mem = DMA_M2M_DISABLE;
        /* Data Transfer Direction Configure */
        s_SpiDmaChHwConfigPtr.dir  = DMA_DIR_PERIPHERAL;
        /* configure the DMA channel */
        Pdl_TopDmaChConfig(spiHwUnitCfgPtr->rxDmaChannel, &s_SpiDmaChHwConfigPtr);
        /* Clear channelx Transfer Complete interrupt flag */
        Pdl_TopDmaChStsFlagClr(dmaTfFlags[spiHwUnitCfgPtr->rxDmaChannel - 1]);
    }
#endif
    if(devAttrCfgPtr != NULL_PTR)
    {
        REG_WRITE32(SPI_CTRL1_ADDRESS_U32, (devAttrCfgPtr->cfgCTRL1 & SPI_CTRL1_BITS_MASK));
    }
    else
    {
        /* No Operation */
    }
}

/*!
* @brief    De-initialize a specific peripheral unit of the SPI driver.
* 
* @param[in] HWUnitId      HWUnit ID
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_DeInit( VAR(Spi_HWUnitType, AUTOMATIC) HWUnitId )
{
    VAR(sint32, AUTOMATIC) timeOut = 0;
    for(timeOut = (sint32)SPI_TIMEOUT_NUMBER; timeOut > 0; timeOut--)
    {
        if((uint32)(REG_READ32(SPI_STS_ADDRESS_U32) & (SPI_STS_FTLSEL | SPI_STS_BSYFLG | SPI_STS_FRLSEL)) == (uint32)0)
        {
            /* Reset the SPI Control Register */
            REG_WRITE32(SPI_BASEADDRESS[HWUnitId], SPI_CTRL1_RESET);
            REG_WRITE32(SPI_BASEADDRESS[HWUnitId], SPI_CTRL2_RESET);
            break;
        }
        else
        {
            /* No Operation */
        }
    }
    /* Soft reset the controller */
    Mcu_Rcm_OperationPeriphReset(ENABLE, RCM_APB2_PERIPH, RCM_AHBRST2_SPI1);
    Mcu_Rcm_OperationPeriphReset(DISABLE, RCM_APB2_PERIPH, RCM_AHBRST2_SPI1);
}

#if ((STD_ON == SPI_DMA_SUPPORT) && (LEVEL0 != SPI_LEVEL_DELIVERED ))
/*!
* @brief    Service for TX DMA channels's IRQ  
* 
* @param[in] HwStatePtr    Pointer to HWUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_IsrTxDma( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr )
{
    VAR(Spi_AsyncModeType, AUTOMATIC) spiAsyncMode = HwStatePtr->spiAsyncMode;
    VAR(uint32, AUTOMATIC) isrStatus  = (uint32)FALSE;
    VAR(uint32, AUTOMATIC) dmaSpiStatus = 0u;

    /* check Driver initialized */
    if (NULL_PTR == g_spiCfgPtr)
    {
        /* Driver not initialized , No Operation */
    }
    else if ((boolean)FALSE == Spi_Hw_IsAsyncPhyUnit(HwStatePtr))
    {
        /* Sync transfer owns SPI HW; ignore DMA async completion path */
    }
    else 
    {
        /* check Async Mode */
        switch(spiAsyncMode)
        {
            case SPI_INTERRUPT_MODE:
            {
                isrStatus = (uint8)TRUE;
                break;
            }
            case SPI_POLLING_MODE:
            {
                /* Get poll TX request status */
                isrStatus = (uint8)HwStatePtr->spiIsTxPollReq;
                /* Clear poll TX request state */
                HwStatePtr->spiIsTxPollReq = (uint8)FALSE;
                break;
            }
            default:
                /* No Operation */
                break;
        }
        /* Check:have poll request or operate SPI_INTERRUPT_MODE */
        switch(isrStatus)
        {
            /* SPI_POLLING_MODE and no poll request */
            case FALSE: 
            {
                /* No Operation */
                break; 
            }
            default:
            {
                /* current channel transfer continue */
                if (0u != HwStatePtr->spiRemainFrames) 
                {
                    /* Continue transmit next frames */
                    Spi_Hw_JobDmaTXContinue(HwStatePtr);
                }
                /* check: if have channels to be transmited */
                else if (0u != HwStatePtr->spiRemainTxChannels) 
                {
                    /* update Channel information of list */
                    HwStatePtr->spiRemainTxChannels--;
                    HwStatePtr->spiCurTxChanIndexListPtr++;
                    /* plan next DMA Tx channel */
                    Spi_Hw_DmaChanTXInit(HwStatePtr,*(HwStatePtr->spiCurTxChanIndexListPtr));
                }
                /* no Remain DMA Tx Channels */
                else 
                {
                    /* Close job only when SPI HW is really idle. */
                    dmaSpiStatus = REG_READ32(HwStatePtr->spiStsAddr);
                    if ((uint32)0u == (dmaSpiStatus & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                    {
                        /* Disable Receive/Transmit Data DMA */
                        REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_RXDEN | SPI_CTRL2_TXDEN));
                        /* Job transmission end */
                        Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
                    }
                    else
                    {
                        /* RX still running, wait for RX completion */
                    }
                }
                break;
            }
        }
    }
}
        
/*!
* @brief    Service for RX DMA channels's IRQ  
* 
* @param[in] HwStatePtr     pointer to HWUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_IsrRxDma( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr )
{
    VAR(Spi_AsyncModeType, AUTOMATIC) spiAsyncMode = HwStatePtr->spiAsyncMode;
    VAR(uint8, AUTOMATIC) isrStatus  = (uint8)FALSE;
    VAR(uint32, AUTOMATIC) dmaSpiStatus = 0u;

    /* check: Driver is initialized */
    if (NULL_PTR == g_spiCfgPtr)
    {
        /* Driver is not initialized , No Operation */
    }
    else if ((boolean)FALSE == Spi_Hw_IsAsyncPhyUnit(HwStatePtr))
    {
        /* Sync transfer owns SPI HW; ignore DMA async completion path */
    }
    else 
    {
        /* check Async Mode */
        switch(spiAsyncMode)
        {
            case SPI_INTERRUPT_MODE:
            {
                isrStatus = (uint8)TRUE;
                break;
            }
            case SPI_POLLING_MODE:
            {
                /* Get poll TX request status */
                isrStatus = (uint8)HwStatePtr->spiIsRxPollReq;
                /* Clear poll TX request state */
                HwStatePtr->spiIsRxPollReq = (uint8)FALSE;
                break;
            }
            default:
                /* No Operation */
                break;
        }
        /* Check:have poll request or operate SPI_INTERRUPT_MODE */
        switch(isrStatus)
        {
            case FALSE:
            {
                break; 
            }
            default:
            {   
                /* current channel transfer continue */
                if ( 0u != HwStatePtr->spiReceivedData ) 
                {
                    /* Continue transmit next frames */
                    Spi_Hw_JobDmaRXContinue(HwStatePtr);
                }
                /* check: if have channels to be transmited */
                else if (0u != HwStatePtr->spiRemainRxChannels) 
                {
                    /* update Channel information of list */
                    HwStatePtr->spiRemainRxChannels--;
                    HwStatePtr->spiCurRxChanIndexListPtr++;
                    /* plan next DMA Tx channel */
                    Spi_Hw_DmaChanRXInit(HwStatePtr,*(HwStatePtr->spiCurRxChanIndexListPtr));
                }
                /* no Remain DMA Tx Channels */
                else 
                {
                    /* Close job only when SPI HW is really idle. */
                    dmaSpiStatus = REG_READ32(HwStatePtr->spiStsAddr);
                    if ((uint32)0u == (dmaSpiStatus & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                    {
                        /* Disable Receive/Transmit Data DMA*/
                        REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_RXDEN | SPI_CTRL2_TXDEN));
                        /* Job transmission end */
                        Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
                    }
                    else
                    {
                        /* TX still running, wait for TX completion */
                    }
                }
                break;
            }
        }
    }
}
#endif /* {((STD_ON == SPI_DMA_SUPPORT) && (LEVEL0 != SPI_LEVEL_DELIVERED ))} */

#if (LEVEL0 != SPI_LEVEL_DELIVERED )
/*!
* @brief     Service for SPI IRQ configuration
* 
* @param[in] HWUnitId      HWUnit ID
* @param[in] AsyncMode     the async operation mode:SPI_INTERRUPT_MODE , SPI_POLLING_MODE
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_IrqCfg(VAR(Spi_HWUnitType, AUTOMATIC) HWUnitId,VAR(Spi_AsyncModeType, AUTOMATIC) AsyncMode)
{
    P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr = &g_SpiHwUnitState[HWUnitId];
    P2CONST(Spi_HWUnitConfigType, AUTOMATIC, SPI_APPL_CONST) spiHwUnitCfgPtr = HwStatePtr->spiHwUnitCfgPtr;

    /* set the HWUnit async transmission mode */
    HwStatePtr->spiAsyncMode = AsyncMode;
    switch(spiHwUnitCfgPtr->syncMode)
    {
        /* Set TDF, RDF interrupts for Async HWUnits */
        case SPI_PHYUNIT_ASYNC_U32: 
        {
            if (SPI_INTERRUPT_MODE == AsyncMode)
            {
            #if (STD_ON == SPI_DMA_SUPPORT)
                if ((uint16)TRUE == spiHwUnitCfgPtr->useDma)
                {
                    /* Configures DMA interrupts for the Rx channel */
                    Spi_Hw_DmaIrqCfg(HwStatePtr, AsyncMode);
                    /* Clear Receive Data Interrupt */
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXBNEIEN);
                }
                /* Un-Used DMA */
                else 
                {
            #endif
                #if (STD_OFF == SPI_SLAVE_SUPPORT)
                    /* Enable Receive Data Interrupt */
                    REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXBNEIEN);
                #else
                    /* Clear Receive Data Interrupt */
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXBNEIEN);
                #endif
            #if (STD_ON == SPI_DMA_SUPPORT)
                }
            #endif
            }
            /* SPI_INTERRUPT_MODE != AsyncMode */
            else 
            {
            #if (STD_ON == SPI_DMA_SUPPORT)
                if ((uint16)TRUE == spiHwUnitCfgPtr->useDma)
                {
                    /* Configures DMA interrupts for the Rx channel */
                    Spi_Hw_DmaIrqCfg(HwStatePtr, AsyncMode);
                }
                /* Un-Used DMA */
                else 
                {
                    /* No Operation */
                }
            #endif 
                /* Clear Receive Data Interrupt */
                REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXBNEIEN);
            }
            /* Clear transmit Data Interrupt */
            REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_TXBEIEN);
            break;
        }
        case SPI_PHYUNIT_SYNC_U32:
        default: 
            /* No Operation */
            break; 
    }
}

/*!
* @brief    Polling SPI Interrupt Request include used DMA or not 
* 
* @param[in] HWUnitId HWUnit ID
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_PollingIrq(VAR(Spi_HWUnitType, AUTOMATIC) HWUnitId)
{
    P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr;
    VAR(uint32, AUTOMATIC) isrStatus = 0u;
#if (STD_ON == SPI_DMA_SUPPORT)
    P2CONST(Spi_HWUnitConfigType, AUTOMATIC, SPI_APPL_CONST) spiHwUnitCfgPtr;
    VAR(boolean, AUTOMATIC) rxDmaDone = (boolean)FALSE;
    VAR(boolean, AUTOMATIC) txDmaDone = (boolean)FALSE;
    VAR(boolean, AUTOMATIC) dmaHandledThisRound = (boolean)FALSE;
    VAR(uint32, AUTOMATIC) dmaSpiStatus = 0u;
    VAR(uint32, AUTOMATIC) rxDmaRemain = 0u;
#endif

    HwStatePtr = SPI_HWUNIT_TO_SPI(HWUnitId);

    /* Polling Async Mode HWUnit IRQ  */
    if ((SPI_POLLING_MODE != HwStatePtr->spiAsyncMode) \
        || (SPI_PHYUNIT_ASYNC_U32 != HwStatePtr->spiHwUnitCfgPtr->syncMode))
    {
        /* HWUnit configuration or Async Mode invalid */
        /* No Operation */
    }
    else 
    {
        /* Enable poll request */
        HwStatePtr->spiIsPollReqEn = TRUE;
    #if (STD_OFF != SPI_DMA_SUPPORT)
        /* Get SPI HWUnit configuration */
        spiHwUnitCfgPtr = HwStatePtr->spiHwUnitCfgPtr;
        /* Used DMA */
        if ((uint16)TRUE == spiHwUnitCfgPtr->useDma) 
        {
            dmaSpiStatus = REG_READ32(HwStatePtr->spiStsAddr);
            /* Mark DMA transfer started once any RX-side activity is observed. */
            if ((dmaSpiStatus & (SPI_STS_BSYFLG | SPI_STS_RXBNEFLG | SPI_STS_FRLSEL)) != 0u)
            {
                HwStatePtr->spiIsEndJob = (boolean)TRUE;
            }
            /* check if the RX DMA transfer is completed */
            rxDmaDone = Pdl_TopDmaIsTransComp(spiHwUnitCfgPtr->rxDmaChannel);
            rxDmaRemain = Pdl_TopDmaChDataNumRead(spiHwUnitCfgPtr->rxDmaChannel);
            if (((boolean)FALSE == rxDmaDone)
                && (0u == rxDmaRemain))
            {
                rxDmaDone = (boolean)TRUE;
            }
            if (((boolean)FALSE == rxDmaDone)
                && (1u == rxDmaRemain)
                && ((dmaSpiStatus & (SPI_STS_RXBNEFLG | SPI_STS_FRLSEL)) != 0u))
            {
                /*
                 * For the last 1-byte DMA transfer, hardware may keep pending data in RX FIFO
                 * without updating transfer-complete status in polling mode.
                 * Re-arm RX DMA request/channel to finish this final move by DMA.
                 */
                if (0u == HwStatePtr->spiFirstChannelInJob)
                {
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXDEN);
                    Pdl_TopDmaChDis(spiHwUnitCfgPtr->rxDmaChannel);
                    Pdl_TopDmaChStsFlagClr(dmaTfFlags[spiHwUnitCfgPtr->rxDmaChannel - 1]);
                    Pdl_TopDmaChDataNumSet(spiHwUnitCfgPtr->rxDmaChannel, rxDmaRemain);
                    REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXDEN);
                    Pdl_TopDmaChEn(spiHwUnitCfgPtr->rxDmaChannel);
                    HwStatePtr->spiFirstChannelInJob = 1u;
                }
            }
            if ((boolean)FALSE == rxDmaDone) 
            {
                /* RX DMA transfer not complete , No Operation */  
            }
            else 
            {
                /* Enable RX poll request */
                HwStatePtr->spiIsRxPollReq = TRUE;
                HwStatePtr->spiIsEndJob = (boolean)TRUE;
                /* Set the DMA Channel Done */
                Pdl_TopDmaChStsFlagClr(dmaTfFlags[spiHwUnitCfgPtr->rxDmaChannel - 1]);
                Spi_Hw_IsrRxDma(HwStatePtr);
                dmaHandledThisRound = (boolean)TRUE;
            }
            /* check if the TX DMA transfer is completed */
            txDmaDone = Pdl_TopDmaIsTransComp(spiHwUnitCfgPtr->txDmaChannel);
            if (((boolean)FALSE == txDmaDone)
                && (0u == Pdl_TopDmaChDataNumRead(spiHwUnitCfgPtr->txDmaChannel)))
            {
                txDmaDone = (boolean)TRUE;
            }
            if ((boolean)FALSE == txDmaDone) /* TX DMA transfer not complete */
            {
                /* No Operation */
            }
            else 
            {
                /* Enable TX poll request */
                HwStatePtr->spiIsTxPollReq = TRUE;
                HwStatePtr->spiIsEndJob = (boolean)TRUE;
                /* Set the DMA Channel Done */
                Pdl_TopDmaChStsFlagClr(dmaTfFlags[spiHwUnitCfgPtr->txDmaChannel - 1]);
                Spi_Hw_IsrTxDma(HwStatePtr);
                dmaHandledThisRound = (boolean)TRUE;
            }
            if ((boolean)FALSE == dmaHandledThisRound)
            {
                dmaSpiStatus = REG_READ32(HwStatePtr->spiStsAddr);
                if (((boolean)TRUE == HwStatePtr->spiIsEndJob)
                    && ((uint32)0u == (dmaSpiStatus & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                    && (0u == HwStatePtr->spiRemainFrames)
                    && (0u == HwStatePtr->spiReceivedData)
                    && (0u == HwStatePtr->spiRemainTxChannels)
                    && (0u == HwStatePtr->spiRemainRxChannels)
                    && (SPI_BUSY == *(HwStatePtr->spiStatusPtr)))
                {
                    /* DMA transfer finished in HW, force SW state machine completion. */
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_RXDEN | SPI_CTRL2_TXDEN));
                    Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
                }
            }
        }
        else 
        {
    #endif 
            isrStatus = REG_READ32(HwStatePtr->spiStsAddr);
            HwStatePtr->spiIsTxPollReq = isrStatus & SPI_STS_TXBEFLG;
            HwStatePtr->spiIsRxPollReq = isrStatus & SPI_STS_RXBNEFLG;
            if ((0u == HwStatePtr->spiIsRxPollReq)
                && ((isrStatus & SPI_STS_FRLSEL) != 0u))
            {
                /*
                 * If FIFO still has unread data but RX threshold flag is not set,
                 * force one RX poll request to drain the remaining bytes.
                 */
                HwStatePtr->spiIsRxPollReq = TRUE;
            }
            switch(HwStatePtr->spiIsPollReqEn)
            {
                case TRUE:
                {
                    if (((0u != HwStatePtr->spiIsTxPollReq) || (0u != HwStatePtr->spiIsRxPollReq))
                        || ((SPI_MASTER == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                            && ((boolean)TRUE == HwStatePtr->spiIsEndJob)
                            && ((uint32)0u == (isrStatus & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                            && (0u == HwStatePtr->spiRemainFrames)
                            && (0u == HwStatePtr->spiRemainTxChannels))
                        || ((SPI_SLAVE == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                            && ((uint32)0u == (isrStatus & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                            && (0u == HwStatePtr->spiRemainFrames)
                            && (0u == HwStatePtr->spiRemainTxChannels)))
                    {
                        /* Emulate the SPI units IRQ in PIO_FIFO mode */
                        Spi_Hw_IrqRxFifo(HwStatePtr);
                    }
                    else
                    {
                        /* No poll request , No Operation */
                    }
                    /* Disable poll request */
                    HwStatePtr->spiIsPollReqEn = FALSE;
                    break;
                }
                default:
                    /* No Operation */
                    break;
            }
    #if (STD_ON == SPI_DMA_SUPPORT)
        }
    #endif 
    }
}

/*!
* @brief    Initialize TX channel informations after starting async transfer
* 
* @param[in] HwStatePtr     Pointer to HWUnit state
* @param[in] Channel        Channel ID 
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_ChanTXTransFifoInit \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel ) 
{
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) channelAttrCfgPtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) channelCfgPtr;
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr;
    VAR(uint32, AUTOMATIC) frameCmd;
    VAR(uint32, AUTOMATIC) fifoCfg;
    /* Get the channel configuration */
    channelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel];
    /* Get the channel attributes configuration */
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[Channel];
    /* Get the channel state */
    channelStatePtr = channelCfgPtr->channelStatePtr;
    HwStatePtr->spiRemainFrames = channelStatePtr->dataLength;
    /* Get current channel frame command */
    frameCmd = channelAttrCfgPtr->attrSC1R;
    /* Get current channel fifo configuration */
    fifoCfg = channelAttrCfgPtr->attrSC2R;
    HwStatePtr->spiCurrentCmd = frameCmd;
    /* check the TX buffers type */
    if (0u == (channelStatePtr->transmitFlags & ((uint8)SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG))) 
    {
        /* Use input transmit value for TX */
        HwStatePtr->spiCurrentTxBufPtr = channelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr;
    }
    else 
    {
        /* Use default transmit value for TX */
        HwStatePtr->spiCurrentTxBufPtr = NULL_PTR;
        HwStatePtr->spiDefaultTransData = channelCfgPtr->defaultTransmitValueSet;
    }
    /* LSB First Transfer Select(LSBSEL) */
    REG_RMW32(SPI_CTRL1_ADDRESS_U32, SPI_CTRL1_LSBSEL,frameCmd & SPI_CTRL1_LSBSEL_LSB);
    /* config DSCFG & FRTCFG in SPI_CTRL2 */
    REG_RMW32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG, fifoCfg & (SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG));
    
#if (STD_ON == SPI_SLAVE_SUPPORT)
    /* current HWUnit mode is master */
    if(SPI_MASTER == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode) 
    {
        /* No Operation */
    }
    else 
    {
        /* Enable transmit interrupt for interrupt mode */
        switch(HwStatePtr->spiAsyncMode)
        {
            case SPI_INTERRUPT_MODE:
            {
                /* Enable Receive Data Interrupt */
                REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_RXBNEIEN);
                break;
            }
            default:
                /* SPI_POLLING_MODE , No Operation */
                break; 
        }
    }
#endif
}

/*!
* @brief    Initialize RX channel informations after starting async transfer
* 
* @param[in]     HwStatePtr   Pointer to HWUnit state
* @param[in]     Channel      channel ID 
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_ChanRXTransFifoInit \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel )
{
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) channelCfgPtr;
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr;
    /* Get the RX channel configuration */
    channelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel];
    /* Get the RX channel state */
    channelStatePtr = channelCfgPtr->channelStatePtr;
    HwStatePtr->spiReceivedData = channelStatePtr->dataLength;
    /* check the RX buffers type,the read datas will ignore if RX buffer valid */
    HwStatePtr->spiCurrentRxBufPtr = channelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr;
}

/*!
* @brief    Service for filling the transfer FIFO
* 
* @param[in] HwStatePtr     Pointer to HWUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_FillTransFifo \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr )
{
    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt;
    VAR(uint8, AUTOMATIC) jobEndFlg = (uint8)FALSE; 
    
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) channelAttrCfgPtr = \
        &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[*(HwStatePtr->spiCurTxChanIndexListPtr)];

    /* Calculate the frames number to be sent according to dataAccessWidth */
    framesCnt = HwStatePtr->spiRemainFrames;
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            framesCnt /= 2u;
            break;
        }
        default:
            /* default data accesss width 8bits , No Operation */
            break; 
    }

    if ((SPI_MASTER == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode) \
        && ((0u == (uint32)(HwStatePtr->spiRemainTxChannels)) && (1U == framesCnt)))
    {
        jobEndFlg = (uint8)TRUE;
    }
    else 
    {
        /* Have remain Tx Channels or SPI_SLAVE mdoe */
        jobEndFlg = (uint8)FALSE;
    }

    if(framesCnt > 0u)
    {
        framesCnt = 1u;
    }
    else 
    {
        /* No frame to send */
    }

    HwStatePtr->spiRemainFrames -= framesCnt;
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            HwStatePtr->spiRemainFrames -= framesCnt;
            break;
        }
        default:
            /* default data accesss width 8bits , No Operation */
            break; 
    }
    
    HwStatePtr->spiSentFrames = framesCnt;
    Spi_Hw_SetTxFifo(HwStatePtr, jobEndFlg);
}

/*!
* @brief    Service for filling the Tx FIFO
* 
* @param[in] HwStatePtr    Pointer to HWUnit state
* @param[in] jobEndFlg     job end flag
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_SetTxFifo \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(uint8, AUTOMATIC) JobEndFlg ) 
{
    P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_CONST) spiTxBufferPtr = HwStatePtr->spiCurrentTxBufPtr;
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) channelAttrCfgPtr = \
    &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[*(HwStatePtr->spiCurTxChanIndexListPtr)];
    P2CONST(uint16, AUTOMATIC, SPI_APPL_CONST) tx16BitBufferPtr;
    
    /* Get Transmit Data Register (TXDATA) address */
    VAR(uint32, AUTOMATIC) spiDataAddr = HwStatePtr->spiDataAddr;
    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt = HwStatePtr->spiSentFrames;
    
    /* check Tx buffer availability */
    if (NULL_PTR == spiTxBufferPtr) /* write the default value */
    {
        while (framesCnt > 0u)
        {
            framesCnt--;
            /* write default transmit data to Transmit Data Register (TXDATA) */
            REG_WRITE32(spiDataAddr, HwStatePtr->spiDefaultTransData);
            switch(HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
            {
                case SPI_MASTER:
                {
                    if ((0u == framesCnt) && (1u == JobEndFlg))
                    {
                        /* set the job end flag of current HWUnit  */
                        HwStatePtr->spiIsEndJob = (boolean)TRUE;
                    }
                    else 
                    {
                        /* continous */
                    }
                    break;
                }
                default:
                    /* No Operation */
                    break;  
            }
        }
    }
    /* spiTxBufferPtr = NULL_PTR */
    else 
    {
        /* update pointer of TX buffer */
        HwStatePtr->spiCurrentTxBufPtr = &HwStatePtr->spiCurrentTxBufPtr[framesCnt];
        /* Calculate the TX buffer pointer */
        switch(channelAttrCfgPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                HwStatePtr->spiCurrentTxBufPtr = &HwStatePtr->spiCurrentTxBufPtr[framesCnt];
                break;
            }
            default:
                /* default data accesss width 8bits , No Operation */
                break; 
        }
        /* write the buffer to Transmit Data Register (TXDATA) according to dataAccessWidth */
        while (framesCnt > 0u)
        {
            framesCnt--;
            switch(channelAttrCfgPtr->dataAccessWidth)
            {
                case SPI_ACCESS_DATATYPE_16:
                {
                    /*** @warning Spi_Hw_c_MISRA_REF2 Casting to different object pointer type.
                                 Pointer cast to stricter alignment.*/
                    /*** @warning Spi_Hw_c_MISRA_REF3 Dangerous pointer cast results in loss of const qualification.*/
                    tx16BitBufferPtr = (uint16 *) spiTxBufferPtr;
                    REG_WRITE32(spiDataAddr, (*tx16BitBufferPtr));
                    spiTxBufferPtr++;
                    break;
                }
                /* default data accesss width 8bits */
                default: 
                {
                    REG_WRITE8(spiDataAddr, (*spiTxBufferPtr));
                    break;
                }
            }
            spiTxBufferPtr++;

            if ((0u == framesCnt) && (1u == JobEndFlg))
            {
                /* set the job end flag of current HWUnit  */
                HwStatePtr->spiIsEndJob = (boolean)TRUE;
            }
            else
            {
                /*continous */
            }
        }
    }
}

/*!
* @brief    Get the Receive Data Register (RXDATA) information from SPI FIFO
* 
* @param[in] HwStatePtr      Pointer to HWUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_GetFifoData \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr ) 
{
    if ((NULL_PTR == g_spiCfgPtr) || (NULL_PTR == HwStatePtr->spiCurRxChanIndexListPtr))
    {
        (void)REG_READ8(HwStatePtr->spiDataAddr);
        return;
    }

    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) \
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[*(HwStatePtr->spiCurRxChanIndexListPtr)];
    
    P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) spiRxBufferPtr;
    P2VAR(uint16, AUTOMATIC, SPI_APPL_DATA) rx16BitBufferPtr;
    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt = 0U;
    VAR(uint32, AUTOMATIC) spiDataAddr = HwStatePtr->spiDataAddr;
    VAR(Spi_NumberOfDataType, AUTOMATIC) cmpFramesCnt = 0U;
#if (STD_ON == SPI_SLAVE_SUPPORT)
    VAR(Spi_NumberOfDataType, AUTOMATIC) abandonFramesCnt = 0U;
#endif
    /* Slave mode */
    if( SPI_SLAVE == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode ) 
    {
    #if (STD_ON == SPI_SLAVE_SUPPORT)
        {
            VAR(Spi_NumberOfDataType, AUTOMATIC) rxFifoLevel;
            VAR(Spi_NumberOfDataType, AUTOMATIC) remainFrames;

            remainFrames = HwStatePtr->spiReceivedData;
            rxFifoLevel = (Spi_NumberOfDataType)SPI_STS_FRLSEL_VAL_U32(REG_READ32(SPI_STS_ADDRESS_U32));
            switch(channelAttrCfgPtr->dataAccessWidth)
            {
                case SPI_ACCESS_DATATYPE_16:
                {
                    /* spiReceivedData is byte count; remainFrames is 16-bit frame count */
                    remainFrames /= 2u;
                    /* FRLSEL is RX FIFO level in byte slots, convert to 16-bit frame count */
                    if (rxFifoLevel > 0u)
                    {
                        rxFifoLevel /= 2u;
                    }
                    framesCnt = remainFrames;
                    break;
                }
                default:
                {
                    framesCnt = remainFrames;
                    break;
                }
            }
            /* Judge the remaining buffer space to store the received data */
            if (rxFifoLevel <= framesCnt)
            {
                framesCnt = rxFifoLevel;
                abandonFramesCnt = 0u;
            }
            /* Too much data, buffer overflow detected */
            else
            {
                abandonFramesCnt = rxFifoLevel - framesCnt;
            }
        }
    #endif
    }
    /* Master mode */
    else 
    {
        framesCnt = HwStatePtr->spiSentFrames;
    }

    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            HwStatePtr->spiReceivedData -= (framesCnt * 2u);
            break;
        }
        default:
        {
            HwStatePtr->spiReceivedData -= framesCnt;
            break;
        }
    }
    /* Get current RX buffer */
    spiRxBufferPtr = HwStatePtr->spiCurrentRxBufPtr;
    cmpFramesCnt = framesCnt;
    if (NULL_PTR == spiRxBufferPtr) 
    {
        /* Abandon the Receive Data Register (RXDATA) information */
        s_SpiReadAbandon = REG_READ32(spiDataAddr);
        framesCnt--;
        while ((framesCnt > 0u) && (framesCnt < cmpFramesCnt))
        {
            s_SpiReadAbandon = REG_READ32(spiDataAddr);
            framesCnt--;
        }
    }
    /* spiRxBufferPtr != NULL_PTR */
    else 
    {
        /* read the Receive Data Register (RXDATA) information */
        for( ; framesCnt > (Spi_NumberOfDataType)0; framesCnt-- )
        {
            switch(channelAttrCfgPtr->dataAccessWidth)
            {
                case SPI_ACCESS_DATATYPE_16:
                {
                    /*** @warning Spi_Hw_c_MISRA_REF2 Casting to different object pointer type.
                                 Pointer cast to stricter alignment.*/
                    rx16BitBufferPtr = (uint16 *) spiRxBufferPtr;
                    spiRxBufferPtr = &spiRxBufferPtr[2];
                    *rx16BitBufferPtr = (uint16)REG_READ32(spiDataAddr);
                    break;
                }
                default:
                {
                    *spiRxBufferPtr = (Spi_DataBufferType)REG_READ8(spiDataAddr);
                    spiRxBufferPtr++;
                    break;
                }
            }
        }
        /* update the pointer of HWUnit current RX_buffer */
        HwStatePtr->spiCurrentRxBufPtr = spiRxBufferPtr;
    }

#if (STD_ON == SPI_SLAVE_SUPPORT)
    switch(HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
    {
        case SPI_SLAVE:
        {
            /* Check the abandon frames according to abandonFramesCnt */
            if(0u == abandonFramesCnt) 
            {
                /* No abandon frames */
            }
            /* Have abandon frames */
            else 
            {
                cmpFramesCnt = abandonFramesCnt;
                /* Abandon all the redundant frames */
                s_SpiReadAbandon = REG_READ32(spiDataAddr);
                abandonFramesCnt--;
                while((abandonFramesCnt > 0u) && (abandonFramesCnt < cmpFramesCnt))
                {
                    s_SpiReadAbandon = REG_READ32(spiDataAddr);
                    abandonFramesCnt--;
                }
            }
            /* with Received frames */
            if((Spi_NumberOfDataType)0u != HwStatePtr->spiReceivedData) 
            {
                /* No Operation */
            }
            else  
            {
                /* No Received frames , end job */
                HwStatePtr->spiIsEndJob = (boolean)TRUE;
            }
            break;
        }
        default: 
            /* Current HWUnit mode is SPI_MASTER , No Operation */
            break; 
    }
#endif
}

/*!
* @brief    config the Job attributes and transfer all the datas
* 
* @param[in] JobCfgPtr     Pointer to job configuration
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_JobTrans( P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) JobCfgPtr )
{
    P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) hwUnitStatePtr = &g_SpiHwUnitState[JobCfgPtr->jobHWUnit];
    P2CONST(Spi_ChannelType, AUTOMATIC, SPI_APPL_CONST) channelListPtr = JobCfgPtr->pcChannelIndexListPtr;

    if(NULL_PTR == JobCfgPtr->pfStartNotificationPtr)
    {
        /* No Notification , No Operation */
    }
    else 
    {
        /* assert job start notification */
        JobCfgPtr->pfStartNotificationPtr();
    }
    
    hwUnitStatePtr->spiExtDeviceCTRL1 = (*JobCfgPtr->extDevAttrsPtr->spiExtDeviceAttrCfgPtr)->cfgCTRL1;
    hwUnitStatePtr->spiExtDeviceCTRL2 = (*JobCfgPtr->extDevAttrsPtr->spiExtDeviceAttrCfgPtr)->cfgCTRL2;
    
    /* config starting channel index according to configuration */
    hwUnitStatePtr->spiCurTxChanIndexListPtr = channelListPtr;
    hwUnitStatePtr->spiRemainTxChannels = JobCfgPtr->numOfChannels - (Spi_ChannelType) 1u;
    
    hwUnitStatePtr->spiCurRxChanIndexListPtr = channelListPtr;
    hwUnitStatePtr->spiRemainRxChannels = JobCfgPtr->numOfChannels - (Spi_ChannelType) 1u;
    /* clear one-byte RX DMA re-arm flag for each new job */
    hwUnitStatePtr->spiFirstChannelInJob = 0u;

    /* get the current job configuration */
    hwUnitStatePtr->spiCurrentJobPtr = JobCfgPtr;
#if (STD_ON == SPI_DMA_SUPPORT)
    if ((uint16)FALSE != hwUnitStatePtr->spiHwUnitCfgPtr->useDma)
    {
        /*
         * For DMA short transfer (e.g. 1 byte), BSY pulse can be too short to be sampled
         * in polling path. Allow completion check from first polling round in master mode.
         */
        hwUnitStatePtr->spiIsEndJob = (SPI_MASTER == hwUnitStatePtr->spiHwUnitCfgPtr->hwUnitMode) ? (boolean)TRUE : (boolean)FALSE;
        /* initialize the DMA first channel transfer parameters */
        Spi_Hw_DmaChanTXInit(hwUnitStatePtr, *channelListPtr);
        Spi_Hw_DmaChanRXInit(hwUnitStatePtr, *channelListPtr);

        /*
         * Ensure DMA request is generated for tail/short frames (e.g. 1 byte).
         * Keep LDRX/LDTX enabled when DMA path is used.
         */
        REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_LDRX | SPI_CTRL2_LDTX));

        /* Enable Receive/Transmit Data DMA */
        REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32,(uint32)(SPI_CTRL2_RXDEN | SPI_CTRL2_TXDEN));
    }
    else
    {
#endif 
        hwUnitStatePtr->spiIsEndJob = (boolean)FALSE;
        /* initialize the DMA first channel transfer parameters */
        Spi_Hw_ChanTXTransFifoInit(hwUnitStatePtr, *channelListPtr);
        Spi_Hw_ChanRXTransFifoInit(hwUnitStatePtr, *channelListPtr);
        Spi_Hw_FillTransFifo(hwUnitStatePtr);
        
        /* Enable transmit interrupt for interrupt mode */
        switch(hwUnitStatePtr->spiAsyncMode)
        {
            case SPI_INTERRUPT_MODE:
            {
                REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_TXBEIEN);
                break;
            }
            default:
                /* SPI_POLLING_MODE , No Operation */
                break; 
        }

#if (STD_ON == SPI_DMA_SUPPORT)
    }
#endif 
}

/*!
* @brief    Interrupt service: Emulate the SPI units IRQ in PIO_FIFO mode 
* 
* @param[in] HwStatePtr    Pointer to HWUnit state
* @param[in] HwUnitOffset      Offset above base address
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_IrqRxFifo(P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr)
{
    VAR(Spi_AsyncModeType, AUTOMATIC) asyncModeT = HwStatePtr->spiAsyncMode;
    VAR(uint32, AUTOMATIC) isrStatusTX = 0u;
    VAR(uint32, AUTOMATIC) isrStatusRX = 0u;
    VAR(uint32, AUTOMATIC) spiStsValue = 0u;
    /* not initialized, clear status flags and Reset Control Register (CTRL)*/
    if (NULL_PTR == g_spiCfgPtr) 
    {
        /* Reset the SPI Control Register (CTRL) */
        REG_WRITE32(SPI_CTRL1_ADDRESS_U32, SPI_CTRL1_RESET);
    }
    else
    {
        if ((boolean)FALSE == Spi_Hw_IsAsyncPhyUnit(HwStatePtr))
        {
            /* Sync transfer owns SPI HW; do not run async FIFO state machine */
        }
        else
        {
        if (SPI_POLLING_MODE == asyncModeT)
        {
            switch(HwStatePtr->spiIsPollReqEn)
            {
                case TRUE:
                {
                    isrStatusTX = HwStatePtr->spiIsTxPollReq;
                    isrStatusRX = HwStatePtr->spiIsRxPollReq;
                    HwStatePtr->spiIsPollReqEn = FALSE;
                    break;
                }
                default: 
                    /* no poll request , No Operation */
                    break; 
            }
        }
        /* asyncModeT = SPI_INTERRUPT_MODE */ 
        else 
        {
            /* read Status Register (SR) once to avoid split-read timing race */
            spiStsValue = REG_READ32(HwStatePtr->spiStsAddr);
            isrStatusTX = spiStsValue & SPI_STS_TXBEFLG;
            isrStatusRX = spiStsValue & SPI_STS_RXBNEFLG;
            if ((0u == isrStatusRX)
                && ((spiStsValue & SPI_STS_FRLSEL) != 0u))
            {
                /*
                 * RX threshold flag may stay low while FIFO still has data.
                 * Force RX handling to drain tail data and complete status machine.
                 */
                isrStatusRX = SPI_STS_RXBNEFLG;
            }
        }
        /* check triggered status */
        if ((0u == isrStatusTX) && (0u == isrStatusRX))  
        {
            /* No triggered , clear error flags only */
            if ((spiStsValue & SPI_STS_MEFLG) != 0u)
            {
                REG_BIT_CLEAR32(SPI_STS_ADDRESS_U32, SPI_STS_MEFLG);
            }
            if ((spiStsValue & SPI_STS_OVRFLG) != 0u)
            {
                REG_BIT_CLEAR32(SPI_STS_ADDRESS_U32, SPI_STS_OVRFLG);
            }

            if ((SPI_MASTER == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                && ((boolean)TRUE == HwStatePtr->spiIsEndJob)
                && ((uint32)0u == (REG_READ32(HwStatePtr->spiStsAddr) & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                && (0u == HwStatePtr->spiRemainFrames)
                && (0u == HwStatePtr->spiRemainTxChannels))
            {
                /*
                 * HW already idle but software accounting can still be pending at high speed.
                 * Complete job to release Spi_HwQueueArray[].Status to SPI_IDLE.
                 */
                HwStatePtr->spiReceivedData = 0u;
                HwStatePtr->spiRemainRxChannels = 0u;
                REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_TXBEIEN | SPI_CTRL2_RXBNEIEN));
                Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
            }
            else if ((SPI_SLAVE == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                && ((uint32)0u == (REG_READ32(HwStatePtr->spiStsAddr) & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                && (0u == HwStatePtr->spiRemainFrames)
                && (0u == HwStatePtr->spiRemainTxChannels))
            {
                /*
                 * Slave TX done and HW idle: drain tail RX before closing job.
                 */
                if ((0u != HwStatePtr->spiReceivedData)
                    && ((REG_READ32(HwStatePtr->spiStsAddr) & SPI_STS_FRLSEL) != 0u))
                {
                    Spi_Hw_GetFifoData(HwStatePtr);
                }
                if (0u == HwStatePtr->spiReceivedData)
                {
                    HwStatePtr->spiIsEndJob = (boolean)TRUE;
                    HwStatePtr->spiRemainRxChannels = 0u;
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_TXBEIEN | SPI_CTRL2_RXBNEIEN));
                    Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
                }
            }
        }
        else
        {
            /* Copy data from FIFO and prepare next channel transmission */
            Spi_Hw_TransStatus(HwStatePtr, isrStatusTX, isrStatusRX);
            switch(HwStatePtr->spiIsEndJob)
            {
                case TRUE:
                {
                    if(((0u == HwStatePtr->spiReceivedData) && (0u == HwStatePtr->spiRemainRxChannels))
                        || ((SPI_MASTER == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                            && ((uint32)0u == (REG_READ32(HwStatePtr->spiStsAddr) & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                            && (0u == HwStatePtr->spiRemainFrames)
                            && (0u == HwStatePtr->spiRemainTxChannels))
                        || ((SPI_SLAVE == HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
                            && (0u == HwStatePtr->spiReceivedData)
                            && ((uint32)0u == (REG_READ32(HwStatePtr->spiStsAddr) & (SPI_STS_FTLSEL | SPI_STS_FRLSEL | SPI_STS_BSYFLG)))
                            && (0u == HwStatePtr->spiRemainFrames)
                            && (0u == HwStatePtr->spiRemainTxChannels)))
                    {
                        /* job transmit end */
                        REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_TXBEIEN | SPI_CTRL2_RXBNEIEN));
                        Spi_JobTransEnd(HwStatePtr->spiCurrentJobPtr);
                    }
                    else 
                    {
                        /* continous */
                    }
                    break;
                }
                default:
                    /* continous , No Operation */
                    break; 
            }
        }
        }
    }
}

/*!
* @brief    Interrupt service:Emulate the SPI units IRQ in PIO_FIFO mode according to TX/RX ISR status
* 
* @param[in]  HwStatePtr      Pointer to HWUnit state
* @param[in]  TxIsrStatus     TXDFLG(Transmit Data Flag) bit Status
* @param[in]  RxIsrStatus     RXDFLG(Receive Data Flag) bit flag Status
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_TransStatus( P2VAR(Spi_HwStateType, \
    AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(uint32, AUTOMATIC) TxIsrStatus, VAR(uint32, AUTOMATIC) RxIsrStatus )
{
    /* Handle RX ISR */
    if(0u == RxIsrStatus)
    {
        /* No RX ISR , No Operation */
    }
    else
    {
        Spi_Hw_GetFifoData(HwStatePtr);
        /* Update the transfer RX channel */
        if ((0u != HwStatePtr->spiRemainRxChannels) && (0u == HwStatePtr->spiReceivedData))
        {
            /* Update Channel and related indexes */
            HwStatePtr->spiRemainRxChannels--;
            HwStatePtr->spiCurRxChanIndexListPtr++;
            /* prepare MASTER/SLAVE next channel transmission */
            switch(HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
            {
                case SPI_SLAVE:
                {
                #if (STD_ON == SPI_SLAVE_SUPPORT)
                    /* Update Channel and related indexes */
                    HwStatePtr->spiRemainTxChannels--;
                    HwStatePtr->spiCurTxChanIndexListPtr++;
                    Spi_Hw_ChanTXTransFifoInit(HwStatePtr, *(HwStatePtr->spiCurTxChanIndexListPtr));
                    Spi_Hw_ChanRXTransFifoInit(HwStatePtr, *(HwStatePtr->spiCurRxChanIndexListPtr));
                #endif
                    break;
                }
                default://SPI_MASTER
                {
                    Spi_Hw_ChanRXTransFifoInit(HwStatePtr, *(HwStatePtr->spiCurRxChanIndexListPtr));
                    break;
                }
            }
        }
        else 
        {
            /* No remain channel */
        }
    #if (STD_ON == SPI_SLAVE_SUPPORT)
        switch(HwStatePtr->spiHwUnitCfgPtr->hwUnitMode)
        {
            case SPI_SLAVE:
            {
                if ((boolean)FALSE == HwStatePtr->spiIsEndJob)
                {
                    /* filling the transfer FIFO for next transmission */
                    Spi_Hw_FillTransFifo(HwStatePtr);
                }
                else 
                {
                    /* job end */
                }
                break;
            }
            default:
                /* No Operation */
                break;
        }
    #endif
    }

    /* Handle TX ISR */
    if(0u == TxIsrStatus)  
    {
        /* No TX ISR , No Operation */
    }
    else
    {
        switch(HwStatePtr->spiIsEndJob)
        {
            case TRUE:
            {
                switch(HwStatePtr->spiAsyncMode)
                {
                    case SPI_INTERRUPT_MODE:
                    {
                        /*
                         * Wait RX side drain done before closing TX IRQ,
                         * otherwise async state machine may stay SPI_BUSY.
                         */
                        if ((0u == HwStatePtr->spiReceivedData) && (0u == HwStatePtr->spiRemainRxChannels))
                        {
                            REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_TXBEIEN);
                        }
                        break;
                    }
                    default:
                        /* No Operation */
                        break;
                }

                break;
            }
            case FALSE:
            {
                /* Update the transfer TX channel */
                if ((0u == HwStatePtr->spiRemainFrames) && (0u != HwStatePtr->spiRemainTxChannels))
                {
                    /* Update Channel and related indexes */
                    HwStatePtr->spiRemainTxChannels--;
                    HwStatePtr->spiCurTxChanIndexListPtr++;
                    /* prepare next channel transmission */
                    Spi_Hw_ChanTXTransFifoInit(HwStatePtr, *(HwStatePtr->spiCurTxChanIndexListPtr));
                }
                else 
                {
                    /* No remain channels */
                }
                /* filling the transfer FIFO for next transmission */
                Spi_Hw_FillTransFifo(HwStatePtr);
                break;
            }
            default:
                /* No Operation */
                break;
        }
    }
}
#endif /* { (LEVEL0 != SPI_LEVEL_DELIVERED ) } */

#if ((SPI_LEVEL_DELIVERED != LEVEL1) && (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE))
/*!
* @brief     Service for caching Prepare Information of sequence / job configuration.
* 
* @param[in] None
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_PreCacheInfo(void)
{
    /* Pointer to device attributes configuration */
    P2CONST(Spi_DeviceAttrCfgType, AUTOMATIC, SPI_APPL_CONST) devAttrCfgPtr;
    /* Pointer to channel attributes configuration */
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) channelCfgPtr;
    /* Pointer to job configuration */
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr;
    /* Pointer to sequence configuration */
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
    
    /* Pointer to channel attributes */
    P2VAR(Spi_CachedChannelAttrType, AUTOMATIC, SPI_APPL_DATA) channelAttrPtr;
    /* Pointer to sequence attributes */
    P2VAR(Spi_CachedSeqAttrType, AUTOMATIC, SPI_APPL_DATA) seqAttrPtr;
    
    /* Senquence attributes current index value in index list */
    VAR(Spi_SequenceType, AUTOMATIC) seqAttrCurIndex = 0u;
    /* Channel attributes current index value in index list */
    VAR(Spi_ChannelType, AUTOMATIC) chanAttrCurIndex = 0u;
    VAR(Spi_ChannelType, AUTOMATIC) channelNum;
    VAR(Spi_ChannelType, AUTOMATIC) channelId;
    VAR(Spi_JobType, AUTOMATIC) jobId;
    VAR(uint32, AUTOMATIC) seqId = 0;
    VAR(uint8, SPI_VAR) optimizedHWType;
    
    /* Initialize all sequences optimized as NULL_PTR*/
    while(seqId <= (uint32)(g_spiCfgPtr->maxSequence))
    {
        spiSingleJobSeqOptPtr[seqId] = NULL_PTR;
        seqId++;
    }
    seqId = 0u; 
    /* for all sequences */
    while(seqId <= (uint32)(g_spiCfgPtr->maxSequence))
    {
        seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[seqId];
        /* check the sequence has only one job */
        if (1u != seqCfgPtr->numOfJobs) 
        {
            /* More than one job,sequences can not be optimized*/
        }
        else
        {
            jobId = seqCfgPtr->pcJobIndexListPtr[0];
            jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];

            /* Make sure have enough empty place in the cached data channel pool */
            if (jobCfgPtr->numOfChannels > (SPI_ONEJOBSEQCHANNEL_BUFFER_SIZE - chanAttrCurIndex)) 
            {
                /* No enough caches to be used */
            }
            else
            {
                seqAttrPtr = &s_spiSeqAttr[seqAttrCurIndex];
                spiSingleJobSeqOptPtr[seqId] = seqAttrPtr;
                /* Cache base address of the sequence */
                seqAttrPtr->spiBaseAddress = g_SpiHwUnitState[jobCfgPtr->jobHWUnit].spiBaseAddress;
                
                /* Cache All prepare information of the sequence */
                seqAttrPtr->spiJobStatePtr = &g_spiJobState[jobId];
                seqAttrPtr->optimizedHWType = optimizedHWType;
                seqAttrPtr->spiHwUnit = jobCfgPtr->jobHWUnit;
                seqAttrPtr->spiChannelsNum = jobCfgPtr->numOfChannels;
                seqAttrPtr->spiHWStatusPtr = g_SpiHwUnitState[jobCfgPtr->jobHWUnit].spiStatusPtr;
                
                /* Get the sequence device configuration */
                devAttrCfgPtr = (g_spiCfgPtr->pcAttrCfgPtr->spiDevAttrCfgPtr)[g_spiCfgPtr->pcJobCfgPtr[jobId].extDevType];
                
                seqAttrPtr->cfgCTRL1 = devAttrCfgPtr->cfgCTRL1;
                seqAttrPtr->cfgCTRL2 = devAttrCfgPtr->cfgCTRL2;
                seqAttrPtr->cfgCRCPOLY = devAttrCfgPtr->cfgCRCPOLY;

                /* link the first cached channel entry */
                seqAttrPtr->spiChannelsPtr = &s_spiChannelAttr[chanAttrCurIndex];

                /* prepare the cache information for channel*/
                channelNum = 0u;
                /* for all channels */
                while(channelNum < jobCfgPtr->numOfChannels)
                {
                    channelId = jobCfgPtr->pcChannelIndexListPtr[channelNum];
                    channelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[channelId];
                    channelAttrPtr = &seqAttrPtr->spiChannelsPtr[channelNum];
                    channelAttrPtr->spiDefaultTransmitValue = channelCfgPtr->defaultTransmitValueSet;
                    channelAttrPtr->spiStatePtr = channelCfgPtr->channelStatePtr;
                    channelAttrPtr->spiBufDescriptorPtr = channelCfgPtr->pcBufferDescriptPtr;

                    /* get the Data Accessed Width */
                    channelAttrPtr->spiDataAccessedWidth =
                        g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[channelId].dataAccessWidth;
                    channelNum++;
                } 

                /* update pool indexes of index list */
                seqAttrCurIndex++;
                chanAttrCurIndex += jobCfgPtr->numOfChannels;

                /* No caches to be used, loop end */
                if((seqAttrCurIndex >= SPI_ONEJOBSEQ_BUFFER_SIZE) || (chanAttrCurIndex >= SPI_ONEJOBSEQCHANNEL_BUFFER_SIZE))
                {
                    /* loop end */
                    break; 
                }
                else 
                {
                    /* loop continous */
                }
            }
        } 
        seqId++;
    } 
}
#endif 

#if (LEVEL1 != SPI_LEVEL_DELIVERED)
/*!
* @brief    Service for starting synchronous transmission
* 
* @param[in] SeqId       Sequence ID
* @param[out] None
* @param[in,out] None
*
* @retval transStatus:E_OK,E_NOT_OK
*
* @note   Non-AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTrans( VAR(Spi_SequenceType, AUTOMATIC) SeqId )
{
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr;
    P2CONST(Spi_HwStateType, AUTOMATIC, SPI_APPL_CONST) hwUnitStatePtr;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) jobIndexListPtr;
    
    P2VAR(Spi_JobStateType, AUTOMATIC, SPI_APPL_DATA) spiJobStatePtr;
    P2VAR(Spi_SyncProcessStateType, AUTOMATIC, SPI_APPL_DATA) syncTransStatePtr;
    
    VAR(Spi_JobType, AUTOMATIC) jobsCnt;
    VAR(Spi_JobType, AUTOMATIC) remaining;
    VAR(Spi_JobType, AUTOMATIC) jobId;
    VAR(Std_ReturnType, AUTOMATIC) transStatus = (Std_ReturnType)E_OK;
    VAR(uint32, AUTOMATIC) spiJobCmd = 0u;
    VAR(uint32, AUTOMATIC) devCTRL2 = 0u;
    VAR(Std_ReturnType, AUTOMATIC) syncJobStatus = (Std_ReturnType)E_NOT_OK;

    /* Get the configuration of sequence */
    seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[SeqId];
    /* Get the jobs number of sequence */
    jobsCnt = seqCfgPtr->numOfJobs;
    jobIndexListPtr = seqCfgPtr->pcJobIndexListPtr;
    for ( ; jobsCnt > 0u ; jobsCnt--)
    {
        jobId = *jobIndexListPtr;
        /* Set job Result to SPI_JOB_PENDING */
        spiJobStatePtr = &g_spiJobState[jobId];
        spiJobStatePtr->jobResult = SPI_JOB_PENDING;
        jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
        /* check job start notification */
        if (NULL_PTR == jobCfgPtr->pfStartNotificationPtr) /* no job start notification */
        {
            /* No Operation */
        }
        else
        {
            jobCfgPtr->pfStartNotificationPtr();
        }
        /* get HWunit state */
        hwUnitStatePtr = &g_SpiHwUnitState[jobCfgPtr->jobHWUnit];
        /* Set status to SPI_BUSY */
        *(hwUnitStatePtr->spiStatusPtr) = SPI_BUSY;
        
        /* Get device SPI_CTRL1 SPI_CTRL2 Register configuration */
        spiJobCmd = (*jobCfgPtr->extDevAttrsPtr->spiExtDeviceAttrCfgPtr)->cfgCTRL1;
        devCTRL2 = (*jobCfgPtr->extDevAttrsPtr->spiExtDeviceAttrCfgPtr)->cfgCTRL2;

        /* Set device SPI_CTRL1/CTRL2 Register */
        REG_WRITE32(hwUnitStatePtr->spiCtrl1Addr, (spiJobCmd & SPI_CTRL1_BITS_MASK));
        REG_WRITE32(hwUnitStatePtr->spiCtrl2Addr, devCTRL2);
        /* Update state of Synchronous transmission */
        syncTransStatePtr = &s_SpiSyncTransState[jobCfgPtr->jobHWUnit];
        syncTransStatePtr->spiBaseAddress = hwUnitStatePtr->spiBaseAddress;
        syncTransStatePtr->spiJobEndFlag=(uint8)FALSE;
        syncTransStatePtr->spiJobCmd = spiJobCmd;
        syncTransStatePtr->spiTxChannelsNum = jobCfgPtr->numOfChannels;
        syncTransStatePtr->spiRxChannelsNum = jobCfgPtr->numOfChannels;
        syncTransStatePtr->spiTxChannelIndexListPtr = jobCfgPtr->pcChannelIndexListPtr;
        syncTransStatePtr->spiRxChannelIndexListPtr = jobCfgPtr->pcChannelIndexListPtr;
        /* Start a job Synchronous transmission */
        syncJobStatus = Spi_Hw_SyncTransJob(syncTransStatePtr);
        *(hwUnitStatePtr->spiStatusPtr) = SPI_IDLE;
        if(syncJobStatus == E_NOT_OK)
        {
            /* Set the job result as SPI_JOB_FAILED */
            g_spiJobState[*jobIndexListPtr].jobResult = SPI_JOB_FAILED;
            jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[*jobIndexListPtr];
            /* Check job End Notification */
            if (NULL_PTR == jobCfgPtr->pfEndNotificationPtr)
            {
                /* no job End Notification , No Operation */
            }
            else
            {
                jobCfgPtr->pfEndNotificationPtr();
            }
            /* Update job index */
            jobIndexListPtr++;
            remaining = jobsCnt - 1u;
            while(remaining > (uint32)0)
            {
                /* Set the job result as SPI_JOB_FAILED */
                g_spiJobState[*jobIndexListPtr].jobResult = SPI_JOB_FAILED;
                jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[*jobIndexListPtr];
                /* Check job End Notification */
                if (NULL_PTR == jobCfgPtr->pfEndNotificationPtr)
                {
                    /* no job End Notification , No Operation */
                }
                else 
                {
                    /* no job End Notification */
                    jobCfgPtr->pfEndNotificationPtr();
                }
                /* Update job index */
                jobIndexListPtr++;
                remaining--;
            }
            transStatus = (Std_ReturnType)E_NOT_OK;
            break;
        }
        else
        {
            /* Set the job result as SPI_JOB_OK */
            spiJobStatePtr->jobResult = SPI_JOB_OK;
            /* Check job End Notification */
            if (NULL_PTR == jobCfgPtr->pfEndNotificationPtr)
            {
                /* no job End Notification , No Operation */
            }
            else 
            {
                jobCfgPtr->pfEndNotificationPtr();
            }
        }
        /* update job index */
        jobIndexListPtr++;
    } 
#if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)
    switch(transStatus)
    {
        case E_NOT_OK:
        {
            /* Report Dem Hardware Error */
            if ((uint32)STD_ON != g_spiCfgPtr->eHardwareErrorCfg.state) /* no Dem Error */
            {
                /* No Operation */
            }
            else
            {
                (void)Dem_SetEventStatus((Dem_EventIdType)g_spiCfgPtr->eHardwareErrorCfg.id, DEM_EVENT_STATUS_FAILED);
            }
            break;
        }
        /* job Synchronous transmission success */
        default: 
        {
            /* Call Dem_ReportErrorStatus. */
            if ((uint32)STD_ON != g_spiCfgPtr->eHardwareErrorCfg.state) /* no Dem Error */
            {
                /* No Operation */
            }
            else
            {
                (void)Dem_SetEventStatus((Dem_EventIdType)g_spiCfgPtr->eHardwareErrorCfg.id, DEM_EVENT_STATUS_PASSED);
            }
            break;
        }
    }
#endif 
    return transStatus;
}

/*!
* @brief    Service for starting a job synchronous transmission
* 
* @param[in] SyncTransmitStatePtr        pointer to job synchronous transmission state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
static FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTransJob
    ( P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr )
{
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) chanAttrCfgTXPtr = NULL_PTR;
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) chanAttrCfgRXPtr = NULL_PTR;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) chanCfgTXPtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) chanCfgRXPtr;
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr;
    
    VAR(uint8, AUTOMATIC) jobFirstChannel = (uint8)TRUE;
    VAR(sint32, AUTOMATIC) timeout = (sint32)SPI_TIMEOUT_NUMBER;
    VAR(Std_ReturnType, AUTOMATIC) syncJobStatus = (Std_ReturnType)E_OK;
    VAR(uint32, AUTOMATIC) fsrTxRxStatus = 0u;
    VAR(Spi_ChannelType, AUTOMATIC) txChannel = 0u;
    VAR(Spi_ChannelType, AUTOMATIC) rxChannel = 0u;

    while(SyncTransmitStatePtr->spiTxChannelsNum > (Spi_ChannelType)0)
    {
        SyncTransmitStatePtr->spiTxChannelsNum--;
        /* Get tx channel ID */
        txChannel = *SyncTransmitStatePtr->spiTxChannelIndexListPtr;

        /* Get TX Channel Attributes configuration */
        chanAttrCfgTXPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[txChannel];
        /* Update frames command */
        SyncTransmitStatePtr->frameCmd = SyncTransmitStatePtr->spiJobCmd | chanAttrCfgTXPtr->attrSC1R;
        REG_WRITE32(SPI_CTRL1_ADDRESS_U32, (SyncTransmitStatePtr->frameCmd & SPI_CTRL1_BITS_MASK));
        REG_RMW32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG),
            chanAttrCfgTXPtr->attrSC2R & (SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG));
        chanCfgTXPtr = &g_spiCfgPtr->pcChannelCfgPtr[txChannel];

        channelStatePtr = chanCfgTXPtr->channelStatePtr;
        SyncTransmitStatePtr->spiDefaultTransmitValue = chanCfgTXPtr->defaultTransmitValueSet;
        SyncTransmitStatePtr->spiTxDataAccess = chanAttrCfgTXPtr->dataAccessWidth;

        /* Get TX buffers */
        if (1u != (channelStatePtr->transmitFlags & ((uint8)SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG))) 
        {
            /* update tx buffer */
            SyncTransmitStatePtr->spiTxBufferPtr = chanCfgTXPtr->pcBufferDescriptPtr->pBufferTXPtr;
        }
        else 
        {
            /* use default value */
            SyncTransmitStatePtr->spiTxBufferPtr = NULL_PTR;
        }
        SyncTransmitStatePtr->spiTxLength = channelStatePtr->dataLength;

        switch(chanAttrCfgTXPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                SyncTransmitStatePtr->spiTxLength /= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , No Operation */
                break; 
        }

        /* Get RX buffers and the RX data length */
        switch(jobFirstChannel)
        {
            case TRUE:
            {
                SyncTransmitStatePtr->spiRxChannelsNum--;
                /* Get RX channel ID */
                rxChannel = *SyncTransmitStatePtr->spiRxChannelIndexListPtr;
                /* Get RX channel configuration */
                chanAttrCfgRXPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[rxChannel];
                chanCfgRXPtr = &g_spiCfgPtr->pcChannelCfgPtr[rxChannel];
                SyncTransmitStatePtr->spiRxBufferPtr = chanCfgRXPtr->pcBufferDescriptPtr->pBufferRXPtr;
                SyncTransmitStatePtr->spiRxDataAccess = chanAttrCfgRXPtr->dataAccessWidth;
                SyncTransmitStatePtr->spiRxLength = SyncTransmitStatePtr->spiTxLength;
                break;
            }
            default:
                /* No Operation */
                break;  
        }

        timeout = (sint32)SPI_TIMEOUT_NUMBER;
        Spi_Hw_SyncFlushRxFifo();
        /* Get RX/TX ISR status */
        fsrTxRxStatus = REG_READ32(SPI_STS_ADDRESS_U32) & (SPI_STS_FRLSEL | SPI_STS_FTLSEL);
        /* Check if remain datas to read or write */
#if (STD_ON == SPI_SLAVE_SUPPORT)
        if ((boolean)TRUE == Spi_Hw_SyncIsSlaveJob(SyncTransmitStatePtr))
        {
            while ((SyncTransmitStatePtr->spiTxLength > 0u)
                || (SyncTransmitStatePtr->spiRxLength > 0u)
                || (fsrTxRxStatus != 0u))
            {
                VAR(Std_ReturnType, AUTOMATIC) txStatus;
                VAR(Std_ReturnType, AUTOMATIC) rxStatus;
                VAR(boolean, AUTOMATIC) countTimeout = (boolean)TRUE;

                fsrTxRxStatus = REG_READ32(SPI_STS_ADDRESS_U32) & (SPI_STS_FRLSEL | SPI_STS_FTLSEL);
                txStatus = Spi_Hw_SyncTXTrans(SyncTransmitStatePtr);
                rxStatus = Spi_Hw_SyncRXTrans(SyncTransmitStatePtr, SPI_NORMAL_SYNCTRANS);

                if (((Std_ReturnType)E_OK == txStatus) || ((Std_ReturnType)E_OK == rxStatus))
                {
                    timeout = (sint32)SPI_TIMEOUT_NUMBER;
                    countTimeout = (boolean)FALSE;
                }
                else if ((boolean)TRUE == Spi_Hw_SyncIsSlaveIdleWait(SyncTransmitStatePtr, txStatus, rxStatus))
                {
                    timeout = (sint32)SPI_TIMEOUT_NUMBER;
                    countTimeout = (boolean)FALSE;
                }
                else
                {
                    /* No Operation */
                }

                if ((boolean)TRUE == countTimeout)
                {
                    timeout--;
                }

                if (timeout <= (sint32)0)
                {
                    SyncTransmitStatePtr->spiTxChannelsNum = 0u;
                    SyncTransmitStatePtr->spiRxChannelsNum = 0u;
                    syncJobStatus = (Std_ReturnType)E_NOT_OK;
                    break;
                }
            }
        }
        else
#endif
        {
        while((SyncTransmitStatePtr->spiTxLength > 0u) \
            || ((SyncTransmitStatePtr->spiRxLength > 0u) && (SyncTransmitStatePtr->spiJobEndFlag == (uint8)TRUE)) \
            || (fsrTxRxStatus != 0u))
        {
            VAR(Std_ReturnType, AUTOMATIC) txStatus;
            VAR(Std_ReturnType, AUTOMATIC) rxStatus;
            VAR(boolean, AUTOMATIC) countTimeout = (boolean)TRUE;

            fsrTxRxStatus = REG_READ32(SPI_STS_ADDRESS_U32) & (SPI_STS_FRLSEL | SPI_STS_FTLSEL);
            /* start TX Sync Transmit */
            txStatus = Spi_Hw_SyncTXTrans(SyncTransmitStatePtr);
            /* start RX Sync Transmit */
            rxStatus = Spi_Hw_SyncRXTrans(SyncTransmitStatePtr, SPI_NORMAL_SYNCTRANS);

            if (((Std_ReturnType)E_OK == txStatus) || ((Std_ReturnType)E_OK == rxStatus))
            {
                timeout = (sint32)SPI_TIMEOUT_NUMBER;
                countTimeout = (boolean)FALSE;
            }

            if ((boolean)TRUE == countTimeout)
            {
                timeout--;
            }

            /* Check if transfer timeout */
            if (timeout <= (sint32)0) 
            {
                /* timeout: stop outer channel loop to avoid illegal channel index access */
                SyncTransmitStatePtr->spiTxChannelsNum = 0u;
                SyncTransmitStatePtr->spiRxChannelsNum = 0u;
                syncJobStatus = (Std_ReturnType)E_NOT_OK;
                break;
            }
        } 
        }

        if ((Std_ReturnType)E_NOT_OK == syncJobStatus)
        {
            break;
        }

        SyncTransmitStatePtr->spiTxChannelIndexListPtr++;
        jobFirstChannel=(uint8)FALSE;
    } 
    return syncJobStatus;
}

#if (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE)
/*!
* @brief     Service for starting synchronous transmission for optimized sequences with only one job.
* 
* @param[in] SeqCfgPtr       Pointer to sequence configuration
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTransFast
    ( P2CONST(Spi_CachedSeqAttrType, AUTOMATIC, SPI_APPL_CONST) SeqCfgPtr )
{
    P2CONST(Spi_CachedChannelAttrType, AUTOMATIC, SPI_APPL_CONST) chanTXPtr;

    P2VAR(Spi_SyncProcessStateType, AUTOMATIC, SPI_APPL_DATA) \
          syncTransStatePtr = &s_SpiSyncTransState[SeqCfgPtr->spiHwUnit];
    P2VAR(Spi_JobStateType, AUTOMATIC, SPI_APPL_DATA) jobStatePtr = SeqCfgPtr->spiJobStatePtr;
    
    VAR(sint32, AUTOMATIC) timeout = SPI_TIMEOUT_NUMBER;
    VAR(Std_ReturnType, AUTOMATIC) transStatus;
    VAR(uint8, AUTOMATIC) firstJobChannel=(uint8)TRUE;
    volatile VAR(Std_ReturnType, AUTOMATIC) tempTxRxStatus = (Std_ReturnType)E_NOT_OK;
    VAR(uint32, AUTOMATIC) spiBaseAddress = SeqCfgPtr->spiBaseAddress;
    
    /* Set job Result to SPI_JOB_PENDING */
    jobStatePtr->jobResult = SPI_JOB_PENDING;
    /* Set module state to SPI_BUSY */
    *(SeqCfgPtr->spiHWStatusPtr) = SPI_BUSY;
    
    
     /* Update RX channel info of Synchronous transmission */
    syncTransStatePtr->spiRxChannelPtr = SeqCfgPtr->spiChannelsPtr;
    syncTransStatePtr->spiRxChannelsNum = SeqCfgPtr->spiChannelsNum;
    chanTXPtr = SeqCfgPtr->spiChannelsPtr;
    
    syncTransStatePtr->spiBaseAddress = spiBaseAddress;
    syncTransStatePtr->spiJobEndFlag = (uint8)FALSE;
    
     /* Get Tx channel number of Synchronous transmission */
    syncTransStatePtr->spiTxChannelsNum = SeqCfgPtr->spiChannelsNum;

    while(syncTransStatePtr->spiTxChannelsNum > (Spi_ChannelType)0)
    {
        syncTransStatePtr->spiTxChannelsNum--;
        syncTransStatePtr->spiDefaultTransmitValue = chanTXPtr->spiDefaultTransmitValue;
        syncTransStatePtr->spiTxDataAccess = chanTXPtr->spiDataAccessedWidth;

        /* Get TX buffers */
        if (1u == (chanTXPtr->spiStatePtr->transmitFlags & SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG))
        {
            /* use default value */
            syncTransStatePtr->spiTxBufferPtr = NULL_PTR;
        }
        else 
        { 
            /* Input TX buffers valid , update tx buffer */
            syncTransStatePtr->spiTxBufferPtr = chanTXPtr->spiBufDescriptorPtr->pBufferTXPtr;
        }
        syncTransStatePtr->spiTxLength = chanTXPtr->spiStatePtr->dataLength;
        switch(chanTXPtr->spiDataAccessedWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                syncTransStatePtr->spiTxLength /= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , No Operation */
                break; 
        }
        /* Get RX buffers and the RX data length */
        switch(firstJobChannel)
        {
            case TRUE:
            {
                syncTransStatePtr->spiRxChannelsNum--;
                syncTransStatePtr->spiRxBufferPtr = syncTransStatePtr->spiRxChannelPtr->spiBufDescriptorPtr->pBufferRXPtr;
                syncTransStatePtr->spiRxLength = syncTransStatePtr->spiTxLength;
                syncTransStatePtr->spiRxDataAccess = syncTransStatePtr->spiRxChannelPtr->spiDataAccessedWidth;
                break;
            }
            default:
                /* No Operation */
                break;  
        }

        timeout = SPI_TIMEOUT_NUMBER;

        /* Check remain datas to read or to write */
        while((syncTransStatePtr->spiTxLength > 0u) || \
              ((syncTransStatePtr->spiJobEndFlag == (uint8)TRUE) && (syncTransStatePtr->spiRxLength > 0u)))
        {
            /* start TX Sync Transmit */
            tempTxRxStatus = Spi_Hw_SyncTXTrans(syncTransStatePtr);
            switch(tempTxRxStatus)
            {
                case E_OK:
                {
                    timeout = SPI_TIMEOUT_NUMBER;
                    break;
                }
                default:
                    /* Transmission fail */
                    break;  
            }

            /* start RX Sync Transmit */
            tempTxRxStatus = Spi_Hw_SyncRXTrans(syncTransStatePtr, SPI_FAST_SYNCTRANS);
            switch(tempTxRxStatus)
            {
                case E_OK:
                {
                    timeout = SPI_TIMEOUT_NUMBER;
                    break;
                }
                default:
                    /* Transmission fail */
                    break;  
            }

            timeout--;

            /* Check if transfer timeout */
            if (timeout <= (sint32)0) 
            {
                /* timeout, job Synchronous transmission fail */
                syncTransStatePtr->spiTxChannelsNum = 0U;
                syncTransStatePtr->spiRxChannelsNum = 0U;
                break;
            }
        } 
        chanTXPtr++;
        firstJobChannel=(uint8)FALSE;
    }
    *(SeqCfgPtr->spiHWStatusPtr) = SPI_IDLE;
    if (timeout > (sint32)0)
    {
        /* Set Job result as SPI_JOB_OK */
        jobStatePtr->jobResult = SPI_JOB_OK;
        transStatus = (Std_ReturnType)E_OK;
    }
    /* timeout, job Synchronous transmission fail */
    else 
    {
        /* Set Job result as SPI_JOB_FAILED */
        jobStatePtr->jobResult = SPI_JOB_FAILED;
        transStatus = (Std_ReturnType)E_NOT_OK;
    }
    #if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)
        if((uint32)STD_ON == g_spiCfgPtr->eHardwareErrorCfg.state)
        {
            if(E_NOT_OK == transStatus)
            {
                (void)Dem_SetEventStatus((Dem_EventIdType)g_spiCfgPtr->eHardwareErrorCfg.id, DEM_EVENT_STATUS_FAILED);
            }
            else
            {
                (void)Dem_SetEventStatus((Dem_EventIdType)g_spiCfgPtr->eHardwareErrorCfg.id, DEM_EVENT_STATUS_PASSED);
            }
        }
        else
        {
            /* No Operation */
        }

    #endif
    return transStatus;
}
#endif /* { (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE) } */

/*!
* @brief    Service for filling the SPI TX FIFO.
* 
* @param[in] SyncTransmitStatePtr      pointer to synchronous transmission state
* @param[out] None
* @param[in,out] None
*
* @retval transStatus:E_OK,E_NOT_OK
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncTXTrans
    ( P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr )
{
    P2CONST(uint16, AUTOMATIC, SPI_APPL_CONST) tx16BitBufferPtr;
    P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) txBufferPtr = SyncTransmitStatePtr->spiTxBufferPtr;
    
    VAR(Std_ReturnType, AUTOMATIC) transStatus = (Std_ReturnType)E_NOT_OK;
    VAR(uint32, AUTOMATIC) devFSTS;
    VAR(uint8, AUTOMATIC) txDataAccess = SyncTransmitStatePtr->spiTxDataAccess;
    VAR(uint8, AUTOMATIC) txDataFifoFlg = (uint8)FALSE;
    
    /* Get device FIFO Status Register(FSTS) value */
    devFSTS = REG_READ32(SPI_STS_ADDRESS_U32);
#if (STD_ON == SPI_SLAVE_SUPPORT)
    if ((boolean)TRUE == Spi_Hw_SyncIsSlaveJob(SyncTransmitStatePtr))
    {
        /* Slave: load TX only when shift register / TX pipeline is empty (TXBE) */
        if ((SyncTransmitStatePtr->spiTxLength > 0u)
            && (0u != (devFSTS & SPI_STS_TXBEFLG)))
        {
            txDataFifoFlg = TRUE;
        }
        else
        {
            txDataFifoFlg = FALSE;
        }
    }
    else
#endif
    {
        /* Check datas to be send and the FIFO status */
        if (((((devFSTS & SPI_STS_FTLSEL) >> 11u) + ((devFSTS & SPI_STS_FRLSEL) >> 9u)) < (SPI_CFG_FIFOSIZE - 1u)) && \
           (SyncTransmitStatePtr->spiTxLength > 0u))
        {
            txDataFifoFlg = TRUE;
        }
        else
        {
            txDataFifoFlg = FALSE;
        }
    }
    switch(txDataFifoFlg)
    {
        case TRUE:
        {
            SyncTransmitStatePtr->spiTxLength--;
            /* prepare transfer data */
            if (NULL_PTR != txBufferPtr)
            {
                /* txBufferPtr valid , Get the transfer data */
                switch(txDataAccess)
                {
                    case SPI_ACCESS_DATATYPE_16:
                    {
                        /*** @warning Spi_Hw_c_MISRA_REF2 Casting to different object pointer type.
                                 Pointer cast to stricter alignment.*/
                        tx16BitBufferPtr = (uint16 *) txBufferPtr;
                        /* Set the Transmit Data Register(TXDATA) */
                        REG_WRITE32(SPI_DATA_ADDRESS_U32, (*tx16BitBufferPtr));
                        txBufferPtr++;
                        break;
                    }
                    /* default data accesss width 8bits */
                    default: 
                    {
                        /* Set the Transmit Data Register(TXDATA) */
                        REG_WRITE8(SPI_DATA_ADDRESS_U32, (*txBufferPtr));
                        break;
                    }
                }
                txBufferPtr++;
            }
            else 
            {
                /* Use default data,Set the Transmit Data Register(TXDATA) */
                REG_WRITE32(SPI_DATA_ADDRESS_U32, SyncTransmitStatePtr->spiDefaultTransmitValue);
            }
            /* update tx Buffer pointer */
            SyncTransmitStatePtr->spiTxBufferPtr = txBufferPtr;

            /* Check the remain datas and channels */
            if (0u != ( SyncTransmitStatePtr->spiTxLength | SyncTransmitStatePtr->spiTxChannelsNum )) /* remain datas */
            {
                /* No Operation */
            }
            else 
            {
                /* job end */
                SyncTransmitStatePtr->spiJobEndFlag=(uint8)TRUE;
            }
            transStatus = (Std_ReturnType)E_OK;
            break;
        }
        default:
            /* no datas to be send or the FIFO is full , No Operation */
            break; 
    }
    return transStatus;
}

/*!
* @brief    Service for getting the received data from SPI FIFO
* 
* @param[in] SyncTransmitStatePtr   Pointer to the synchronous transmission state
* @param[in] SyncType               SPI_NORMAL_SYNCTRANS,SPI_FAST_SYNCTRANS
* @param[out] None
* @param[in,out] None
*
* @retval transStatus:E_OK,E_NOT_OK
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SyncRXTrans
  (P2VAR(Spi_SyncProcessStateType, AUTOMATIC,SPI_APPL_DATA) SyncTransmitStatePtr, VAR(uint8, AUTOMATIC) SyncType)
{
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) chanAttrCfgRXPtr = NULL_PTR;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) chanCfgRXPtr;
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr;
    P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) spiRxBufferPtr = SyncTransmitStatePtr->spiRxBufferPtr;
    P2VAR(uint16, AUTOMATIC, SPI_APPL_DATA) rx16BitBufferPtr;
    VAR(uint8, AUTOMATIC) spiRxDataAccess = SyncTransmitStatePtr->spiRxDataAccess;
    VAR(Std_ReturnType, AUTOMATIC) transStatus = (Std_ReturnType)E_NOT_OK;
    VAR(uint32, AUTOMATIC) devFSTS;
    VAR(Spi_ChannelType, AUTOMATIC) rxChannel=0u;

    /* Check datas to be Received in the FIFO */
    if (0u == SyncTransmitStatePtr->spiRxLength)
    {
        /* No Received datas in the FIFO , No Operation */
    }
    else
    {
        devFSTS = REG_READ32(SPI_STS_ADDRESS_U32);
        if ((0u == (devFSTS & SPI_STS_FRLSEL)) && (0u == (devFSTS & SPI_STS_RXBNEFLG)))
        {
            /* No RX data yet */
        }
        else
        {
             SyncTransmitStatePtr->spiRxLength--;
            /* prepare read data buffer */
            if (NULL_PTR != spiRxBufferPtr) /* RxBufferPtr valid */
            {
                switch(spiRxDataAccess)
                {
                    case SPI_ACCESS_DATATYPE_16:
                    {
                        /*** @warning Spi_Hw_c_MISRA_REF2 Casting to different object pointer type.
                                 Pointer cast to stricter alignment.*/
                        rx16BitBufferPtr = (uint16 *) spiRxBufferPtr;
                        /*** @warning Spi_Hw_c_MISRA_REF1 Performing pointer arithmetic.*/
                        spiRxBufferPtr = &spiRxBufferPtr[2];
                        *rx16BitBufferPtr = (uint16)REG_READ32(SPI_DATA_ADDRESS_U32);
                        break;
                    }
                    /* default data accesss width 8bits */
                    default: 
                    {
                        *spiRxBufferPtr = (Spi_DataBufferType)REG_READ32(SPI_DATA_ADDRESS_U32);
                        spiRxBufferPtr++;
                        break;
                    }
                }
            }
            else
            {
                /* Abandon read data */
                s_SpiReadAbandon = REG_READ32(SPI_DATA_ADDRESS_U32);
            }
            /* update rx Buffer pointer */
            SyncTransmitStatePtr->spiRxBufferPtr = spiRxBufferPtr;
            /* Check the remain channels and update */
            if((0u == SyncTransmitStatePtr->spiRxLength) && (0u < SyncTransmitStatePtr->spiRxChannelsNum))
            {
                SyncTransmitStatePtr->spiRxChannelsNum--;
                switch(SyncType)
                {
                    case SPI_FAST_SYNCTRANS:
                    {
                    #if (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE)
                        SyncTransmitStatePtr->spiRxChannelPtr++;
                        /* Get RX buffers and the received data length */
                        SyncTransmitStatePtr->spiRxLength = SyncTransmitStatePtr->spiRxChannelPtr->spiStatePtr->dataLength;
                        SyncTransmitStatePtr->spiRxBufferPtr = SyncTransmitStatePtr->spiRxChannelPtr->spiBufDescriptorPtr->pBufferRXPtr;
                        SyncTransmitStatePtr->spiRxDataAccess = SyncTransmitStatePtr->spiRxChannelPtr->spiDataAccessedWidth;
                        spiRxDataAccess = SyncTransmitStatePtr->spiRxDataAccess;
                    #endif
                        break;
                    }
                    case SPI_NORMAL_SYNCTRANS:
                    {
                        SyncTransmitStatePtr->spiRxChannelIndexListPtr++;
                        /* Get rx channel ID */
                        rxChannel = *SyncTransmitStatePtr->spiRxChannelIndexListPtr;
                        /* Get the channel attributes configuration */
                        chanAttrCfgRXPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[rxChannel];
                        SyncTransmitStatePtr->spiRxDataAccess = chanAttrCfgRXPtr->dataAccessWidth;
                        spiRxDataAccess = SyncTransmitStatePtr->spiRxDataAccess;
                        /* Get rx channel configuration */
                        chanCfgRXPtr = &g_spiCfgPtr->pcChannelCfgPtr[rxChannel];
                        channelStatePtr = chanCfgRXPtr->channelStatePtr;
                        SyncTransmitStatePtr->spiRxLength = channelStatePtr->dataLength;
                        SyncTransmitStatePtr->spiRxBufferPtr = chanCfgRXPtr->pcBufferDescriptPtr->pBufferRXPtr;
                        break;
                    }
                    default:
                        /* No Operation */
                        break;
                }
                switch(spiRxDataAccess)
                {
                    case SPI_ACCESS_DATATYPE_16:
                    {
                        SyncTransmitStatePtr->spiRxLength /= 2u;
                        break;
                    }
                    /* default data accesss width 8bits */
                    default: 
                        /* No Operation */
                        break;
                }
            }
            else
            {
                /* No Operation */
            }
            transStatus = (Std_ReturnType)E_OK;
        }
    }
    return transStatus;
}
#endif /* LEVEL1 != SPI_LEVEL_DELIVERED */

#if ((LEVEL0 != SPI_LEVEL_DELIVERED) && (STD_ON == SPI_DMA_SUPPORT))

/*!
* @brief     config the RX channel's DMA interrupts
* 
* @param[in] HwStatePtr      pointer to HWUnit state
* @param[in] AsyncMode       Operation mode:SPI_INTERRUPT_MODE,SPI_POLLING_MODE
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaIrqCfg \
    (P2CONST(Spi_HwStateType, AUTOMATIC, SPI_APPL_CONST) HwStatePtr, VAR(Spi_AsyncModeType, AUTOMATIC) AsyncMode)
{
    /* Check the Async mode */
    switch(AsyncMode)
    {
        case SPI_POLLING_MODE:
        {
            /* Disables the interrupts when all transfer completes */
//            Pdl_TopDmaNotifiDis(HwStatePtr->spiHwUnitCfgPtr->txDmaChannel,PDL_DMA_TRAN_COMPLETED);
//            Pdl_TopDmaNotifiDis(HwStatePtr->spiHwUnitCfgPtr->rxDmaChannel,PDL_DMA_TRAN_COMPLETED);
            /* Set RX DMA TCINTEN first */
            Pdl_TopDmaNotifiEn(HwStatePtr->spiHwUnitCfgPtr->rxDmaChannel,PDL_DMA_TRAN_COMPLETED);
            /* Set TX DMA TCINTEN follow */
            Pdl_TopDmaNotifiEn(HwStatePtr->spiHwUnitCfgPtr->txDmaChannel,PDL_DMA_TRAN_COMPLETED); 
            break;
        }
        case SPI_INTERRUPT_MODE:
        {
            /* Set RX DMA TCINTEN first */
            Pdl_TopDmaNotifiEn(HwStatePtr->spiHwUnitCfgPtr->rxDmaChannel,PDL_DMA_TRAN_COMPLETED);
            /* Set TX DMA TCINTEN follow */
            Pdl_TopDmaNotifiEn(HwStatePtr->spiHwUnitCfgPtr->txDmaChannel,PDL_DMA_TRAN_COMPLETED);
            break;
        }
        default:
            /* No Operation */
            break;
    }
}

/*!
* @brief    Initialize TX DMA channl
* 
* @param[in] HwStatePtr       pointer to HWUnit state
* @param[in] Channel          channel ID
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaChanTXInit \
    (P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel)
{
    P2CONST(Spi_HWUnitConfigType, AUTOMATIC, SPI_APPL_CONST) spiHwUnitCfgPtr = HwStatePtr->spiHwUnitCfgPtr;
    
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) channelAttrCfgPtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) channelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel];
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr = channelCfgPtr->channelStatePtr;
    P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) spiTxBufferPtr;
    
    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt;
    VAR(uint32, AUTOMATIC) frameCmd;
    VAR(uint32, AUTOMATIC) fifoCfg;

    /* Get current channel attributes configuration */
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[Channel];
    /* Get current channel transmit command */
    frameCmd = (HwStatePtr->spiExtDeviceCTRL1 | channelAttrCfgPtr->attrSC1R);
    HwStatePtr->spiCurrentCmd = frameCmd;
    /* Get current channel attributes configuration of FIFO Control Register */
    fifoCfg = (channelAttrCfgPtr->attrSC2R);

    /* LSB First Transfer Select(LSBSEL) */
    REG_RMW32(SPI_CTRL1_ADDRESS_U32, SPI_CTRL1_LSBSEL,frameCmd & SPI_CTRL1_LSBSEL_LSB);
    /* config DSCFG & FRTCFG in SPI_CTRL2 */
    REG_RMW32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG, fifoCfg & (SPI_CTRL2_FRTCFG | SPI_CTRL2_DSCFG));

    framesCnt = channelStatePtr->dataLength;
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            framesCnt /= 2u;
            break;
        }
        default:
            /* Default data accesss width 8bits , No Operation */
            break; 
    }
    if (framesCnt <= 1u)
    {
        /*
         * Single-frame DMA special case:
         * lower RX FIFO request threshold to avoid missing DMA request on 1-byte transfer.
         */
        REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_FRTCFG);
    }

    /* Check TX buffer's type and update information into DMA TCDs */
    if (0u == (channelStatePtr->transmitFlags & ((uint8)SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG))) /* Input Tx buffer valid */
    {
        spiTxBufferPtr = channelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr;
        /* Input Txbuffer as source address and update it into DMA CHMADDR */
        Pdl_TopDmaMAddrRefresh(spiHwUnitCfgPtr->txDmaChannel,(uint32)spiTxBufferPtr);
        /* Set destination address */
    }
    /* use default value buffer */
    else 
    {
        /* Default value buffer as source address and update it into DMA */
        Pdl_TopDmaMAddrRefresh(spiHwUnitCfgPtr->txDmaChannel,(uint32)(&channelCfgPtr->defaultTransmitValueSet));
    }

    /* Confirm the DMA send frames number */
    if (framesCnt <= SPI_MAX_ROUND_CNT_OF_DMA) 
    {
        /* framesCnt not full , update TX transfer frames count */
        HwStatePtr->spiRemainFrames = 0u;
    }
    else
    {
        /* DMA round count : 9 bits, if used e_link field */
        HwStatePtr->spiRemainFrames = framesCnt - SPI_MAX_ROUND_CNT_OF_DMA;
        switch(channelAttrCfgPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                HwStatePtr->spiRemainFrames *= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , no Operation */
                break; 
        }
        framesCnt = SPI_MAX_ROUND_CNT_OF_DMA;
    }
    /* Update DMA TX transfer count for current channel transmission explicitly. */
    Pdl_TopDmaChDataNumSet(spiHwUnitCfgPtr->txDmaChannel, framesCnt);
    /* Start the DMA TX HWunit request */
    Pdl_TopDmaChEn(spiHwUnitCfgPtr->txDmaChannel);

}

/*!
* @brief    Initialize RX DMA channl
* 
* @param[in] HwStatePtr     pointer to HWUnit state
* @param[in] Channel        channel ID
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_DmaChanRXInit \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr, VAR(Spi_ChannelType, AUTOMATIC) Channel )
{
    /* Get the HwUnit configuration */
    P2CONST(Spi_HWUnitConfigType, AUTOMATIC, SPI_APPL_CONST) spiHwUnitCfgPtr = HwStatePtr->spiHwUnitCfgPtr;;
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) channelAttrCfgPtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) channelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel];
    P2CONST(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_CONST) channelStatePtr = channelCfgPtr->channelStatePtr;
    P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) spiRxBufferPtr;

    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt;
    
    /* Get channel attributes configuration */
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[Channel];
    framesCnt = channelStatePtr->dataLength;
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            framesCnt /= 2u;
            break;
        }
        default:
            /* default data accesss width 8bits , no Operation */
            break; 
    }

    /* Confirm the DMA receive frames number */
    if (framesCnt <= SPI_MAX_ROUND_CNT_OF_DMA) /* framesCnt not full */
    {
        HwStatePtr->spiReceivedData = 0u;
    }
    else
    {
        /* DMA round count : 9 bits, if used e_link field */
        HwStatePtr->spiReceivedData = framesCnt - SPI_MAX_ROUND_CNT_OF_DMA;
        switch(channelAttrCfgPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                HwStatePtr->spiReceivedData *= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , no Operation */
                break; 
        }
        framesCnt = SPI_MAX_ROUND_CNT_OF_DMA;
    }
    /* Update DMA RX transfer count for current channel transmission explicitly. */
    Pdl_TopDmaChDataNumSet(spiHwUnitCfgPtr->rxDmaChannel, framesCnt);
    /* Get channel configuration of RX buffer descriptor */
    spiRxBufferPtr = channelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr;

    /* Abandon the read datas if Rx buffer is invalid */
    if (NULL_PTR != spiRxBufferPtr) /* Rx buffer is valid */
    {
        /* Rxbuffer as destination address and update it into DMA */
        spiRxBufferPtr = channelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr;
        Pdl_TopDmaMAddrRefresh(spiHwUnitCfgPtr->rxDmaChannel,(uint32)spiRxBufferPtr);
    }
    else
    {
        Pdl_TopDmaMAddrRefresh(spiHwUnitCfgPtr->rxDmaChannel,(uint32)&s_SpiReadAbandon);
    }

    /* Start the DMA RX HWunit request */
    Pdl_TopDmaChEn(spiHwUnitCfgPtr->rxDmaChannel);
}

/*!
* @brief    Continue the DMA transmission,regain the size with Source and destination addresses already in active TCDs
* 
* @param[in] HwStatePtr     pointer to HwUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function,can be called only after DMA configuration initialized
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_JobDmaTXContinue \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr ) 
{
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) \
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[*(HwStatePtr->spiCurTxChanIndexListPtr)];

    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt;
    
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            framesCnt = HwStatePtr->spiRemainFrames / 2u;
            break;
        }
        /* default data accesss width 8bits */
        default: 
        {
            framesCnt = HwStatePtr->spiRemainFrames;
            break; 
        }
    }

    /* Confirm the DMA send frames number */
    if (framesCnt <= SPI_MAX_ROUND_CNT_OF_DMA) 
    {
        /* framesCnt not full */
        HwStatePtr->spiRemainFrames = 0u;
    }
    else
    {
        HwStatePtr->spiRemainFrames = framesCnt - SPI_MAX_ROUND_CNT_OF_DMA;
        switch(channelAttrCfgPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                HwStatePtr->spiRemainFrames *= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , no Operation */
                break; 
        }
        framesCnt = SPI_MAX_ROUND_CNT_OF_DMA;
    }
    Pdl_TopDmaChDataNumSet(HwStatePtr->spiHwUnitCfgPtr->txDmaChannel, framesCnt);
    /* Clear Transmit Data Interrupt Enable bit , it will be config after RX DMA done */
    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_TXDEN);
}

/*!
* @brief    Continue the DMA transmission,regain the size with Source and destination addresses already in active TCDs
* 
* @param[in] HwStatePtr   pointer to HWUnit state
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_Hw_JobDmaRXContinue \
    ( P2VAR(Spi_HwStateType, AUTOMATIC, SPI_APPL_DATA) HwStatePtr ) 
{
    P2CONST(Spi_ChannelAttrCfgType, AUTOMATIC, SPI_APPL_CONST) \
    channelAttrCfgPtr = &g_spiCfgPtr->pcAttrCfgPtr->spiChannelAttrCfgPtr[*(HwStatePtr->spiCurRxChanIndexListPtr)];
    
    VAR(Spi_NumberOfDataType, AUTOMATIC) framesCnt;
    
    switch(channelAttrCfgPtr->dataAccessWidth)
    {
        case SPI_ACCESS_DATATYPE_16:
        {
            framesCnt = HwStatePtr->spiReceivedData / 2u;
            break;
        }
        /* default data accesss width 8bits */
        default: 
        {
            framesCnt = HwStatePtr->spiReceivedData;
            break; 
        }
    }

    /* Confirm the DMA receive frames number */
    if (framesCnt <= SPI_MAX_ROUND_CNT_OF_DMA)
    {
        HwStatePtr->spiReceivedData = 0u;
    }
    else
    {
        /* DMA round count : 9 bits, if used e_link field */
        HwStatePtr->spiReceivedData = framesCnt - SPI_MAX_ROUND_CNT_OF_DMA;
        switch(channelAttrCfgPtr->dataAccessWidth)
        {
            case SPI_ACCESS_DATATYPE_16:
            {
                HwStatePtr->spiReceivedData *= 2u;
                break;
            }
            default:
                /* default data accesss width 8bits , no Operation */
                break; 
        }
        framesCnt = SPI_MAX_ROUND_CNT_OF_DMA;
    }
    Pdl_TopDmaChDataNumSet(HwStatePtr->spiHwUnitCfgPtr->rxDmaChannel, framesCnt);

    /* Transmit Buffer DMA Enable */
    REG_BIT_SET32(SPI_CTRL2_ADDRESS_U32, SPI_CTRL2_TXDEN);
}
#endif  /* { (LEVEL0 != SPI_LEVEL_DELIVERED) && (STD_ON == SPI_DMA_SUPPORT) } */

#if ((STD_ON == SPI_CANCEL_API) && (STD_ON == SPI_SLAVE_SUPPORT))
/*!
* @brief    Service for cancelling the sequence transmission and stop sequence immediately in slave mode
* 
* @param[in] SeqId       sequence ID
* @param[out] None
* @param[in,out] None
*
* @retval None
*
* @note   Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Hw_SlaveTransCancel(VAR(Spi_SequenceType, AUTOMATIC) SeqId)
{
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr;
    P2CONST(Spi_HwStateType, AUTOMATIC, SPI_APPL_CONST) HwUnitStatePtr;
    P2CONST(Spi_SeqStateType, AUTOMATIC, SPI_APPL_CONST) seqStatePtr;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) jobPtr;

    VAR(uint32, AUTOMATIC) valOfSR;
    VAR(sint32, AUTOMATIC) timeout = SPI_TIMEOUT_NUMBER;
    VAR(Spi_JobType, AUTOMATIC) jobId;
    
    seqStatePtr = &g_spiSequenceState[SeqId];
    jobPtr = seqStatePtr->pcCurrentJobIndexPtr;
    jobId = *jobPtr;
    jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
    HwUnitStatePtr = &g_SpiHwUnitState[jobCfgPtr->jobHWUnit];
    switch(HwUnitStatePtr->spiHwUnitCfgPtr->hwUnitMode)
    {
        case SPI_SLAVE:
        {
        #if (STD_ON == SPI_DMA_SUPPORT)
            /* if use DMA ,there will stop the transfer */
            switch(HwUnitStatePtr->spiHwUnitCfgPtr->useDma)
            {
                case TRUE:
                {
                    
                    /* Disable TX channel first */
                    Pdl_TopDmaChDis(HwUnitStatePtr->spiHwUnitCfgPtr->txDmaChannel);
                    /* Disable RX channel follow */
                    Pdl_TopDmaChDis(HwUnitStatePtr->spiHwUnitCfgPtr->rxDmaChannel);
                    /* Disable DMA Buffer Enable for Receiving and Transmitting */
                    REG_BIT_CLEAR32(SPI_CTRL2_ADDRESS_U32, (SPI_CTRL2_RXDEN | SPI_CTRL2_TXDEN));
                    break;
                }
                default:
                    /* No Operation */
                    break;
            }
        #endif
            /* Wait until the SPI module is IDLE. There don't have data in Receive/Transmit FIFO count register */
            /* get the value of Module Busy Flag */
            valOfSR = REG_READ32(HwUnitStatePtr->spiStsAddr) & SPI_STS_BSYFLG;
 
            while(((uint32)0 != valOfSR))
            {
                timeout--;
                /* check the operation timeout status */
                if (timeout <= (sint32)0)
                {
                #if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED) 
                    /* Report Dem error */
                    switch(g_spiCfgPtr->eTimeoutErrorCfg.state)
                    {
                        case STD_ON:
                        {
                            (void)Dem_SetEventStatus((Dem_EventIdType)g_spiCfgPtr->eTimeoutErrorCfg.id, DEM_EVENT_STATUS_FAILED);
                            break;
                        }
                        default:
                            /* No Operation */
                            break;
                    }
                #endif  
                    /* End while loop */
                    break; 
                }
                /* Not timeout,continue */
                else 
                {
                    /* get the value of Module Busy Flag */
                    valOfSR = REG_READ32(HwUnitStatePtr->spiStsAddr) & SPI_STS_BSYFLG;
                }
            }

            /* job transmission end */
            Spi_JobTransEnd(jobCfgPtr);
            break;
        }
        default:
            /* No Operation */
            break;
    }
}
#endif   

#if (LEVEL1 != SPI_LEVEL_DELIVERED)
/*!
* @brief Perform SPI sequence synchronous transmission
* 
* @param[in] spiSeqId: SPI sequence ID value
* @param[out] None
* @param[in,out] None
*
* @retval spiSyncResult:E_OK,IPW Sync transmission status success
*                        :E_NOT_OK,IPW Sync transmission status fail
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_Hw_SeqSyncTrans(VAR(Spi_SequenceType, AUTOMATIC) spiSeqId)
{
    VAR(Std_ReturnType, AUTOMATIC) spiSyncResult = (Std_ReturnType)E_NOT_OK;
#if (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE)
    P2CONST(Spi_CachedSeqAttrType, AUTOMATIC, SPI_APPL_CONST) spiSeqCachePtr;
    VAR(Spi_JobType, AUTOMATIC) lpwJobIndex;
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) lpwSeqCfgPtr;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) lpwJobCfgPtr;
     
    /* map the SPI cached sequence configuration */
    spiSeqCachePtr = spiSingleJobSeqOptPtr[spiSeqId];
    if (NULL_PTR == spiSeqCachePtr)
    {
        /* get the sync transmission result */
        spiSyncResult = Spi_Hw_SyncTrans(spiSeqId);
    }
    else
    {
        /* Get sequence configuration */
        lpwSeqCfgPtr = &g_spiCfgPtr->seqCfgPtr[spiSeqId];
        /* Get the job id */
        lpwJobIndex = lpwSeqCfgPtr->pcJobIndexListPtr[0];
        /* Get job configuration */
        lpwJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[lpwJobIndex];
        /* assert job start notification */
        if (NULL_PTR == lpwJobCfgPtr->pfStartNotificationPtr)
        {
            /* Not configure SpiJobStartNotification , No Operation */
        }
        else
        {
            /* call job start notification */
            lpwJobCfgPtr->pfStartNotificationPtr();
        }
        /* get the sync transmission result */
        spiSyncResult = Spi_Hw_SyncTransFast(spiSeqCachePtr);
        /* assert job end notification */
        if (NULL_PTR == lpwJobCfgPtr->pfEndNotificationPtr)
        {
            /* Not configure SpiJobEndNotification , No Operation */
        }
        else
        {
            /* call job end notification */
            lpwJobCfgPtr->pfEndNotificationPtr();
        }
    }
#else
    /* get the sync transmission result */
    spiSyncResult = Spi_Hw_SyncTrans(spiSeqId);
#endif
    return spiSyncResult;
}

#endif 

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    
    #if (STD_ON == SPI_DMA_SUPPORT)
        /*!
        * @brief Spi0 SPI DMA Rx notification. 
        * 
        * @param[in] None
        * @param[out] None
        * @param[in,out] None
        *
        * @retval None
        *
        * @note   Non-AUTOSAR support function
        */
        FUNC (void, SPI_CODE) Spi0_IsrRxDma(void)
        {
            Spi_Hw_IsrRxDma(SPI_HWUNIT_TO_SPI(SPI0_HWUNIT_CFG));
        }
        /*!
        * @brief Spi0 SPI DMA Tx notification. 
        * 
        * @param[in] None
        * @param[out] None
        * @param[in,out] None
        *
        * @retval None
        *
        * @note   Non-AUTOSAR support function
        */
        FUNC (void, SPI_CODE) Spi0_IsrTxDma(void)
        {
            Spi_Hw_IsrTxDma(SPI_HWUNIT_TO_SPI(SPI0_HWUNIT_CFG));
        }
    #endif /* End SPI_DMA_SUPPORT */
    /*!
    * @brief Spi0: the end-of-queue Rx ISR
    * 
    * @param[in] None
    * @param[out] None
    * @param[in,out] None
    *
    * @retval None
    *
    * @note   Non-AUTOSAR support function
    */
    ISR(SPI_IRQHandler)
    {
        Spi_Hw_IrqRxFifo(SPI_HWUNIT_TO_SPI(SPI0_HWUNIT_CFG));
        EXIT_INTERRUPT();
    }
    
#endif /* {(LEVEL0 != SPI_LEVEL_DELIVERED)} */

#define SPI_STOP_SEC_CODE
#include "Spi_MemMap.h"

/**@} end of group SPI_Fuctions */
#ifdef __cplusplus
}
#endif
/**@} end of group SPI_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */

