/* * codrv_mcan - driver for mcan * * Copyright (c) 2017-2020 emotas embedded communication GmbH *------------------------------------------------------------------- * SVN $Id: codrv_mcan.c 51556 2023-12-18 09:35:01Z ro $ * * *------------------------------------------------------------------- * * */ /* Functionality Singleline: - extended and standard id - rtr - software auto bus on - CAN-FD ISO - id filter - id group filter */ /***************************************************************************/ /** * \file * \brief mCAN CAN driver (e.g. STM32, LPC, Atmel) * * * * Note: This settings should be part of gen_define.h! * */ /* #define CO_DRV_FILTER 1 */ /* #define CO_DRV_GROUP_FILTER 1 */ /* header of standard C - libraries ---------------------------------------------------------------------------*/ #include #include #include /* header of project specific types ---------------------------------------------------------------------------*/ #include #include #include #include #include #include "codrv_mcan.h" /* constant definitions ---------------------------------------------------------------------------*/ /* * Below is the message RAM setting, it will be stored in the system RAM. * Please adjust the message size according to your application. */ #if defined(CODRV_MCAN_STM32_L5) || defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) || defined(CODRV_MCAN_STM32_U5) || defined(CODRV_MCAN_STM32_H5) # define CODRV_MCAN_FIXED_MSG_RAM 1u # define CODRV_MCAN_FILTER_STD_SIZE 28u # define CODRV_MCAN_FILTER_EXT_SIZE 8u # define CODRV_MCAN_RXFIFO_SIZE 3u # define CODRV_MCAN_ELEMENT_DATA_SIZE 64u # define CODRV_MCAN_TXBUFFER_SIZE 3u # define CODRV_RX0L_IR_POS 2u #endif /* defined(CODRV_MCAN_STM32_L5) || defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) || defined(CODRV_MCAN_STM32_U5) || defined(CODRV_MCAN_STM32_H5) */ /* The value should be 8/12/16/20/24/32/48/64. */ # ifndef CODRV_MCAN_ELEMENT_DATA_SIZE # define CODRV_MCAN_ELEMENT_DATA_SIZE 8u # define CODRV_MCAN_ELEMENT_SIZE_CODE 0u # endif /*CODRV_MCAN_ELEMENT_DATA_SIZE*/ /** * \define CODRV_MCAN_RXFIFO_SIZE * Number of rx fifo elements */ #ifndef CODRV_MCAN_RXFIFO_SIZE # define CODRV_MCAN_RXFIFO_SIZE (10u) #endif /* CODRV_MCAN_RXFIFO_SIZE */ /** * \define CODRV_RX0L_IR_POS * RX-fifo message lost flag position */ #ifndef CODRV_RX0L_IR_POS # define CODRV_RX0L_IR_POS 3u #endif /* CODRV_RX0L_IR_POS */ /** * \define CODRV_MCAN_TXBUFFER_SIZE * Number of tx buffer elements */ #ifndef CODRV_MCAN_TXBUFFER_SIZE # define CODRV_MCAN_TXBUFFER_SIZE 1u #endif /* CODRV_MCAN_TXBUFFER_SIZE */ /** * \define CODRV_MCAN_FILTER_STD_SIZE * Number of std id filter elements */ #ifndef CODRV_MCAN_FILTER_STD_SIZE # ifdef CO_DRV_FILTER # define CODRV_MCAN_FILTER_STD_SIZE (28u) # else /* CO_DRV_FILTER */ # define CODRV_MCAN_FILTER_STD_SIZE 0u # endif /* CO_DRV_FILTER */ #endif /* CODRV_MCAN_FILTER_STD_SIZE */ /** * \define CODRV_MCAN_FILTER_EXT_SIZE * Number of ext id filter elements */ #ifndef CODRV_MCAN_FILTER_EXT_SIZE # ifdef CO_DRV_FILTER # define CODRV_MCAN_FILTER_EXT_SIZE (28u) # else /* CO_DRV_FILTER */ # define CODRV_MCAN_FILTER_EXT_SIZE 0u # endif /* CO_DRV_FILTER */ #endif /* CODRV_MCAN_FILTER_EXT_SIZE */ #define MCAN_SIDF_SIZE 4u /* standard id filter */ #define MCAN_XIDF_SIZE 8u /* extended id filter */ #define MCAN_RXF0_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* rx fifo 0 */ #define MCAN_RXB_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* rx buffer */ #define MCAN_TXE_SIZE 8u /* tx event */ #define MCAN_TXB_SIZE (MCAN_XIDF_SIZE + CODRV_MCAN_ELEMENT_DATA_SIZE) /* tx buffer */ /** * \define CODRV_DEBUG * UART Debug output */ /* #define CODRV_DEBUG 1 */ /** * \define POLLING * work without interrupts * !! Seldom tested - support is not guaranteed !! */ /* #define POLLING 1 */ /* OS related macros - default definition */ #ifdef CO_OS_SIGNAL_CAN_TRANSMIT #else # define CO_OS_SIGNAL_CAN_TRANSMIT #endif #ifdef CO_OS_SIGNAL_CAN_RECEIVE #else # define CO_OS_SIGNAL_CAN_RECEIVE #endif /* local defined data types ---------------------------------------------------------------------------*/ typedef struct { UNSIGNED32 id; UNSIGNED32 ctrl; UNSIGNED8 data[CODRV_MCAN_ELEMENT_DATA_SIZE]; }MCAN_FIFO_ELEMENT_T; typedef struct { UNSIGNED32 F0; UNSIGNED32 F1; }MCAN_EXT_FILTER_ELEMENT_T; typedef struct { #if defined(CO_DRV_FILTER) || defined(CODRV_MCAN_FIXED_MSG_RAM) UNSIGNED32 stdIdFilter[CODRV_MCAN_FILTER_STD_SIZE]; MCAN_EXT_FILTER_ELEMENT_T extIdFilter[CODRV_MCAN_FILTER_EXT_SIZE]; #endif /* CO_DRV_FILTER || CODRV_MCAN_FIXED_MSG_RAM */ MCAN_FIFO_ELEMENT_T rxFifo[CODRV_MCAN_RXFIFO_SIZE]; #ifdef CODRV_MCAN_FIXED_MSG_RAM MCAN_FIFO_ELEMENT_T rxFifo2[CODRV_MCAN_RXFIFO_SIZE]; UNSIGNED8 eventfifo[8 * 3]; #endif /* CODRV_MCAN_FIXED_MSG_RAM */ MCAN_FIFO_ELEMENT_T txBuf[CODRV_MCAN_TXBUFFER_SIZE]; } MCAN_MSGRAM_T; /* list of external used functions, if not in headers ---------------------------------------------------------------------------*/ /* list of global defined functions ---------------------------------------------------------------------------*/ #ifdef CODRV_DEBUG # ifdef CO_DRV_FILTER void printFilter(void); # endif /* CO_DRV_FILTER */ #endif /* CODRV_DEBUG */ /* list of local defined functions ---------------------------------------------------------------------------*/ static RET_T codrvCanInitController(UNSIGNED16 nomBitrate, UNSIGNED16 datBitrate); static RET_T codrvCanTransmit(CO_CONST CO_CAN_TR_MSG_T * pBuf); static CO_CONST CODRV_BTR_T * codrvCanGetBtrSettings(UNSIGNED16 bitRate); static void codrvCanResetRam(void); #ifdef CO_DRV_FILTER # ifdef CO_DRV_GROUP_FILTER static BOOL_T codrvCanCheckGroupFilter(CO_CONST CO_CAN_COB_T * CO_CONST pCob); # endif /* CO_DRV_GROUP_FILTER */ static RET_T codrvCanEnableExtIdFilter(CO_CAN_COB_T * CO_CONST pCob); static RET_T codrvCanEnableStdIdFilter(CO_CAN_COB_T * CO_CONST pCob); static RET_T codrvCanDisableExtIdFilter(CO_CAN_COB_T * CO_CONST pCob); static RET_T codrvCanDisableStdIdFilter(CO_CAN_COB_T * CO_CONST pCob); #endif #ifdef CODRV_AUTOBAUD RET_T codrvAutoBaudNextBitrate(void); UNSIGNED16 codrvAutoBaudGetActualBitrate(void); #endif /* CODRV_AUTOBAUD */ /* external variables ---------------------------------------------------------------------------*/ /* global variables ---------------------------------------------------------------------------*/ /* local defined variables ---------------------------------------------------------------------------*/ static BOOL_T canEnabled = { CO_FALSE }; static volatile BOOL_T transmissionIsActive = { CO_FALSE }; static UNSIGNED32 oldEsrValue; /** currently TX message buffer */ static CO_CAN_TR_MSG_T *pTxBuf = { NULL }; /** CAN Controller address */ #ifdef CODRV_MCAN_STM32_H7 # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A000ul) # define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4000A400ul) #endif /* CODRV_MCAN_STM32_H7 */ #ifdef CODRV_MCAN_STM32_MP1 # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4400E000ul) # define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4400F000ul) #endif /* CODRV_MCAN_STM32_MP1 */ #if defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x40006400ul) # define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x40006800ul) # if defined(CODRV_MCAN_STM32_G4) # define CODRV_MCAN2_ADDR ((CODRV_MCANFD_T*)0x40006C00ul) # endif /* defined(CODRV_MCAN_STM32_G4) */ #endif /* defined(CODRV_MCAN_STM32_G0) || defined(CODRV_MCAN_STM32_G4) */ /* STM32L5 - only CPUs with 1 FDCAN out at the moment! */ #if defined(CODRV_MCAN_STM32_L5) # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul) #endif /* defined(CODRV_MCAN_STM32_L5) */ /* STM32U5 - only CPUs with 1 FDCAN out at the moment! */ #if defined(CODRV_MCAN_STM32_U5) # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul) #endif /* defined(CODRV_MCAN_STM32_U5) */ #ifdef CODRV_MCAN_STM32_H5 # define CODRV_MCAN0_ADDR ((CODRV_MCANFD_T*)0x4000A400ul) # define CODRV_MCAN1_ADDR ((CODRV_MCANFD_T*)0x4000A800ul) #endif /* CODRV_MCAN_STM32_MP1 */ #ifndef CODRV_MCAN0_ADDR # error select MCAN configuration first! #endif /* CODRV_MCAN0_ADDR */ /** \var pCan - used CAN controller address */ # ifdef CONFIG_MCAN0 static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN0_ADDR; /*lint !e923 CAN controller address */ # endif /* CONFIG_MCAN0 */ # ifdef CONFIG_MCAN1 static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN1_ADDR; /*lint !e923 CAN controller address */ # endif /* CONFIG_MCAN1 */ # ifdef CONFIG_MCAN2 static volatile CODRV_MCANFD_T * const pCan = CODRV_MCAN2_ADDR; /*lint !e923 CAN controller address */ # endif /* CONFIG_MCAN2 */ /** CAN message RAM address */ #define CODRV_MCAN_STATIC_MSG_RAM # ifdef CONFIG_MCAN0 static const UNSIGNED8 mcanMsgRamOffs = 0u; # endif /* CONFIG_MCAN0 */ # ifdef CONFIG_MCAN1 static const UNSIGNED8 mcanMsgRamOffs = 1u; # endif /* CONFIG_MCAN1 */ # ifdef CONFIG_MCAN2 static const UNSIGNED8 mcanMsgRamOffs = 2u; # endif /* CONFIG_MCAN2 */ #ifdef CODRV_MCAN_STATIC_MSG_RAM # ifdef CODRV_MCAN_STM32_H7 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u); # endif /* CODRV_MCAN_STM32_H7 */ # ifdef CODRV_MCAN_STM32_MP1 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x44011000u); # endif /* CODRV_MCAN_STM32_MP1 */ # ifdef CODRV_MCAN_STM32_G0 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000B400u); # endif /* CODRV_MCAN_STM32_G0 */ # ifdef CODRV_MCAN_STM32_G4 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000A400u); # endif /* CODRV_MCAN_STM32_G4 */ # ifdef CODRV_MCAN_STM32_L5 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u); # endif /* CODRV_MCAN_STM32_L5 */ # ifdef CODRV_MCAN_STM32_U5 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u); # endif /* CODRV_MCAN_STM32_U5 */ # ifdef CODRV_MCAN_STM32_H5 static volatile MCAN_MSGRAM_T * const pMcanMsgRam = (MCAN_MSGRAM_T*)(0x4000AC00u); # endif /* CODRV_MCAN_STM32_U5 */ # else /* CODRV_MCAN_STATIC_MSG_RAM */ static volatile MCAN_MSGRAM_T mcanMsgRam __attribute__((section(".MCAN_SECTION"))); static volatile MCAN_MSGRAM_T * volatile pMcanMsgRam = &mcanMsgRam; # ifdef CONFIG_MCAN0 static volatile UNSIGNED32* pMcanMRBA = (UNSIGNED32 *)0x4009D200ul; # endif /* CONFIG_MCAN0 */ # ifdef CONFIG_MCAN1 static volatile UNSIGNED32* pMcanMRBA = (UNSIGNED32 *)0x4009e200ul; # endif /* CONFIG_MCAN1 */ #endif /* CODRV_MCAN_STATIC_MSG_RAM */ #ifdef CODRV_BIT_TABLE_EXTERN extern CO_CONST CODRV_BTR_T codrvCanBittimingTable[]; #else /* CODRV_BIT_TABLE_EXTERN */ /** CAN bittiming table */ static CO_CONST CODRV_BTR_T codrvCanBittimingTable[] = { # ifdef CODRV_CANCLOCK_PRE_10BIT /* 80MHz table */ { 10u, 500u, 0u, 13u, 2u }, /* 87.5% */ { 20u, 250u, 0u, 13u, 2u }, /* 87.5% */ { 50u, 100u, 0u, 13u, 2u }, /* 87.5% */ # endif /* CODRV_CANCLOCK_PRE_10BIT */ { 100u, 50u, 0u, 13u, 2u }, /* 87.5% */ { 125u, 40u, 0u, 13u, 2u }, /* 87.5% */ { 250u, 20u, 0u, 13u, 2u }, /* 87.5% */ { 500u, 10u, 0u, 13u, 2u }, /* 87.5% */ { 800u, 10u, 0u, 8u, 1u }, /* 90.0% */ { 1000u, 5u, 0u, 13u, 2u }, /* 87.5% */ { 0u, 0u, 0u, 0u, 0u } /* last */ }; #endif /* CODRV_BIT_TABLE_EXTERN */ #ifdef CODRV_AUTOBAUD static UNSIGNED16 autoBaudBitRateIdx = { 0u }; static UNSIGNED8 autoBaudActive = { 0u }; #endif /* CODRV_AUTOBAUD */ /*---------------------------------------------------------------------------*/ /* #define DEBUG_SEND_TESTMESSAGE */ #ifdef DEBUG_SEND_TESTMESSAGE static void codrvSendTestMessage( void /* no parameter */ ) { MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); pRam->txBuf[0].id = (0x555 << 18u); pRam->txBuf[0].ctrl = (9u << 16u);/* | (3u << 20u)*/; pRam->txBuf[0].data[0] = 0x01; pRam->txBuf[0].data[7] = 0x08; pCan->TXBTIE = 0x01; pCan->TXBAR = 0x01; } #endif /* DEBUG_SEND_TESTMESSAGE */ /*---------------------------------------------------------------------------*/ /***************************************************************************/ /** * \brief codrvCanInit - init CAN controller * * This Function inits the CAN controller and setup the bitrate * After that, the CAN controller is disabled. * * \param * bitrate - CANopen bitrate * \results * RET_T */ RET_T codrvCanInit( UNSIGNED16 bitRate /**< Bitrate */ ) { RET_T retVal; /* clear the FD RAM */ codrvCanResetRam(); #ifdef CO_DRV_FILTER /* start of ID filter */ #endif /* CO_DRV_FILTER */ retVal = codrvCanInitController(bitRate, 0u); return(retVal); } /***************************************************************************/ /** * \brief codrvCanReInit - reinit CAN controller * * This Function reinits the CAN controller after deactivation. * * In Filter mode: After this function call all Filter are reset and must * be reconfigured! * * At the end of the function, the CAN controller should be in state disabled. * * \param * bitrate - CANopen bitrate * \results * RET_T */ RET_T codrvCanReInit( UNSIGNED16 bitRate /**< Bitrate */ ) { RET_T retVal; retVal = codrvCanInitController(bitRate,0u); return(retVal); } /***************************************************************************/ /** * \brief codrvCanInitController - init CAN controller * * \internal * * This Function inits the CAN controller and setup the bitrate * After that, the CAN controller is disabled. * * \param * bitrate - CANopen bitrate * \results * RET_T */ static RET_T codrvCanInitController( UNSIGNED16 nomBitrate, UNSIGNED16 datBitrate ) { RET_T retVal = RET_OK; #ifdef CODRV_MCAN_FIXED_MSG_RAM #else /* CODRV_MCAN_FIXED_MSG_RAM */ UNSIGNED32 ramOffset = (sizeof(MCAN_MSGRAM_T) * mcanMsgRamOffs); #endif /* CODRV_MCAN_FIXED_MSG_RAM */ /* exit from sleep mode */ pCan->CCCR &= ~MCAN_CCCR_BIT_CSR; /* wait for sleep mode acknowledge */ while((pCan->CCCR & MCAN_CCCR_BIT_CSA) == MCAN_CCCR_BIT_CSA) { ; } /* Request initialization */ pCan->CCCR |= MCAN_CCCR_BIT_INIT; while((pCan->CCCR & MCAN_CCCR_BIT_INIT) != MCAN_CCCR_BIT_INIT) { ; } /* Enable configuration change */ pCan->CCCR |= MCAN_CCCR_BIT_CCE; while((pCan->CCCR & MCAN_CCCR_BIT_CCE) != MCAN_CCCR_BIT_CCE) { ; } /* set the ram address for message ram */ #ifdef CODRV_MCAN_STATIC_MSG_RAM #else /* CODRV_MCAN_STATIC_MSG_RAM */ *pMcanMRBA = (UNSIGNED32)pMcanMsgRam; #endif /* CODRV_MCAN_STATIC_MSG_RAM */ /* setup filter */ #ifdef CODRV_MCAN_FIXED_MSG_RAM #else /* CODRV_MCAN_FIXED_MSG_RAM */ pCan->SIDFC = ((UNSIGNED32)CODRV_MCAN_FILTER_STD_SIZE << 16u) | ramOffset; ramOffset += MCAN_SIDF_SIZE * CODRV_MCAN_FILTER_STD_SIZE; pCan->XIDFC = ((UNSIGNED32)CODRV_MCAN_FILTER_EXT_SIZE << 16u) | ramOffset; ramOffset += MCAN_XIDF_SIZE * CODRV_MCAN_FILTER_EXT_SIZE; /* RX Buffer/FIFO Element Size 64 bytes data field */ pCan->RXESC |= (UNSIGNED32)CODRV_MCAN_ELEMENT_SIZE_CODE; /* RX Buffer/FIFO configuration */ pCan->RXF0C = ((UNSIGNED32)CODRV_MCAN_RXFIFO_SIZE << 16u) | ramOffset; ramOffset += CODRV_MCAN_RXFIFO_SIZE * MCAN_RXF0_SIZE; #endif /* CODRV_MCAN_FIXED_MSG_RAM */ #ifdef CO_DRV_FILTER /* the GFC register differs if the message ram is fixed or not. This has to be checked if new STM32 derivatives are released, that this is still the case! */ # ifdef CODRV_MCAN_FIXED_MSG_RAM pCan->GFC = (UNSIGNED32)(0x3c | (CODRV_MCAN_FILTER_EXT_SIZE << 24) | (CODRV_MCAN_FILTER_STD_SIZE << 16)) ; # else /* CODRV_MCAN_FIXED_MSG_RAM */ pCan->GFC = (UNSIGNED32)0x3c; # endif /* CODRV_MCAN_FIXED_MSG_RAM */ #else /* CO_DRV_FILTER */ /* Accept Non-matching Frames Into FIFO 0 */ pCan->GFC = (UNSIGNED32)0x0; #endif /* CO_DRV_FILTER */ #ifdef CODRV_MCAN_FIXED_MSG_RAM #else /* CODRV_MCAN_FIXED_MSG_RAM */ /* only support one Tx Buffer currently */ pCan->TXBC = ((UNSIGNED32)1u << 16u) | ramOffset; /* support up to 64 bytes payload */ pCan->TXESC = ((UNSIGNED32)CODRV_MCAN_ELEMENT_SIZE_CODE); #endif /* CODRV_MCAN_FIXED_MSG_RAM */ /* Set the automatic retransmission */ pCan->CCCR &= ~MCAN_CCCR_BIT_DAR; /* init req. variables */ canEnabled = CO_FALSE; transmissionIsActive = CO_FALSE; /* error states */ codrvCanErrorInit(); /* set bitrate */ retVal = codrvCanSetBitRate(nomBitrate); /*lint !e838 initialization for long function */ (void)datBitrate; #ifdef DEBUG_SEND_TESTMESSAGE if (retVal == RET_OK) { codrvCanEnable(); codrvSendTestMessage(); } #endif /* DEBUG_SEND_TESTMESSAGE */ return(retVal); } #ifdef CODRV_AUTOBAUD /***************************************************************************/ /** * * codrvAutoBaudNextBitrate - set next bitrate for autobaud * * \internal * * \returns * RET_T */ RET_T codrvAutoBaudNextBitrate( void /* no parameter */ ) { RET_T retVal; autoBaudBitRateIdx++; if (codrvCanBittimingTable[autoBaudBitRateIdx].bitRate == 0u) { autoBaudBitRateIdx = 0u; } retVal = codrvCanSetBitRate(codrvCanBittimingTable[autoBaudBitRateIdx].bitRate); /*lint !e838 initialization for long function */ return(retVal); } /***********************************************************************/ /** * codrvAutoBaudGetActualBitrate - get actual used bitrate * * This function returns the actual used bitrate. * They haven't be valid. * * * \returns * bitrate */ UNSIGNED16 codrvAutoBaudGetActualBitrate( void /* no parameter */ ) { return(codrvCanBittimingTable[autoBaudBitRateIdx].bitRate); } #endif /* CODRV_AUTOBAUD */ /***************************************************************************/ /** * codrvCanGetBtrSettings - get pointer to the btr value structure * * \internal * * \returns * pointer to an btr table entry */ static CO_CONST CODRV_BTR_T * codrvCanGetBtrSettings( UNSIGNED16 bitRate /**< required bitrate */ ) { CO_CONST CODRV_BTR_T * pBtrEntry = NULL; UNSIGNED8 i = 0u; while (codrvCanBittimingTable[i].bitRate != 0u) { if (codrvCanBittimingTable[i].bitRate == bitRate) { pBtrEntry = &codrvCanBittimingTable[i]; break; } i++; } return(pBtrEntry); } /***************************************************************************/ /** * codrvCanSetBitRate - sets the CAN bit rate * * \internal * * Changing the Bitrate only if the CAN controller is in Reset * * \param * bitRate in kbit/s * \results * RET_T * */ RET_T codrvCanSetBitRate( UNSIGNED16 bitRate /**< bit rate in kbit/s */ ) { CO_CONST CODRV_BTR_T * pBtrEntry; UNSIGNED32 pre; UNSIGNED32 seg1; UNSIGNED32 seg2; /* stop CAN controller */ (void)codrvCanDisable(); pBtrEntry = codrvCanGetBtrSettings(bitRate); if (pBtrEntry == NULL) { /* if bitrate not supported */ return(RET_DRV_WRONG_BITRATE); } /* Enable configuration change */ pCan->CCCR |= MCAN_CCCR_BIT_CCE; while((pCan->CCCR & MCAN_CCCR_BIT_CCE) != MCAN_CCCR_BIT_CCE) { ; } pre = (UNSIGNED32)pBtrEntry->pre; seg1 = (UNSIGNED32)pBtrEntry->seg1 + (UNSIGNED32)pBtrEntry->prop; seg2 = (UNSIGNED32)pBtrEntry->seg2; #ifdef CODRV_AUTOBAUD # warning "autobaud not supported yet" #endif pCan->NBTP = ((UNSIGNED32)(seg2 - 1u) << 25) | /*use same size for sjw as seg2*/\ ((UNSIGNED32)(pre - 1u) << 16) | \ ((UNSIGNED32)(seg1 - 1u) << 8) | \ ((UNSIGNED32)(seg2 - 1u)); return(RET_OK); } /***************************************************************************/ /** * codrvCanEnable - enable CAN controller * * \internal * * \param * none * \results * RET_T */ RET_T codrvCanEnable( void /* no parameter */ ) { pCan->CCCR &= ~MCAN_CCCR_BIT_INIT; /* Error active is later checked */ /* enable interrupts */ codrvCanEnableInterrupt(); /* enable interrupt line 0 */ pCan->ILE = 1u; pCan->IE = MCAN_IE_BIT_RF0NE | MCAN_IE_BIT_TCE | MCAN_IE_BIT_BO | MCAN_IE_BIT_EP; #ifdef CO_DRV_FILTER # ifdef CODRV_DEBUG printFilter(); # endif /* CODRV_DEBUG */ #endif /* CO_DRV_FILTER */ canEnabled = CO_TRUE; oldEsrValue = 0xFFffFFffu; return(RET_OK); } /***************************************************************************/ /** * codrvCanDisable - disable CAN controller * * This function disables the CAN controller. The function waits * for the CAN controller being disabled. Code calling this function * typically expects that after returning the CAN controller is in Init mode. * * But note, the time the CAN controller needs to enter the Init mode * can be as long as the duration of one CAN frame. * * \internal * * \param * none * \results * RET_OK CAN controller is set to be disabled */ RET_T codrvCanDisable( void /* no parameter */ ) { /* disable CAN controller */ pCan->CCCR |= MCAN_CCCR_BIT_INIT; while ((pCan->CCCR & MCAN_CCCR_BIT_INIT) == 0u) { /* 500us on 250kbit/s */ } pCan->ILE = 0u; pCan->IE &= ~MCAN_IE_BIT_RF0NE; pCan->IE &= ~MCAN_IE_BIT_TCE; pCan->IE &= ~MCAN_IE_BIT_BO; pCan->IE &= ~MCAN_IE_BIT_EP; canEnabled = CO_FALSE; return(RET_OK); } #ifdef CO_DRV_FILTER # ifdef CO_DRV_GROUP_FILTER /***********************************************************************/ /** * \brief codrvCheckGroupFilter - check, if the canId part of the group filter * * Depend of some settings the group filter are for the IDs * 0x700..0x77F - Heartbeat * 0x80..0xFF - Emergency (and default Sync) * * \return BOOL_T * \retval CO_TRUE * The ID is part of the group filter. * \retval CO_FALSE * The ID is not part of the group filter. * * * */ static BOOL_T codrvCanCheckGroupFilter( CO_CONST CO_CAN_COB_T * CO_CONST pCob ) { BOOL_T retval; UNSIGNED32 canId = pCob->canId; retval = CO_FALSE; if ((pCob->flags & CO_COBFLAG_RTR) != CO_COBFLAG_RTR) { # ifdef CO_HB_CONSUMER_CNT if ((canId & 0x0780u) == 0x700u) { /* part of the group filter */ retval = CO_TRUE; } # endif /* CO_HB_CONSUMER_CNT */ # ifdef CO_EMCY_CONSUMER_CNT if ((canId & 0x0780u) == 0x80u) { /* part of the group filter */ retval = CO_TRUE; } # endif /* CO_EMCY_CONSUMER_CNT */ } return(retval); } # endif /* CO_DRV_GROUP_FILTER */ /***************************************************************************/ /* codrvCanDisableExtIdFilter -disables an extended filter element * * This function disables an extended filter element from a given cob. The * element number is coded in the upper 8bits of the canChan member. * * \internal * * \results * RET_T */ static RET_T codrvCanDisableExtIdFilter( CO_CAN_COB_T * CO_CONST pCob ) { UNSIGNED16 chan; MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); if ((pCob->canChan & 0xff00) == 0xff00) { /* already disabled */ return(RET_OK); /*lint !e904 function entry check */ } chan = pCob->canChan >> 8u; pRam->extIdFilter[chan].F0 = 0u; pRam->extIdFilter[chan].F1= 0u; pCob->canChan |= 0xff00; return(RET_OK); } /***************************************************************************/ /* codrvCanDisableStdIdFilter -disables an standard filter element * * This function disables an standard filter element from a given cob. The * element number is coded in the lower 8bits of the canChan member. * * \internal * * \results * RET_T */ static RET_T codrvCanDisableStdIdFilter( CO_CAN_COB_T * CO_CONST pCob ) { UNSIGNED16 chan; MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); if ((pCob->canChan & 0x00ff) == 0x00ff) { /* already disabled */ return(RET_OK); /*lint !e904 function entry check */ } chan = pCob->canChan & 0x00ff; pRam->stdIdFilter[chan] = 0x00000000u; pCob->canChan |= 0x00ff; return(RET_OK); } static RET_T codrvCanEnableExtIdFilter( CO_CAN_COB_T * CO_CONST pCob ) { UNSIGNED16 chan; UNSIGNED32 mask; MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); chan = pCob->canChan >> 8u; if (chan == 0xff) { /* search next free entry */ for (chan = 0u; chan < CODRV_MCAN_FILTER_EXT_SIZE; chan++) { if (pRam->extIdFilter[chan].F0 == 0u) { break; } } if (chan == CODRV_MCAN_FILTER_EXT_SIZE) { return(RET_DRV_ERROR); } } pRam->extIdFilter[chan].F0 = pCob->canId & 0x1fffffff; mask = ~(pCob->ignore); mask &= 0x1fffffff; pRam->extIdFilter[chan].F1 = 0x2u << 30u; pRam->extIdFilter[chan].F1 |= mask; /* enable filter */ pRam->extIdFilter[chan].F0 |= 0x20000000; pCob->canChan &= 0x00ff; pCob->canChan |= (chan << 8u); return(RET_OK); } static RET_T codrvCanEnableStdIdFilter( CO_CAN_COB_T * CO_CONST pCob ) { UNSIGNED16 chan; UNSIGNED32 mask; MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); chan = pCob->canChan & 0xff; if (chan == 0xff) { /* search next free entry */ for (chan = 0u; chan < CODRV_MCAN_FILTER_STD_SIZE; chan++) { if (pRam->stdIdFilter[chan] == 0x00000000u) { break; } } if (chan == CODRV_MCAN_FILTER_STD_SIZE) { return(RET_DRV_ERROR); } } pRam->stdIdFilter[chan] = pCob->canId & 0x7ff; pRam->stdIdFilter[chan] <<= 16u; mask = ~(pCob->ignore); mask &= 0x7ff; pRam->stdIdFilter[chan] |= mask; /* enable filter */ pRam->stdIdFilter[chan] |= (1u<<27); pRam->stdIdFilter[chan] |= (2u<<30); pCob->canChan &= 0xff00; pCob->canChan |= chan; return(RET_OK); } /***********************************************************************/ /** * codrvCanSetFilter - activate and configure the receive filter * * Depend of the COB entry's the driver specific filter will * be configured. * * For the bxCan only Base Identifiere are allowed. * * * \retval RET_OK * OK * \retval RET_INVALID_PARAMETER * invalid COB reference * \retval RET_DRV_ERROR * filter cannot be set, e.g. no free entry * */ RET_T codrvCanSetFilter( CO_CAN_COB_T * pCanCob /**< COB reference */ ) { # ifdef CODRV_DEBUG printf("codrvCanSetFilter: 0x%04x rtr: %d enabled: %d\n", pCanCob->canId, (pCanCob->flags & CO_COBFLAG_RTR), (pCanCob->flags & CO_COBFLAG_ENABLED)); # endif /* get a filter entry in case of: * - COB has a filter entry from older setting or * - COB is enabled and * - COB is a Receive Data Frame or * - COB is a Transmit Data Frame, but can be query by RTR */ (void)codrvCanDisableExtIdFilter(pCanCob); (void)codrvCanDisableStdIdFilter(pCanCob); if ((pCanCob->flags & CO_COBFLAG_ENABLED) == CO_COBFLAG_ENABLED) { if ((pCanCob->flags & CO_COBFLAG_EXTENDED) == CO_COBFLAG_EXTENDED) { return(codrvCanEnableExtIdFilter(pCanCob)); } else { return(codrvCanEnableStdIdFilter(pCanCob)); } } # ifdef CODRV_DEBUG printFilter(); # endif return(RET_OK); } #endif /* CO_DRV_FILTER */ /***********************************************************************/ /** * codrvCanStartTransmission - start can transmission if not active * * Transmission of CAN messages should be interrupt driven. * If a message was sent, the Transmit Interrupt is called * and the next message can be transmitted. * To start the transmission of the first message, * this function is called from the stack. * * The easiest way to implement this function is * to trigger the transmit interrupt, * but only if the transmission is not already active. * * \internal * * \return RET_T * */ RET_T codrvCanStartTransmission( void /* no parameter */ ) { RET_T retVal = RET_DRV_BUSY; /* if can is not enabled, return with error */ if (canEnabled != CO_TRUE) { return(RET_DRV_ERROR); /*lint !e904 function entry check */ } if (transmissionIsActive == CO_FALSE) { /* trigger transmit interrupt */ #ifdef POLLING retVal = codrvCanTransmitInterrupt(); #else /* POLLING */ /* enable global interrupt pending bit to call interrupt */ codrvCanSetTxInterrupt(); #endif /* POLLING */ } else { codrvCanDriverHandler(); } return(retVal); } /***************************************************************************/ /* codrvCanTransmit - transmit can message * * This function writes a new message to the CAN controller and transmits it. * Normally called from transmit Interrupt * * \internal * * \results * RET_T */ static RET_T codrvCanTransmit( CO_CONST CO_CAN_TR_MSG_T * pBuf /**< pointer to data */ ) { RET_T retVal = RET_OK; /* currently, general MB 0 */ UNSIGNED32 ctrl; UNSIGNED8 i; MCAN_MSGRAM_T * pRam; pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); /* return if device is not initialized or enabled */ if (canEnabled == CO_FALSE) { return(RET_DRV_ERROR); } /* busy check */ if (pCan->TXBRP != 0ul) { return(RET_DRV_BUSY); /*lint !e904 function entry check */ } ctrl = pBuf->len; if (ctrl > 8u) { ctrl = 8u; } pRam->txBuf[0u].ctrl = (ctrl << 16u); /* extended CAN ID */ if ((pBuf->flags & CO_COBFLAG_EXTENDED) == CO_COBFLAG_EXTENDED) { /* message with 29 bit identifier */ pRam->txBuf[0u].id = pBuf->canId; pRam->txBuf[0u].id |= MCAN_CANID_BIT_XTD; } else { /* message with 11 bit identifier */ pRam->txBuf[0u].id = (pBuf->canId << 18u); } /* remote transmission request */ if ((pBuf->flags & CO_COBFLAG_RTR) == CO_COBFLAG_RTR) { /* message is remote frame */ pRam->txBuf[0u].id |= MCAN_CANID_BIT_RTR; } /* copy message data */ if ((pBuf->flags & CO_COBFLAG_RTR) != CO_COBFLAG_RTR) { for (i = 0u; i < CODRV_MCAN_ELEMENT_DATA_SIZE; i = i + 4u) { *((UNSIGNED32*)&(pRam->txBuf[0u].data[i])) = (UNSIGNED32)pBuf->data[i] | \ ((UNSIGNED32)pBuf->data[i + 1] << 8u) | \ ((UNSIGNED32)pBuf->data[i + 2] << 16u) | \ ((UNSIGNED32)pBuf->data[i + 3] << 24u); } } /* transmit it */ /* currently, general MB 0 */ pCan->TXBAR = 1ul; pCan->TXBTIE = 0x01; transmissionIsActive = CO_TRUE; return(retVal); } /***************************************************************************/ /* codrvCanDriverTransmitInterrupt - can driver transmit interrupt * * \internal * * This function is called, after message was transmitted. * As first, inform stack about message transmission. * Get the next message from the transmit buffer, write it to the CAN controller * and transmit it. * * \param * none * \results * none */ RET_T codrvCanTransmitInterrupt( void /* no parameter */ ) { RET_T retVal = RET_OK; /* reset interrupt request * => currently reset all possible TX IRQ requests * * -> very simple implementation */ if (pCan->TXBRP == 0ul) { transmissionIsActive = CO_FALSE; /* inform stack about transmitted message */ if (pTxBuf != NULL) { coQueueMsgTransmitted(pTxBuf); pTxBuf = NULL; /* signal transmitted message */ CO_OS_SIGNAL_CAN_TRANSMIT } /* get next message from transmit queue */ pTxBuf = coQueueGetNextTransmitMessage(); if (pTxBuf != NULL) { /* and transmit it - CAN message buffer is free */ retVal = codrvCanTransmit(pTxBuf); } /* clear interrupt flag */ pCan->IR = MCAN_IE_BIT_TCE; } else { retVal = RET_DRV_BUSY; } return(retVal); } /*********************************************************************** * codrvCanReceiveInterrupt - can driver receive interrupt * * \internal * * This function is called, if a new message was received * As first get the pointer to the receive buffer * and save the message there. * Then set the buffer as filled and inform the library about new data. * * * \param * none * \results * none */ void codrvCanReceiveInterrupt( void /* no parameter */ ) { UNSIGNED8 *pRecBuf; UNSIGNED8 coFlags; UNSIGNED8 len; UNSIGNED8 mbNr = 0u; UNSIGNED32 id; CAN_ERROR_FLAGS_T * pError; UNSIGNED8 i; MCAN_MSGRAM_T * pRam; #ifdef CO_CAN_TIMESTAMP_SUPPORTED CO_CAN_TIMESTAMP_T timestamp; #endif /* CO_CAN_TIMESTAMP_SUPPORTED */ pRam = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); pCan->IR = MCAN_IE_BIT_RF0NE; if ((pCan->RXF0S & 0x7f) == 0u) { return; } do { /* delete pending interrupt */ pCan->IR = MCAN_IE_BIT_RF0NE; /* initialize COB flag */ coFlags = CO_COBFLAG_NONE; /* currently only Fifo 0 */ mbNr = ((pCan->RXF0S >> 8u) & 0x3f); /* get Identifier */ id = pRam->rxFifo[mbNr].id; /* extended CAN-ID */ if ((id & MCAN_CANID_BIT_XTD) == MCAN_CANID_BIT_XTD) { coFlags |= CO_COBFLAG_EXTENDED; } /* remote transmission request */ if ((id & MCAN_CANID_BIT_RTR) == MCAN_CANID_BIT_RTR) { coFlags |= CO_COBFLAG_RTR; } len = (pRam->rxFifo[mbNr].ctrl >> 16) & 0x0f; /* FD frame */ if (((pRam->rxFifo[mbNr].ctrl >> 21) & 0x01) == 1u) { continue; } else { if (len > 8u) { len = 8u; } } /* save 11/29 bit CAN-ID */ if ((id & MCAN_CANID_BIT_XTD) != MCAN_CANID_BIT_XTD) { /* save 11 bit CAN-ID */ id = (id >> 18u) & 0x7FFul; } else { /* save 29 bit CAN-ID */ id = id & 0x1FFFFFFFul; } #ifdef CO_CAN_TIMESTAMP_SUPPORTED /* get RX timestamp */ timestamp = (UNSIGNED32)(pRam->rxFifo[mbNr].ctrl & 0xffFF); #endif /* CO_CAN_TIMESTAMP_SUPPORTED */ /* get receiveBuffer */ pRecBuf = coQueueGetReceiveBuffer(id, len, coFlags #ifdef CO_CAN_TIMESTAMP_SUPPORTED , timestamp #endif /* CO_CAN_TIMESTAMP_SUPPORTED */ ); if (pRecBuf == NULL) { /* error, no buffer available */ /* release mailbox */ pCan->RXF0A = mbNr; /* signal received message - but there was generated * signals for all older received messages * that are in the buffer */ /* CO_OS_SIGNAL_CAN_RECEIVE */ return; /*lint !e904 no buffer possible */ } /* save message at buffer */ if ((id & MCAN_CANID_BIT_RTR) != MCAN_CANID_BIT_RTR) { for (i = 0u; i < len; i++) { pRecBuf[i] = pRam->rxFifo[mbNr].data[i]; } } if ((pCan->RXF0S & (1u << 25u)) == (1u << 25u)) { pError = codrvCanErrorGetFlags(); pError->canErrorRxOverrun = CO_TRUE; /* reset message lost error */ pCan->IR |= (1u << CODRV_RX0L_IR_POS); } /* release mailbox */ pCan->RXF0A = mbNr; /* set buffer filled */ coQueueReceiveBufferIsFilled(); } while (pCan->RXF0S & 0x7f); /* signal received message */ CO_OS_SIGNAL_CAN_RECEIVE } /*********************************************************************** * codrvCanErrorInterrupt - can driver error interrupt * * \internal * * This function is called, if a error passive or Busoff event * occurs. * * \param * none * \results * none */ void codrvCanErrorInterrupt( void /* no parameter */ ) { if ((pCan->IR & (MCAN_IE_BIT_BO | MCAN_IE_BIT_EP)) != 0u) { CAN_ERROR_FLAGS_T * pError; /* set flag to signal the state change */ pError = codrvCanErrorGetFlags(); if ((pCan->IR & MCAN_IE_BIT_BO) != 0) { pError->canErrorBusoff = CO_TRUE; /* clear init bit to get buss on again */ pCan->CCCR &= ~MCAN_CCCR_BIT_INIT; } else if ((pCan->IR & MCAN_IE_BIT_EP) != 0) { pError->canErrorPassive = CO_TRUE; } else { /* never occur, because the error interrupt is not * calling for this state change */ pError->canErrorActive = CO_TRUE; } /* clear interrupt bit */ pCan->IR = (MCAN_IE_BIT_BO | MCAN_IE_BIT_EP); } } /***************************************************************************/ /** * codrvCanErrorHandler - Error handler * * This function polls the current state of the CAN controller * and checks explicitly all situation that are not signaled * within the interrupts. * * Call outside of interrupts! * Typical call in codrvCanDriverHandler(). */ static void codrvCanErrorHandler( void /* no parameter */ ) { UNSIGNED32 err; UNSIGNED32 change; CAN_ERROR_FLAGS_T * pError; BOOL_T fStartTransmission = CO_FALSE; pError = codrvCanErrorGetFlags(); /* * Error active/passive/busoff check */ err = pCan->PSR; /* check only changes of passive and busoff */ change = err ^ oldEsrValue; change &= ((MCAN_PSR_BIT_BO) | (MCAN_PSR_BIT_EP)); if (change != 0ul) { if ((err & MCAN_PSR_BIT_BO) != 0ul) { /* busoff */ /* canErrorBusoff = CO_TRUE;*/ pError->canNewState = Error_Busoff; /* current state */ } else if ((err & MCAN_PSR_BIT_EP) != 0ul) { /* error passive */ /* canErrorPassive = CO_TRUE; */ pError->canNewState = Error_Passive; /* current state */ } else { /* error active */ /* canErrorActive = CO_TRUE; */ pError->canNewState = Error_Active; /* current state */ } } oldEsrValue = err; /* busoff recovery */ if ((err & MCAN_PSR_BIT_BO) != 0ul) { /* busoff */ pCan->CCCR &= ~MCAN_CCCR_BIT_INIT; } /* more for polling - software interrupt, but TX object was sended */ if (pCan->TXBRP == 0ul) { /* correct possible Errors -> CAN has deactivated the transmission */ transmissionIsActive = CO_FALSE; } if (canEnabled == CO_TRUE) { /* check for stopped transmissions */ if ((transmissionIsActive == CO_FALSE) && (pTxBuf != NULL)) { /* transmission aborted, e.g. busoff, * discard message -> is done within the tx interrupt */ fStartTransmission = CO_TRUE; } } if (fStartTransmission == CO_TRUE) { (void)codrvCanStartTransmission(); /* -> call Interrupt at this point */ } } /***************************************************************************/ /** codrvCanDriverHandler - can driver handler * * \internal * * is cyclically called from stack to get actual CAN state * (BUS_OFF, PASSIVE, ACTIVE) * and return to bus on again after bus off was occurred. * * \param * none * \results * none */ void codrvCanDriverHandler( void /* no parameter */ ) { /* check current state */ codrvCanErrorHandler(); /* * inform the CANopen Stack about state changes */ (void)codrvCanErrorInformStack(); #ifdef POLLING codrvCanReceiveInterrupt(); codrvCanTransmitInterrupt(); #endif /* POLLING */ return; } #ifdef CODRV_DEBUG #include void printFilter(void) { # ifdef CODRV_DEBUG_MAX int i,j; volatile UNSIGNED32 *pCanFilter = pCanFilterAddr; printf("\nFiltersettings:\n"); printf("FINIT %d\n", pCanFilter[BXCAN_CANFMR] & BXCAN_CANFMR_FINIT ); printf("Filter active (0 off 1 on) 0x%08lx\n", pCanFilter[BXCAN_CANFA1R]); printf("Filtermode (0 mask 1 list) 0x%08lx\n", pCanFilter[BXCAN_CANFM1R]); printf("Filterscale (0 16-bit 1 32-bit) 0x%08lx\n", pCanFilter[BXCAN_CANFS1R]); printf("Filter assignm (0 fifo0 1 fifo1) 0x%08lx\n", pCanFilter[BXCAN_CANFFA1R]); printf("\n"); //for(i = 0; i < 14; i++) for(i = 0; i <= 0; i++) { for (j = 1; j <= 2; j++) { printf("\n"); printf("Filterbank %d Register %d\n", i,j ); printf("Adr: 0x%08lx\n", &pCanFilter[BXCAN_CANFIRX(i,j)]); printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] & 0xFFFFul) >> 5 ); if( (pCanFilter[BXCAN_CANFM1R] & (1ul << i)) != 0) { printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] >> (16 + 5) )& 0xFFFFul); } else { printf("Mask 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] >> (16 + 5) )& 0xFFFFul); } } } for(i = 1; i < 14; i++) { if( (pCanFilter[BXCAN_CANFA1R] & (1ul << i)) != 0) { for (j = 1; j <= 2; j++) { printf("\n"); printf("Filterbank %d Register %d Val 0x%08lx\n", i,j, pCanFilter[BXCAN_CANFIRX(i,j)] ); printf(" ID 0x%04x\n", (pCanFilter[BXCAN_CANFIRX(i,j)] & 0xFFFFul) >> 5); printf(" ID 0x%04x\n", ((pCanFilter[BXCAN_CANFIRX(i,j)] >> 16 )& 0xFFFFul) >> 5); } } } # endif } #endif static void codrvCanResetRam( void /* no parameter */ ) { volatile MCAN_MSGRAM_T *pOffset; pOffset = (MCAN_MSGRAM_T *)(pMcanMsgRam + mcanMsgRamOffs); memset((void*)pOffset, 0x00u, sizeof(MCAN_MSGRAM_T)); }