/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2016-2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_debug_console.h" #include "fsl_flexcan.h" #include "board.h" #include "fsl_device_registers.h" #include "fsl_common.h" #include "pin_mux.h" #include "clock_config.h" /******************************************************************************* * Definitions ******************************************************************************/ #define EXAMPLE_CAN CAN0 #define EXAMPLE_CAN_CLKSRC kCLOCK_BusClk #define EXAMPLE_CAN_CLK_FREQ CLOCK_GetFreq(kCLOCK_BusClk) #define RX_MESSAGE_BUFFER_NUM (9) #define TX_MESSAGE_BUFFER_NUM (8) #define USE_CANFD (1) #define USE_IMPROVED_TIMING_CONFIG (1) /* * DWORD_IN_MB DLC BYTES_IN_MB Maximum MBs * 2 8 kFLEXCAN_8BperMB 32 * 4 10 kFLEXCAN_16BperMB 21 * 8 13 kFLEXCAN_32BperMB 12 * 16 15 kFLEXCAN_64BperMB 7 * * Dword in each message buffer, Length of data in bytes, Payload size must align, * and the Message Buffers are limited corresponding to each payload configuration: */ #define DWORD_IN_MB (8) //TODO: adam_test #define DLC (13) //TODO: adam_test #define BYTES_IN_MB kFLEXCAN_32BperMB //TODO: adam_test /* To get most precise baud rate under some circumstances, users need to set quantum which is composed of PSEG1/PSEG2/PROPSEG. Because CAN clock prescaler = source clock/(baud rate * quantum), for e.g. 84M clock and 1M baud rate, the quantum should be .e.g 14=(6+3+1)+4, so prescaler is 6. By default, quantum is set to 10=(3+2+1)+4, because for most platforms e.g. 120M source clock/(1M baud rate * 10) is an integer. Remember users must ensure the calculated prescaler an integer thus to get precise baud rate. */ #define SET_CAN_QUANTUM 0 #define PSEG1 3 #define PSEG2 2 #define PROPSEG 1 #define FPSEG1 3 #define FPSEG2 3 #define FPROPSEG 1 #if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) /* To consider the First valid MB must be used as Reserved TX MB for ERR005829 If RX FIFO enable(RFEN bit in MCE set as 1) and RFFN in CTRL2 is set default zero, the first valid TX MB Number is 8 If RX FIFO enable(RFEN bit in MCE set as 1) and RFFN in CTRL2 is set by other value(0x1~0xF), User should consider detail first valid MB number If RX FIFO disable(RFEN bit in MCE set as 0) , the first valid MB number is zero */ #ifdef RX_MESSAGE_BUFFER_NUM #undef RX_MESSAGE_BUFFER_NUM #define RX_MESSAGE_BUFFER_NUM (10) #endif #ifdef TX_MESSAGE_BUFFER_NUM #undef TX_MESSAGE_BUFFER_NUM #define TX_MESSAGE_BUFFER_NUM (9) #endif #endif #ifndef DEMO_FORCE_CAN_SRC_OSC #define DEMO_FORCE_CAN_SRC_OSC 0 #endif /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ flexcan_handle_t flexcanHandle; volatile bool txComplete = false; volatile bool rxComplete = false; volatile bool wakenUp = false; flexcan_mb_transfer_t txXfer, rxXfer; #if (defined(USE_CANFD) && USE_CANFD) flexcan_fd_frame_t frame; #else flexcan_frame_t frame; #endif uint32_t txIdentifier; uint32_t rxIdentifier; /******************************************************************************* * Code ******************************************************************************/ /*! * @brief FlexCAN Call Back function */ static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData) { switch (status) { case kStatus_FLEXCAN_RxIdle: if (RX_MESSAGE_BUFFER_NUM == result) { rxComplete = true; } break; case kStatus_FLEXCAN_TxIdle: if (TX_MESSAGE_BUFFER_NUM == result) { txComplete = true; } break; case kStatus_FLEXCAN_WakeUp: wakenUp = true; break; default: break; } } /*! * @brief Main function */ int main(void) { flexcan_config_t flexcanConfig; flexcan_rx_mb_config_t mbConfig; /* Initialize board hardware. */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); PRINTF("********* FLEXCAN Interrupt EXAMPLE *********\r\n"); txIdentifier = 0x321; rxIdentifier = 0x321; /* Get FlexCAN module default Configuration. */ /* * flexcanConfig.clkSrc = kFLEXCAN_ClkSrcOsc; * flexcanConfig.baudRate = 1000000U; * flexcanConfig.baudRateFD = 2000000U; * flexcanConfig.maxMbNum = 16; * flexcanConfig.enableLoopBack = false; * flexcanConfig.enableSelfWakeup = false; * flexcanConfig.enableIndividMask = false; * flexcanConfig.enableDoze = false; * flexcanConfig.timingConfig = timingConfig; */ FLEXCAN_GetDefaultConfig(&flexcanConfig); flexcanConfig.enableLoopBack = true; //TODO: adam_test flexcanConfig.maxMbNum = 12; //TODO: adam_test /* Init FlexCAN module. */ #if (!defined(DEMO_FORCE_CAN_SRC_OSC)) || !DEMO_FORCE_CAN_SRC_OSC #if (!defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)) || !FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri; #else #if defined(CAN_CTRL1_CLKSRC_MASK) if (!FSL_FEATURE_FLEXCAN_INSTANCE_SUPPORT_ENGINE_CLK_SEL_REMOVEn(EXAMPLE_CAN)) { flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri; } #endif #endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */ #endif /* DEMO_FORCE_CAN_SRC_OSC */ /* If special quantum setting is needed, set the timing parameters. */ #if (defined(SET_CAN_QUANTUM) && SET_CAN_QUANTUM) flexcanConfig.timingConfig.phaseSeg1 = PSEG1; flexcanConfig.timingConfig.phaseSeg2 = PSEG2; flexcanConfig.timingConfig.propSeg = PROPSEG; #if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) flexcanConfig.timingConfig.fphaseSeg1 = FPSEG1; flexcanConfig.timingConfig.fphaseSeg2 = FPSEG2; flexcanConfig.timingConfig.fpropSeg = FPROPSEG; #endif #endif #if (defined(USE_IMPROVED_TIMING_CONFIG) && USE_IMPROVED_TIMING_CONFIG) flexcan_timing_config_t timing_config; memset(&timing_config, 0, sizeof(flexcan_timing_config_t)); #if (defined(USE_CANFD) && USE_CANFD) if (FLEXCAN_FDCalculateImprovedTimingValues(flexcanConfig.baudRate, flexcanConfig.baudRateFD, EXAMPLE_CAN_CLK_FREQ, &timing_config)) { /* Update the improved timing configuration*/ memcpy(&(flexcanConfig.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); } else { PRINTF("No found Improved Timing Configuration. Just used default configuration\r\n\r\n"); } #else if (FLEXCAN_CalculateImprovedTimingValues(flexcanConfig.baudRate, EXAMPLE_CAN_CLK_FREQ, &timing_config)) { /* Update the improved timing configuration*/ memcpy(&(flexcanConfig.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); } else { PRINTF("No found Improved Timing Configuration. Just used default configuration\r\n\r\n"); } #endif #endif #if (defined(USE_CANFD) && USE_CANFD) FLEXCAN_FDInit(EXAMPLE_CAN, &flexcanConfig, EXAMPLE_CAN_CLK_FREQ, BYTES_IN_MB, true); #else FLEXCAN_Init(EXAMPLE_CAN, &flexcanConfig, EXAMPLE_CAN_CLK_FREQ); #endif /* Create FlexCAN handle structure and set call back function. */ FLEXCAN_TransferCreateHandle(EXAMPLE_CAN, &flexcanHandle, flexcan_callback, NULL); /* Set Rx Masking mechanism. */ FLEXCAN_SetRxMbGlobalMask(EXAMPLE_CAN, FLEXCAN_RX_MB_STD_MASK(rxIdentifier, 0, 0)); /* Setup Rx Message Buffer. */ mbConfig.format = kFLEXCAN_FrameFormatStandard; mbConfig.type = kFLEXCAN_FrameTypeData; mbConfig.id = FLEXCAN_ID_STD(rxIdentifier); #if (defined(USE_CANFD) && USE_CANFD) FLEXCAN_SetFDRxMbConfig(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &mbConfig, true); #else FLEXCAN_SetRxMbConfig(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &mbConfig, true); #endif /* Setup Tx Message Buffer. */ #if (defined(USE_CANFD) && USE_CANFD) FLEXCAN_SetFDTxMbConfig(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, true); #else FLEXCAN_SetTxMbConfig(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, true); #endif while (1) { GETCHAR(); frame.id = FLEXCAN_ID_STD(txIdentifier); frame.format = kFLEXCAN_FrameFormatStandard; frame.type = kFLEXCAN_FrameTypeData; frame.length = DLC; #if (defined(USE_CANFD) && USE_CANFD) frame.brs = 1; #endif txXfer.mbIdx = TX_MESSAGE_BUFFER_NUM; #if (defined(USE_CANFD) && USE_CANFD) txXfer.framefd = &frame; for(uint8_t i = 0 ; i < 16 ; i++) frame.dataWord[i] = 0x12345678+i; FLEXCAN_TransferFDSendNonBlocking(EXAMPLE_CAN, &flexcanHandle, &txXfer); #else txXfer.frame = &frame; FLEXCAN_TransferSendNonBlocking(EXAMPLE_CAN, &flexcanHandle, &txXfer); #endif while (!txComplete) { }; txComplete = false; for(uint8_t i = 0 ; i < 16 ; i++) frame.dataWord[i] = 0; /* Start receive data through Rx Message Buffer. */ rxXfer.mbIdx = RX_MESSAGE_BUFFER_NUM; #if (defined(USE_CANFD) && USE_CANFD) rxXfer.framefd = &frame; FLEXCAN_TransferFDReceiveNonBlocking(EXAMPLE_CAN, &flexcanHandle, &rxXfer); #else rxXfer.frame = &frame; FLEXCAN_TransferReceiveNonBlocking(EXAMPLE_CAN, &flexcanHandle, &rxXfer); #endif /* Wait until Rx MB full. */ while (!rxComplete) { }; rxComplete = false; PRINTF("Rx MB ID: 0x%3x, Rx MB data: 0x%x, Time stamp: %d\r\n", frame.id >> CAN_ID_STD_SHIFT, frame.dataByte0, frame.timestamp); PRINTF("Press any key to trigger the next transmission!\r\n\r\n"); for(uint8_t i = 0 ; i < 16 ; i++) PRINTF("frame.dataWord[%d] = 0x%x\r\n", i, frame.dataWord[i]); } }