/* include begin */ #include #include #include "CAN0.h" #include #include "fsl_flexcan.h" #include "fsl_clock.h" #include "FreeRTOS.h" #include "FreeRTOSConfig.h" #include "task.h" #include "fsl_tickless_generic.h" #include "timers.h" #include "portmacro.h" #include "event_groups.h" #include "semphr.h" #include "fsl_debug_console.h" /*Application Headers*/ //#include "headers.h" #include "NXP_App.h" /* include end */ /** define begin **/ #define CAN_CLOCK_SPEED (CLOCK_GetFreq(kCLOCK_Osc0ErClk) / 2 ) #define CAN_CLOCK_SOURCE (kFLEXCAN_ClkSrcOsc) #define CAN_BASE (CAN0) /** define end **/ /* variable begin */ static uint32_t u32CANBaudRate = CAN_DEFAULT_BAUDRATE; /* CAN baudrate */ flexcan_frame_t stRxFrame; /* CAN receive location */ flexcan_handle_t stCanBaseHandle; /* CAN handle */ extern TaskHandle_t CAN_RxHandle; extern TaskHandle_t CAN_AppHandle; /* variable end */ /* prototype begin */ void CAN_vTransferCb(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData); CAN_STAT CAN_enDriverInit(void); CAN_STAT CAN_enDriverSetup(void); CAN_STAT CAN_enTimingValues(uint32_t _baud,flexcan_timing_config_t *_config); CAN_STAT CAN_enTxTransfer(uint8_t *_data,uint8_t _length,uint32_t _addr,uint8_t _format); CAN_STAT CAN_enRxConfig(uint8_t _mask_id,uint32_t _mask,flexcan_rx_mb_config_t *_canrxcondig); void CAN_vFrameProcess(flexcan_frame_t _temp); static uint8_t u8CANBaseState(CAN_Type *base); static inline uint8_t u8CanIdValid(uint32_t _canid, uint8_t _format); static void CAN_vRxBufferInit(void); static uint8_t CAN_u8RxBufferEnque(CAN_PCK _data); static uint8_t CAN_u8RxBufferDeque(CAN_PCK *_data); static bool CAN_bRxBufferFullCheck(void); static bool CAN_bRxBufferAvailableCheck(void); static void CAN_vRxBufferFull(void); static void CAN_vTxBufferInit(void); static uint8_t CAN_u8TxBufferEnque(CAN_PCK _data); static uint8_t CAN_u8TxBufferDeque(CAN_PCK *_data); static bool CAN_bTxBufferFullCheck(void); static bool CAN_bTxBufferAvailableCheck(void); static void CAN_vTxBufferFull(void); CAN_STAT CAN_enSendRxData(void); void CAN_vSendTxResult(CAN_PCK _cands); void CAN_vSendApp(uint8_t *_data,uint8_t _length,uint8_t _type); /* prototype end */ /// // //AT_NONCACHEABLE_SECTION; //EDMA_CreateHandle; // /// /** * @brief: can transfer callback * @para: -- * @notes: refer flexcan_transfer_callback_t * @return: -- */ void CAN_vTransferCb(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData) { switch (status) { case kStatus_FLEXCAN_RxIdle: { static signed long xHPTask = pdFALSE; flexcan_mb_transfer_t set_ref; set_ref.frame = &stRxFrame; set_ref.mbIdx = result; FLEXCAN_TransferReceiveNonBlocking(CAN_BASE,&stCanBaseHandle,&set_ref); break; } case kStatus_FLEXCAN_TxIdle: { /*can tx transfer completed*/ break; } case kStatus_FLEXCAN_TxBusy: { break; } case kStatus_FLEXCAN_TxSwitchToRx: { break; } case kStatus_FLEXCAN_RxBusy: { break; } /*buffer overflow callback*/ case kStatus_FLEXCAN_RxOverflow: { break; } case kStatus_FLEXCAN_RxFifoBusy: { break; } case kStatus_FLEXCAN_ErrorStatus: { break; } default: break; } } /** * @brief: CAN start will set the baud and reinit nxp flexcan stack * @para: -- * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enDriverInit(void) { flexcan_timing_config_t timing_config; memset(&timing_config , 0x00 , sizeof(flexcan_timing_config_t)); flexcan_config_t config = { .baudRate = u32CANBaudRate, \ .clkSrc = CAN_CLOCK_SOURCE, \ .maxMbNum = 32, \ .enableLoopBack = false, \ .enableTimerSync = false, \ .enableSelfWakeup = false, \ .enableIndividMask = true, \ .enableDoze = false, \ } ; if(CAN_OK != CAN_enTimingValues(u32CANBaudRate,&timing_config)) return CAN_FAIL; memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); FLEXCAN_Init(CAN_BASE, &config, CAN_CLOCK_SPEED); return CAN_OK; } /** * @brief: CAN Setup nxp flexcan stack * @para: -- * @notes: CAN tx mb config is set to mb 0 * @return: CAN_STAT */ CAN_STAT CAN_enDriverSetup(void) { FLEXCAN_TransferCreateHandle(CAN_BASE, &stCanBaseHandle, CAN_vTransferCb, NULL); /*Tx mb config*/ FLEXCAN_SetTxMbConfig(CAN_BASE, CAN_TX_MESSAGE_BUFFER_INDEX, true); FLEXCAN_EnableInterrupts(CAN_BASE,kFLEXCAN_BusOffInterruptEnable | kFLEXCAN_ErrorInterruptEnable ); if(kStatus_Success != EnableIRQ(CAN0_MB_IRQn)) { #ifdef DEBUG_CAN0_Error PRINTF("ER: CAN IRQ init fail handler\n"); #endif } return CAN_OK; } /** * @notes: reference: www.bittiming.can-wiki.info, Clock rate = 32MHz */ CAN_STAT CAN_enTimingValues(uint32_t _baud,flexcan_timing_config_t *_config) { if(_config == NULL) return CAN_PERROR; switch (_baud) { case 100000: { /*100kbps*/ _config->preDivider = 20; break; } case 125000: { /*125kbps*/ _config->preDivider = 16; break; } case 250000: { /*250kbps*/ _config->preDivider = 8; break; } case 500000: { /*500kbps*/ _config->preDivider = 4; break; } case 1000000: { /*1Mbps or 1000kbps*/ _config->preDivider = 2; break; } default: { return CAN_FAIL; } } _config->phaseSeg1 = 0x07; _config->phaseSeg2 = 0x01; _config->propSeg = 0x04; _config->rJumpwidth = 1; return CAN_OK; } /** * @brief: Can data send * @para: *_data : u8 pointer to data * _length: data length * _addr : can send addr * _format: 0x00 -> standard * 0x01 -> extended * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enTxTransfer(uint8_t *_data,uint8_t _length,uint32_t _addr,uint8_t _format) { flexcan_frame_t frame; flexcan_mb_transfer_t msg; uint8_t send_data[8]; /* check variable */ if( ((_length > 8) || (_length == 0))) return CAN_PERROR; if( (_format != 0x00) && (_format != 0x01) ) return CAN_PERROR; if(_data == NULL) return CAN_PERROR; /* validate can address */ if(!(u8CanIdValid(_addr,_format))) return CAN_PERROR; memset(send_data,0x00,8); memcpy(send_data,_data,_length); frame.type = kFLEXCAN_FrameTypeData; frame.format = (_format == 0x01) ? kFLEXCAN_FrameFormatExtend : kFLEXCAN_FrameFormatStandard; frame.id = (_format == 0x01) ? FLEXCAN_ID_EXT(_addr) : FLEXCAN_ID_STD(_addr); frame.length = _length; frame.dataWord0 = (CAN_WORD0_DATA_BYTE_0(send_data[0])) | \ (CAN_WORD0_DATA_BYTE_1(send_data[1])) | \ (CAN_WORD0_DATA_BYTE_2(send_data[2])) | \ (CAN_WORD0_DATA_BYTE_3(send_data[3])) ; frame.dataWord1 = (CAN_WORD1_DATA_BYTE_4(send_data[4])) | \ (CAN_WORD1_DATA_BYTE_5(send_data[5])) | \ (CAN_WORD1_DATA_BYTE_6(send_data[6])) | \ (CAN_WORD1_DATA_BYTE_7(send_data[7])); msg.frame = &frame; msg.mbIdx = CAN_TX_MESSAGE_BUFFER_INDEX; if(FLEXCAN_TransferSendNonBlocking(CAN_BASE, &stCanBaseHandle, &msg) != kStatus_Success) return CAN_FAIL; return CAN_OK; } /** * @brief: Set CAN Rx cofig * @para: _mask_id -> serial number different identifier 1 <-> CAN_MAX_RX_FILTERS * _mask -> can filter mask updated with flexcan * _canrxconfig -> can config updated with flexcan * @notes: to test for combination of 11 and 29 bit ids * @return: CAN_STAT */ CAN_STAT CAN_enRxConfig(uint8_t _mask_id,uint32_t _mask,flexcan_rx_mb_config_t *_canrxcondig) { flexcan_mb_transfer_t ref; ref.frame = &stRxFrame; ref.mbIdx = _mask_id; FLEXCAN_SetRxIndividualMask(CAN_BASE, _mask_id, _mask); FLEXCAN_SetRxMbConfig(CAN_BASE, _mask_id, _canrxcondig, true); if(FLEXCAN_TransferReceiveNonBlocking(CAN_BASE,&stCanBaseHandle,&ref) != kStatus_Success) return CAN_FAIL; return CAN_OK; } /** * @brief: inits can module * @para: -- * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enInit(void) { if(CAN_OK != CAN_enDriverInit()) return CAN_FAIL; CAN_enDriverSetup(); /*Flag set*/ u8CanState = 0x01; return CAN_OK; } /** * @brief: CAN Deinit * @para: -- * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enDeInit(void) { FLEXCAN_Deinit(CAN_BASE); return CAN_OK; } /** * @brief: set can baudrate and can init * @para: _baudrate : new can speed * @notes: this will reinitialize CAN, if new baud fails to set, baud will be set to previous baud * @return: -- */ CAN_STAT CAN_enBaudSet(uint32_t _baudrate) { uint32_t temp_baud; uint8_t can_init_stat = 0x00; temp_baud = u32CANBaudRate; u32CANBaudRate = _baudrate; can_init_stat = CAN_enDriverInit(); /*check can init success. If fail,set previous baud*/ if(can_init_stat != CAN_OK) { u32CANBaudRate = temp_baud; return CAN_FAIL; } return CAN_OK; } /** * @brief: Get current CAN baud * @para: -- * @notes: -- * @return: baud rate */ uint32_t CAN_u32BaudGet(void) { return u32CANBaudRate; } /** * @brief: set can tx * @para: _id: can id * _data: pointer to data * _length: data length * _addr: send address * _format: 0x00 -> standard * 0x01 -> extended * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enSetTx(uint32_t _id,uint8_t *_data,uint8_t _length,uint8_t _format) { /*check can base state init or deinit*/ if(!u8CANBaseState(CAN_BASE)) return CAN_FAIL; // if((_format != 0x00) || (_format != 0x01)) // return CAN_PERROR; /*check arg */ if(!u8CanIdValid(_id,_format)) return CAN_PERROR; if(_data == NULL) return CAN_PERROR; if(_length > CAN_DATA_MAX_SIZE) return CAN_PERROR; CAN_PCK temp_canpck; temp_canpck.can_id[0] = (_id >> 24) & 0xFF; temp_canpck.can_id[1] = (_id >> 16) & 0xFF; temp_canpck.can_id[2] = (_id >> 8) & 0xFF; temp_canpck.can_id[3] = _id & 0xFF; temp_canpck.can_data_len = _length; temp_canpck.can_format = _format; memcpy(&temp_canpck.can_data,_data,_length); if(CAN_u8TxBufferEnque(temp_canpck) != 0x01) return CAN_FAIL; /* Set Flag for Tx request*/ xEventGroupSetBits(CAN_AppEvent , EVENT_CAN_TX_REQ); return CAN_OK; } /** * @brief: Set CAN Rx filter parameters * @para: _sno: serial number different identifier 1 <-> CAN_MAX_RX_FILTERS * _mask: can filter mask * _id: can id * _format: 0x00 -> standard * 0x01 -> extended * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enSetRx(uint8_t _sno,uint32_t _mask,uint32_t _id,uint8_t _format) { uint32_t flexcan_mask; flexcan_rx_mb_config_t can_config; /*check can base state init or deinit*/ if(!u8CANBaseState(CAN_BASE)) return CAN_FAIL; if(!u8CanIdValid(_id,_format)) return CAN_PERROR; if(!u8CanIdValid(_mask,_format)) return CAN_PERROR; /*_sno = 0 is set as tx message buffer*/ if((_sno > CAN_MAX_RX_FILTERS) || (_sno == 0)) return CAN_PERROR; /*flexcan mask set based on format*/ if(_format == 0x00) { flexcan_mask = FLEXCAN_RX_MB_STD_MASK(_mask,kFLEXCAN_FrameTypeData,0); } else { flexcan_mask = FLEXCAN_RX_MB_EXT_MASK(_mask,kFLEXCAN_FrameTypeData,0); } can_config.format = (_format == 0x00) ? kFLEXCAN_FrameFormatStandard : kFLEXCAN_FrameFormatExtend; can_config.id = (_format == 0x00) ? FLEXCAN_ID_STD(_id) : FLEXCAN_ID_EXT(_id); can_config.type = kFLEXCAN_FrameTypeData; if(CAN_enRxConfig(_sno,flexcan_mask,&can_config) != CAN_OK) return CAN_FAIL; return CAN_OK; } /** * @brief: Reset CAN rx filter parameters * @para: _sno: serial number different identifier 1 - CAN_MAX_RX_FILTERS * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enResetRx(uint8_t _sno) { /*check can base state init or deinit*/ if(!u8CANBaseState(CAN_BASE)) return CAN_FAIL; if((_sno > CAN_MAX_RX_FILTERS) || (_sno == 0)) return CAN_PERROR; /*NULL to disable*/ FLEXCAN_SetRxMbConfig(CAN_BASE, _sno, NULL , false); return CAN_OK; } /** * @brief: Reset CAN rx filter parameters * @para: _sno: serial number different identifier 1 - CAN_MAX_RX_FILTERS * _mask: pointer to u32 for can filter mask * _id: pointer to u32 for can id * _format: pointer to u8 can id format * @notes: -- * @return: CAN_STAT */ CAN_STAT CAN_enGetRx(uint8_t _sno,uint32_t *_mask,uint32_t *_id,uint8_t *_format) { uint32_t mask,id; /*check can base state init or deinit*/ if(!u8CANBaseState(CAN_BASE)) return CAN_FAIL; if((_sno > CAN_MAX_RX_FILTERS) || (_sno == 0)) return CAN_PERROR; if((_mask == NULL) || (_id == NULL) || (_format == NULL)) return CAN_PERROR; // mask = CAN_BASE->RXIMR[_sno]; // id = CAN_BASE->MB_8B[_sno].ID; // // // *_mask = mask; // *_id = id; // uint32_t cs = CAN_BASE->MB_8B[_sno].CS; // // base->RXIMR[maskIdx] = mask; // // base->MB[mbIdx].ID = config->id; // // if(_format == 0x00) // { // flexcan_mask = FLEXCAN_RX_MB_STD_MASK(_mask,kFLEXCAN_FrameTypeData,0); // } // else // { // flexcan_mask = FLEXCAN_RX_MB_EXT_MASK(_mask,kFLEXCAN_FrameTypeData,0); // } // // /* Activate Rx Message Buffer. */ // cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty); // base->MB[mbIdx].CS = cs_temp; return CAN_OK; } /** * @brief: Process data from buffer and send through UART * send format * @para: -- * @notes: blocking function will send all avail data * @return: CAN_STAT */ CAN_STAT CAN_enSendRxData(void) { CAN_PCK raw_send_data; uint8_t data_pack[13]; return CAN_OK; } /** * @brief: send can tx packet confirmation * @para: _cands: can frame packet * @notes: -- * @return: -- */ void CAN_vSendTxResult(CAN_PCK _cands) { return; } /** * @brief: Get error status and count * @para: _txer -> u8 pointer to tx error * _rxer -> u8 pointer to rx error * _ercount -> Flexcan error flag * @notes: rxer will also include total rx packet missed,total packet missed will be reseted after this * @return: -- */ CAN_STAT CAN_enGetError(uint8_t *_txer,uint8_t *_rxer,uint32_t *_ercount) { uint32_t error_flag; uint8_t txerror,rxerror; /*check can base state init or deinit*/ if(!u8CANBaseState(CAN_BASE)) return CAN_FAIL; FLEXCAN_GetBusErrCount(CAN_BASE,&txerror,&rxerror); error_flag = FLEXCAN_GetStatusFlags(CAN_BASE); rxerror += iMBOverflowCount; /*reset error count*/ iMBOverflowCount = 0; *_txer = txerror; *_rxer = rxerror; *_ercount = error_flag; return CAN_OK; }