//***************************************************************************** // (C) Automotive Lighting Reutlingen GmbH // Tuebinger Strasse 123, 72762 Reutlingen, Germany // // Automotive Lighting Reutlingen GmbH owns all the rights to this work. // This work shall not be copied, reproduced, used, modified, transferred // or its information shall not be disclosed without the prior written // authorization of Automotive Lighting Reutlingen GmbH. //***************************************************************************** //----------------------------------------------------------------------------- /// \file CddSpi.c /// /// \brief /// //----------------------------------------------------------------------------- //============================================================================= // includes //============================================================================= //#include #include #include #include //Derived implementation headers #include #ifdef CPU_S32K142 #include #endif #ifdef CPU_S32K146 #include #endif #ifdef CPU_S32K144 #include #endif #warning "to be eliminated when CDD_LED is implemented" uint32 CddLed78702_SpiTx(uint16 unIx) { return 0; } #warning "to be eliminated when CDD_LED is implemented" void CddLed78702_SpiRx(uint16 unIx, uint32 ulData) { //empty } #warning "to be eliminated when CDD_LED is implemented" uint32 CddLed92520_SpiTx(const uint16 unDeviceIdx) { return 0; } #warning "to be eliminated when CDD_LED is implemented" void CddLed92520_SpiRx(const uint16 unDeviceIdx, const uint32 ulData) { //empty } #warning "to be eliminated when CDD_LED is implemented" uint32 CddSbc_SpiTx(uint16 unIx) { return 0; } #warning "to be eliminated when CDD_LED is implemented" void CddSbc_SpiRx(uint16 unIx, uint32 ulData) { (void) unIx; (void) ulData; } //============================================================================= // Private typedefs //============================================================================= typedef enum teCddSpiState { CddSpi_eState_Reset = 0, CddSpi_eState_SingleOperation, CddSpi_eState_CyclicOperation }teCddSpiState; typedef boolean(*tfpCddSpiDevDynCfg)(uint16* punData); typedef struct tsCddSpiDevDynCfg { tfpCddSpiDevDynCfg fpDevDynCfgCb; }tsCddSpiDevDynCfg; //Interface enum #define CDDSPI_MAC_DECL_IFC_ENUM #include #undef CDDSPI_MAC_DECL_IFC_ENUM //Device frames enum #define CDDSPI_MAC_DECL_DEVFRM_ENUM #include #undef CDDSPI_MAC_DECL_DEVFRM_ENUM #ifdef CDDSPI_CYCLIC_OPERATION //Ifc seq enum #define CDDSPI_MAC_DECL_IFCSEQ_ENUM #include #undef CDDSPI_MAC_DECL_IFCSEQ_ENUM typedef void(*tfpCddSpiRxCb)(uint16 unId, uint32 ulData); typedef uint32(*tfpCddSpiTxCb)(uint16 unId); typedef struct tsCddSpiDevCb { tfpCddSpiTxCb fpTx; tfpCddSpiRxCb fpRx; }tsCddSpiDevCb; typedef struct tsCddSpiDevCbData { const uint16 unCbId; tsCddSpiDevCb sDevCb; }tsCddSpiDevCbData; typedef struct tsCddSpiDevSeqData { const teCddSpiDev eDev; tsCddSpiDevCbData* psDevCbData; }tsCddSpiDevSeqData; typedef struct tsCddSpiSeqData { const uint8 ucSize; const uint8 ucIfcSeqEntries; boolean boRxDataValid; tsCddSpiDevSeqData* const psDevData; }tsCddSpiSeqData; typedef struct tsCddSpiSeqHandler { uint16 unCycleCnt; const uint16 unPrescaler; teCddSpiIfc eSpiIfc; tsCddSpiSeqData* psSeqData; }tsCddSpiSeqHandler; #endif //CDDSPI_CYCLIC_OPERATION //============================================================================= // Preprocessor definitions //============================================================================= //Temporary, use GPT APIs instead #define CDDSPI_TIMEOUT_VAL (0xFFFFUL) //Debug //#define CDDSPI_DEBUG #ifdef CDDSPI_DEBUG #define CDDSPI_AUX_BUFF_SIZE 10U #endif //============================================================================= // Private variables //============================================================================= //Device handler #define CDDSPI_MAC_DECL_DEVHANDLE #include #undef CDDSPI_MAC_DECL_DEVHANDLE //Interface handler #define CDDSPI_MAC_DECL_IFC #include #undef CDDSPI_MAC_DECL_IFC #ifdef CDDSPI_DYNAMIC_CFG //Dev Dynamic Cfg #define CDDSPI_MAC_DECL_DEVDYNCFG #include #undef CDDSPI_MAC_DECL_DEVDYNCFG #endif #ifdef CDDSPI_CYCLIC_OPERATION //CBs prototypes #define CDDSPI_MAC_DECL_CBS #include #undef CDDSPI_MAC_DECL_CBS //Device CBs and CbIds #define CDDSPI_MAC_DECL_DEVCB #include #undef CDDSPI_MAC_DECL_DEVCB //Sequence data per interface #define CDDSPI_MAC_DECL_SEQDATAIFC #include #undef CDDSPI_MAC_DECL_SEQDATAIFC //Full sequence data #define CDDSPI_MAC_DECL_SEQDATA #include #undef CDDSPI_MAC_DECL_SEQDATA //Sequence handler #define CDDSPI_MAC_DECL_SEQHANDLE #include #undef CDDSPI_MAC_DECL_SEQHANDLE #endif //Spi driver state STATIC_AL teCddSpiState CddSpi_eState = CddSpi_eState_Reset; //============================================================================= // Private functions prototypes //============================================================================= #ifdef CDDSPI_CYCLIC_OPERATION STATIC_AL void CddSpi_ProcessSequence(uint8 ucIdx); STATIC_AL void CddSpi_ProcessRxCb(const tsCddSpiDevSeqData* psDevSeqData); STATIC_AL void CddSpi_ProcessTxCb(const tsCddSpiDevSeqData* psDevSeqData); #ifdef CDDSPI_DYNAMIC_CFG STATIC_AL boolean CddSpi_SetDynamicCfg(uint8 ucDev); STATIC_AL void CddSpi_UnSetDevCb(uint8 ucDev, uint8 ucCbIdx); #endif #endif //============================================================================= // Public functions implementation //============================================================================= //----------------------------------------------------------------------------- /// \brief /// /// \descr Call Derived Initialization function to configure SPI Interfaces selected in CddSpi_Cfg.h. /// /// \param - /// /// \return void //----------------------------------------------------------------------------- void CddSpi_Init(void) { //Check driver is not initialized if (CddSpi_eState == CddSpi_eState_Reset) { //Initialize Spi ifcs for (uint8 ucIfcIdx = 0; ucIfcIdx < (uint8)CddSpi_eIfc_Count; ucIfcIdx++) { CddSpi_InitIfc_Deriv(CddSpi_aucIfcMap[ucIfcIdx]); } //Switch mode to SINGLE Operation CddSpi_eState = CddSpi_eState_SingleOperation; } } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param - /// /// \return void //----------------------------------------------------------------------------- void CddSpi_DeInit(void) { //Check driver is not de-initialized if (CddSpi_eState != CddSpi_eState_Reset) { for (uint8 ucIdx = 0; ucIdx < (uint8)CddSpi_eIfc_Count; ucIdx++) { //Temporary software timer, use GPT instead uint32 ulTimer = CDDSPI_TIMEOUT_VAL; while ((CddSpi_IfcIdle_Deriv(CddSpi_aucIfcMap[ucIdx]) == FALSE) && (ulTimer > 0U)) { ulTimer--; } CddSpi_DeInitIfc_Deriv(CddSpi_aucIfcMap[ucIdx]); } CddSpi_eState = CddSpi_eState_Reset; } } #ifdef CDDSPI_SINGLE_OPERATION //----------------------------------------------------------------------------- /// \brief /// /// \descr Send/Receive single message on SPI bus (16-bit max.) /// /// \param eDevice = target SPI peripheral /// - use macro CDDSPI_DEVICE(name) as parameter /// - name = name of SPI peripheral specified in CddSpi_Cfg.h /// pData = in/out parameter (pointer) /// - data given in this variable will be sent to peripheral /// - data received by the peripheral will be placed in this /// variable if the function returns "true" /// /// \return bool returns true if the function call was successful and /// the variable pointed to by pData holds the value /// received by the SPI peripheral //----------------------------------------------------------------------------- boolean CddSpi_TransferMsg(uint8 ucDevice, uint16* punData) { boolean boRetVal = FALSE; //Check SPI is already initialized if (CddSpi_eState == CddSpi_eState_SingleOperation) { //Check device ID is on the range if (ucDevice < (uint8)CddSpi_eDev_Count) { //Temporary software timer, use GPT instead uint32 ulTimer = CDDSPI_TIMEOUT_VAL; //Get Device Transmission Parameters const tsCddSpiDevCfg * const psDevCfg = &CddSpi_asDeviceCfg[ucDevice]; //Configure Transmission Paramters CddSpi_ConfigureTransfer_Deriv(psDevCfg); //Process Tx for (uint8 ucFrame = 0; ucFrame < psDevCfg->ucElements; ucFrame++) { CddSpi_TxFifoPut_Deriv(psDevCfg->ucSpiIfc, punData[ucFrame]); } //Wait until transfer is completed while ((CddSpi_TransferComplete_Deriv(psDevCfg->ucSpiIfc, psDevCfg->ucElements) == FALSE) && (ulTimer > 0U)) { ulTimer--; } //Process Rx for (uint8 ucFrame = 0; ucFrame < psDevCfg->ucElements; ucFrame++) { punData[ucFrame] = (uint16)CddSpi_RxFifoGet_Deriv(psDevCfg->ucSpiIfc); } if (ulTimer > 0U) { boRetVal = TRUE; } } } return boRetVal; } #endif #ifdef CDDSPI_CYCLIC_OPERATION //----------------------------------------------------------------------------- /// \brief Start cyclic SPI communication /// /// \descr Cyclic SPI communication will be started /// CddSpi_Init() has to be called before! /// /// \param - /// /// \return - //----------------------------------------------------------------------------- void CddSpi_Start(void) { boolean boRunCycleOperation = TRUE; //Check if module is in Single Operation mode if (CddSpi_eState == CddSpi_eState_SingleOperation) { //Set Device Dynamic Configuration #ifdef CDDSPI_DYNAMIC_CFG for (uint8 ucDevIdx = 0; ucDevIdx < (uint8)CddSpi_eDev_Count; ucDevIdx++) { if (CddSpi_SetDynamicCfg(ucDevIdx) == FALSE) { boRunCycleOperation = FALSE; break; } } #endif if (boRunCycleOperation == TRUE) { for (uint8 ucSeqIdx = 0U; ucSeqIdx < (uint8)CddSpi_eSeq_Count; ucSeqIdx++) { //Temporary software timer, use GPT instead uint32 ulTimer = CDDSPI_TIMEOUT_VAL; //Wait until SPI Ifc is idle while ((CddSpi_IfcIdle_Deriv(CddSpi_aucIfcMap[CddSpi_asSeqHandler[ucSeqIdx].eSpiIfc]) == FALSE) && (ulTimer > 0U)) { ulTimer--; } } //Switch mode to CYCLIC operation CddSpi_eState = CddSpi_eState_CyclicOperation; } } } //----------------------------------------------------------------------------- /// \brief Stop cyclic SPI communication /// /// \descr Cyclic SPI communication will be stopped after next SPI message /// /// \param - /// /// \return - //----------------------------------------------------------------------------- void CddSpi_Stop(void) { //Check if module is in Cyclic Operation mode if (CddSpi_eState == CddSpi_eState_CyclicOperation) { for (uint8 ucSeqIdx = 0U; ucSeqIdx < (uint8)CddSpi_eSeq_Count; ucSeqIdx++) { //Temporary software timer, use GPT instead uint32 ulTimer = CDDSPI_TIMEOUT_VAL; //Wait until SPI Ifc is idle while ((CddSpi_IfcIdle_Deriv(CddSpi_aucIfcMap[CddSpi_asSeqHandler[ucSeqIdx].eSpiIfc]) == FALSE) && (ulTimer > 0U)) { ulTimer--; } //Clear RxFifo CddSpi_RxFifoClear_Deriv(CddSpi_aucIfcMap[CddSpi_asSeqHandler[ucSeqIdx].eSpiIfc]); } //Switch mode to SINGLE Operation CddSpi_eState = CddSpi_eState_SingleOperation; } } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param - /// /// \return void //----------------------------------------------------------------------------- void CddSpi_Cycle1ms(void) { //Check if module is in Cyclic Operation mode if (CddSpi_eState == CddSpi_eState_CyclicOperation) { for (uint8 ucSeqIdx = 0; ucSeqIdx < (uint8)CddSpi_eSeq_Count; ucSeqIdx++) { CddSpi_ProcessSequence(ucSeqIdx); } } } #endif //============================================================================= // Privatrivate functions implementation //============================================================================= #ifdef CDDSPI_DYNAMIC_CFG //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// E.g Footprint of 5 max elements and only 0,2,4 are active: /// /// --------- --------- --------- --------- --------- /// Elem Id | 4 | | 3 | | 2 | | 1 | | 0 | /// --------- --------- --------- --------- --------- /// --------- --------- --------- --------- --------- /// Value | 1 | | 0 | | 1 | | 0 | | 1 | /// --------- --------- --------- --------- --------- /// Output: /// --------- --------- --------- --------- --------- /// Tx,Rx CBs | USER_DEF| | NULL_PTR| | USER_DEF| | NULL_PTR| | USER_DEF| /// --------- --------- --------- --------- --------- /// Elements : 3 /// /// \param ucDev /// /// \return STATIC_AL boolean //----------------------------------------------------------------------------- STATIC_AL boolean CddSpi_SetDynamicCfg(uint8 ucDev) { boolean boRetVal = TRUE; if (CddSpi_asDevDynCfg[ucDev].fpDevDynCfgCb != NULL_PTR) { uint16 unElemFootPrint = 0U; if (CddSpi_asDevDynCfg[ucDev].fpDevDynCfgCb(&unElemFootPrint) != FALSE) { uint8 ucElemtsCnt = 0U; for (uint8 ucElemIdx = 0U; ucElemIdx < CddSpi_asDeviceCfg[ucDev].ucMaxElements; ucElemIdx++) { if ((unElemFootPrint & (uint16)1U) == (uint16)0U) { #ifdef CDDSPI_CYCLIC_OPERATION CddSpi_UnSetDevCb(ucDev, ucElemIdx); #endif } else { ucElemtsCnt++; } unElemFootPrint >>= 1U; } //Update Number of element of the device CddSpi_asDeviceCfg[ucDev].ucElements = ucElemtsCnt; } else { boRetVal = FALSE; } } return boRetVal; } #endif //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param ucIdx /// /// \return void //----------------------------------------------------------------------------- #ifdef CDDSPI_CYCLIC_OPERATION STATIC_AL void CddSpi_ProcessSequence(uint8 ucIdx) { tsCddSpiSeqHandler* psSeqHandler = &CddSpi_asSeqHandler[ucIdx]; if (psSeqHandler->unCycleCnt == 0U) { //------------------------------------------ //Process Rx //------------------------------------------ //Process only if there is valid data in Rx buffer if (psSeqHandler->psSeqData->boRxDataValid == TRUE) { for (uint8 ucDevIdx = 0; ucDevIdx < psSeqHandler->psSeqData->ucSize; ucDevIdx++) { CddSpi_ProcessRxCb(&psSeqHandler->psSeqData->psDevData[ucDevIdx]); } } //------------------------------------------ // Process Tx //------------------------------------------ for (uint8 ucDevIdx = 0; ucDevIdx < psSeqHandler->psSeqData->ucSize; ucDevIdx++) { //Configure Transmission Parameters CddSpi_ConfigureTransfer_Deriv(&CddSpi_asDeviceCfg[psSeqHandler->psSeqData->psDevData[ucDevIdx].eDev]); //Process Tx Callbacks CddSpi_ProcessTxCb(&psSeqHandler->psSeqData->psDevData[ucDevIdx]); //If there is more than one device attached to the SPI interface //wait until transmission is complete. if (psSeqHandler->psSeqData->ucSize > 1U) { //Temporary software timer, use GPT instead uint32 ulTimer = CDDSPI_TIMEOUT_VAL; //Get actual entries of Rx Fifo uint8 ucRxEntries = (uint8)CddSpi_RxFifoGetEntries_Deriv(CddSpi_asDeviceCfg[psSeqHandler->psSeqData->psDevData[ucDevIdx].eDev].ucSpiIfc); //Add entries to be transmited ucRxEntries += CddSpi_asDeviceCfg[psSeqHandler->psSeqData->psDevData[ucDevIdx].eDev].ucElements; //Wait until entries get recieved or timeout is elapsed while ((CddSpi_TransferComplete_Deriv(CddSpi_asDeviceCfg[psSeqHandler->psSeqData->psDevData[ucDevIdx].eDev].ucSpiIfc, ucRxEntries) == FALSE) && (ulTimer > 0U)) { ulTimer--; } } } //Set Rx data valid flag psSeqHandler->psSeqData->boRxDataValid = TRUE; //Set sequence index to configured prescaler psSeqHandler->unCycleCnt = psSeqHandler->unPrescaler; } else { //Decrement sequence index, period is still not elapsed psSeqHandler->unCycleCnt--; } } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param psDevSeqData /// /// \return STATIC_AL void //----------------------------------------------------------------------------- STATIC_AL void CddSpi_ProcessRxCb(const tsCddSpiDevSeqData* psDevSeqData) { for (uint8 ucIdx = 0U; ucIdx < CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements; ucIdx++) { uint8 ucCbIdx = CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements - ucIdx - 1U; if (psDevSeqData->psDevCbData[ucCbIdx].sDevCb.fpRx != NULL_PTR) { //Get data from HW-Fifo uint32 ulData = CddSpi_RxFifoGet_Deriv(CddSpi_asDeviceCfg[psDevSeqData->eDev].ucSpiIfc); //Put data in HW-Fifo psDevSeqData->psDevCbData[ucCbIdx].sDevCb.fpRx(psDevSeqData->psDevCbData[ucCbIdx].unCbId, ulData); } } } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param psDevSeqData /// /// \return STATIC_AL void //----------------------------------------------------------------------------- STATIC_AL void CddSpi_ProcessTxCb(const tsCddSpiDevSeqData* psDevSeqData) { #ifdef CDDSPI_DEBUG static uint16 aucAuxBuff[CDDSPI_AUX_BUFF_SIZE] = { 0 }; #endif for (uint8 ucIdx = 0U; ucIdx < CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements; ucIdx++) { uint8 ucCbIdx = CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements - ucIdx - 1U; if (psDevSeqData->psDevCbData[ucCbIdx].sDevCb.fpTx != NULL_PTR) { #ifdef CDDSPI_DEBUG aucAuxBuff[ucCbIdx] = psDevSeqData->psDevCbData[ucCbIdx].sDevCb.fpTx(psDevSeqData->psDevCbData[ucCbIdx].unCbId); #else //Get data from Tx-Callback uint32 ulData = psDevSeqData->psDevCbData[ucCbIdx].sDevCb.fpTx(psDevSeqData->psDevCbData[ucCbIdx].unCbId); //Provide data to Rx-Callback CddSpi_TxFifoPut_Deriv(CddSpi_asDeviceCfg[psDevSeqData->eDev].ucSpiIfc, ulData); #endif } } #ifdef CDDSPI_DEBUG for (uint8 ucIdx = 0U; ucIdx < CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements; ucIdx++) { uint8 ucCbIdx = CddSpi_asDeviceCfg[psDevSeqData->eDev].ucMaxElements - ucIdx - 1U; CddSpi_TxFifoPut_Deriv(CddSpi_asDeviceCfg[psDevSeqData->eDev].ucSpiIfc, aucAuxBuff[ucCbIdx]); } #endif } //----------------------------------------------------------------------------- /// \brief /// /// \descr /// /// \param ucDev /// \param ucCbIdx /// /// \return STATIC_AL void //----------------------------------------------------------------------------- #ifdef CDDSPI_DYNAMIC_CFG STATIC_AL void CddSpi_UnSetDevCb(uint8 ucDev, uint8 ucCbIdx) { for (uint8 ucSeqIdx = 0; ucSeqIdx < (uint8)CddSpi_eSeq_Count; ucSeqIdx++) { tsCddSpiSeqHandler* psSeqHandler = &CddSpi_asSeqHandler[ucSeqIdx]; //Only check Ifc Seq that the Dev is attached to if (CddSpi_aucIfcMap[psSeqHandler->eSpiIfc] == CddSpi_asDeviceCfg[ucDev].ucSpiIfc) { for (uint8 ucDevIdx = 0; ucDevIdx < psSeqHandler->psSeqData->ucSize; ucDevIdx++) { //No break due to device could be registered more than once in a sequence. Mac needs to be reworked if ((uint8)psSeqHandler->psSeqData->psDevData->eDev == ucDev) { CddSpi_asSeqData[ucSeqIdx].psDevData[ucDevIdx].psDevCbData[ucCbIdx].sDevCb.fpTx = NULL_PTR; CddSpi_asSeqData[ucSeqIdx].psDevData[ucDevIdx].psDevCbData[ucCbIdx].sDevCb.fpRx = NULL_PTR; } } break; } } } #endif #endif