/////////////////////////////////////////////////////////////////////////////////////////////
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_debug_console.h"
#include "fsl_mcan.h"
#include "board.h"
#include "stdlib.h"
#include "pin_mux.h"
#include <stdbool.h>
/*******************************************************************************
* Definitions
******************************************************************************/
//#define USE_CANFD (1U)
/*
* CAN_DATASIZE DLC BYTES_IN_MB
* 8 8 kMCAN_8ByteDatafield
* 12 9 kMCAN_12ByteDatafield
* 16 10 kMCAN_16ByteDatafield
* 20 11 kMCAN_20ByteDatafield
* 24 12 kMCAN_24ByteDatafield
* 32 13 kMCAN_32ByteDatafield
* 48 14 kMCAN_48ByteDatafield
* 64 15 kMCAN_64ByteDatafield
*
* CAN data size (pay load size), DLC and Bytes in Message buffer must align.
*
*/
#define DLC (15)
#define BYTES_IN_MB kMCAN_64ByteDatafield
/* If not define USE_CANFD or define it 0, CAN_DATASIZE should be 8. */
#define CAN_DATASIZE (8U)
/* If user need to auto execute the improved timming configuration. */
//#define USE_IMPROVED_TIMING_CONFIG (10U)
#define EXAMPLE_MCAN_IRQHandler CAN0_IRQ0_IRQHandler
#define EXAMPLE_MCAN_IRQn CAN0_IRQ0_IRQn
#define EXAMPLE_MCAN CAN0
#define MCAN_CLK_FREQ CLOCK_GetMCanClkFreq(0U)
#define STDID_OFFSET (18U)
#define MSG_RAM_BASE 0x20010000U
#define STD_FILTER_OFS 0x0
#define RX_FIFO0_OFS 0x10U
#define TX_BUFFER_OFS 0x20U
mcan_handle_t mcanHandle;
mcan_buffer_transfer_t txXfer;
mcan_fifo_transfer_t rxXfer;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
volatile bool rxComplete = false;
volatile bool txComplete = false;
mcan_rx_buffer_frame_t rxFrame;
mcan_tx_buffer_frame_t txFrame;
uint8_t tx_data[CAN_DATASIZE];
uint8_t rx_data[CAN_DATASIZE];
/*******************************************************************************
* Code
******************************************************************************/
//void CAN0_IRQ0_IRQHandler(void)
//{
// MCAN_ClearStatusFlag(EXAMPLE_MCAN, CAN_IR_RF0N_MASK);
// MCAN_ReadRxFifo(EXAMPLE_MCAN, 0, &rxFrame);
// rxComplete = true;
// /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
// exception return operation might vector to incorrect interrupt */
//#if defined __CORTEX_M && (__CORTEX_M == 4U)
// __DSB();
//#endif
//}
static void mcan_callback(CAN_Type *base, mcan_handle_t *handle, status_t status, uint32_t result, void *userData)
{
switch (status)
{
case kStatus_MCAN_RxFifo0Idle:
{
rxComplete = true;
}
break;
case kStatus_MCAN_TxIdle:
{
txComplete = true;
}
break;
default:
break;
}
// MCAN_TransmitCancelRequest(EXAMPLE_MCAN,0);
}
/*!
* @brief Main function
*/
int main(void)
{
mcan_config_t mcanConfig;
mcan_frame_filter_config_t rxFilter;
mcan_std_filter_element_config_t stdFilter;
mcan_rx_fifo_config_t rxFifo0;
mcan_tx_buffer_config_t txBuffer;
/* Initialize board hardware. */
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
/* Set MCAN clock 180/5=36MHz. */
CLOCK_SetClkDiv(kCLOCK_DivCan0Clk, 5U, true);
BOARD_InitPins();
BOARD_BootClockPLL180M();
BOARD_InitDebugConsole();
PRINTF("\r\n==MCAN loopback functional example -- Start.==\r\n\r\n");
MCAN_GetDefaultConfig(&mcanConfig);
//mcanConfig.enableLoopBackExt = true;
#if (defined(USE_CANFD) && USE_CANFD)
// mcanConfig.enableCanfdNormal = true;
#endif
#if (defined(USE_IMPROVED_TIMING_CONFIG) && USE_IMPROVED_TIMING_CONFIG)
mcan_timing_config_t timing_config;
memset(&timing_config, 0, sizeof(timing_config));
#if (defined(USE_CANFD) && USE_CANFD)
if (MCAN_FDCalculateImprovedTimingValues(mcanConfig.baudRateA, mcanConfig.baudRateD, MCAN_CLK_FREQ, &timing_config))
{
/* Update the improved timing configuration*/
memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
}
else
{
PRINTF("No found Improved Timing Configuration. use default configuration\r\n\r\n");
}
#else
if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, MCAN_CLK_FREQ, &timing_config))
{
/* Update the improved timing configuration*/
memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
}
else
{
PRINTF("No found Improved Timing Configuration. use default configuration\r\n\r\n");
}
#endif
#endif
MCAN_Init(EXAMPLE_MCAN, &mcanConfig, MCAN_CLK_FREQ);
MCAN_TransferCreateHandle(EXAMPLE_MCAN, &mcanHandle, mcan_callback, NULL);
/* Set Message RAM base address and clear to avoid BEU/BEC error. */
MCAN_SetMsgRAMBase(EXAMPLE_MCAN, MSG_RAM_BASE);
uint32_t *p = (uint32_t *)(MSG_RAM_BASE);
memset(p, 0, (8U + CAN_DATASIZE) * sizeof(uint8_t));
/* STD filter config. */
rxFilter.address = STD_FILTER_OFS;
rxFilter.idFormat = kMCAN_FrameIDStandard;
rxFilter.listSize = 1U;
rxFilter.nmFrame = kMCAN_reject0;
rxFilter.remFrame = kMCAN_rejectFrame;
MCAN_SetFilterConfig(EXAMPLE_MCAN, &rxFilter);
stdFilter.sfec = kMCAN_storeinFifo0;
/* Classic filter mode, only filter matching ID. */
stdFilter.sft = kMCAN_classic;
stdFilter.sfid1 = 0x123U;
stdFilter.sfid2 = 0x0U;
MCAN_SetSTDFilterElement(EXAMPLE_MCAN, &rxFilter, &stdFilter, 0);
/* RX fifo0 config. */
rxFifo0.address = RX_FIFO0_OFS;
rxFifo0.elementSize = 1U;
rxFifo0.watermark = 0;
rxFifo0.opmode = kMCAN_FifoBlocking;
rxFifo0.datafieldSize = kMCAN_8ByteDatafield;
#if (defined(USE_CANFD) && USE_CANFD)
rxFifo0.datafieldSize = BYTES_IN_MB;
#endif
MCAN_SetRxFifo0Config(EXAMPLE_MCAN, &rxFifo0);
/* TX buffer config. */
memset(&txBuffer, 0, sizeof(txBuffer));
txBuffer.address = TX_BUFFER_OFS;
txBuffer.dedicatedSize = 1U;
txBuffer.fqSize = 0;
txBuffer.datafieldSize = kMCAN_8ByteDatafield;
// txBuffer.mode = kMCAN_txQueue;
#if (defined(USE_CANFD) && USE_CANFD)
txBuffer.datafieldSize = BYTES_IN_MB;
#endif
MCAN_SetTxBufferConfig(EXAMPLE_MCAN, &txBuffer);
/* Enable RX fifo0 new message interrupt using interrupt line 0. */
// MCAN_EnableInterrupts(EXAMPLE_MCAN, 0, CAN_IE_RF0NE_MASK);
// EnableIRQ(CAN0_IRQ0_IRQn);
/* Enter normal mode. */
MCAN_EnterNormalMode(EXAMPLE_MCAN);
/* Config TX frame data. */
uint8_t cnt = 0;
for (cnt = 0; cnt < CAN_DATASIZE; cnt++)
{
tx_data[cnt] = cnt;
}
txFrame.xtd = kMCAN_FrameIDStandard;
txFrame.rtr = kMCAN_FrameTypeData;
txFrame.fdf = 0;
txFrame.brs = 0;
txFrame.dlc = 8U;
txFrame.id = 0x110U << STDID_OFFSET;
txFrame.data = tx_data;
txFrame.size = CAN_DATASIZE;
#if (defined(USE_CANFD) && USE_CANFD)
txFrame.fdf = 1;
txFrame.brs = 1;
txFrame.dlc = DLC;
#endif
// MCAN_TransferSendBlocking(EXAMPLE_MCAN, 0, &txFrame);
txXfer.frame = &txFrame;
txXfer.bufferIdx = 0;
// while(1){
MCAN_TransferSendNonBlocking(EXAMPLE_MCAN, &mcanHandle, &txXfer);
// }
while (!txComplete){
}
txComplete = false;
rxFrame.size = CAN_DATASIZE;
rxXfer.frame = &rxFrame;
MCAN_TransferReceiveFifoNonBlocking(EXAMPLE_MCAN, 0, &mcanHandle, &rxXfer);
while (!rxComplete)
{
}
// rxFrame.size = CAN_DATASIZE;
// /* After call the API of rMCAN_TransferReceiveFifoNonBlocking success, we can
// * only get a point (rxFrame.data) to the fifo reading entrance.
// * Copy the received frame data from the FIFO by the pointer(rxFrame.data). */
// memcpy(rx_data, rxFrame.data, rxFrame.size);
//
// PRINTF("Received Frame ID: 0x%x\r\n", rxFrame.id >> STDID_OFFSET);
// PRINTF("Received Frame DATA: ");
// cnt = 0;
// while (cnt < rxFrame.size)
// {
// PRINTF("0x%x ", rx_data[cnt++]);
// }
rxComplete = false;
/* After call the API of rMCAN_TransferReceiveFifoNonBlocking success, we can
* only get a point (rxFrame.data) to the fifo reading entrance.
* Copy the received frame data from the FIFO by the pointer(rxFrame.data). */
memcpy(rx_data, rxFrame.data, rxFrame.size);
PRINTF("Received Frame ID: 0x%x\r\n", rxFrame.id >> STDID_OFFSET);
PRINTF("Received Frame DATA: ");
cnt = 0;
while (cnt < rxFrame.size)
{
PRINTF("0x%x ", rx_data[cnt++]);
}
PRINTF("\r\n");
PRINTF("\r\n\r\n==MCAN loopback functional example -- Finish.==\r\n");
while (1)
{
}
}
Question:
I dont not know how to set CAN BUS buadrate to 1MHZ.I use classic CAN.
I have changed the can0 clock frequency to 36 MHZ by use this function “CLOCK_SetClkDiv(kCLOCK_DivCan0Clk, 5U, true);” .
when I set can bus buadrate to 500khz,I find that it worked normal,the configuration is :
void MCAN_GetDefaultConfig(mcan_config_t *config)
{
/* Assertion. */
assert(NULL != config);
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
/* Initialize MCAN Module config struct with default value. */
config->baudRateA = 500000U;
config->baudRateD = 500000U;
config->enableCanfdNormal = false;
config->enableCanfdSwitch = false;
config->enableLoopBackInt = false;
config->enableLoopBackExt = false;
config->enableBusMon = false;
/* Default protocol timing configuration, time quantum is 16. */
config->timingConfig.seg1 = 0x6U;
config->timingConfig.seg2 = 0x3U;
config->timingConfig.rJumpwidth = 0x1U;
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
config->timingConfig.dataseg1 = 0x16U;
config->timingConfig.dataseg2 = 0xBU;
config->timingConfig.datarJumpwidth = 0xAU;
#endif
};
when I set can bus buadrate to 1000khz(1Mhz),unfortunately,something I can not predict has happened,it has send data 13 times by called this function “MCAN_TransferSendNonBlocking(EXAMPLE_MCAN, &mcanHandle, &txXfer);” one time,and the
“”txComplete” always equal to FALSE, the configuration is:
void MCAN_GetDefaultConfig(mcan_config_t *config)
{
/* Assertion. */
assert(NULL != config);
/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));
/* Initialize MCAN Module config struct with default value. */
config->baudRateA = 1000000U;
config->baudRateD = 1000000U;
config->enableCanfdNormal = false;
config->enableCanfdSwitch = false;
config->enableLoopBackInt = false;
config->enableLoopBackExt = false;
config->enableBusMon = false;
/* Default protocol timing configuration, time quantum is 16. */
config->timingConfig.seg1 = 0x6U;
config->timingConfig.seg2 = 0x3U;
config->timingConfig.rJumpwidth = 0x1U;
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
config->timingConfig.dataseg1 = 0x16U;
config->timingConfig.dataseg2 = 0xBU;
config->timingConfig.datarJumpwidth = 0xAU;
#endif
};
I was use LPC54618 and cantest soft to analyse can bus.
This question has confused a few days,I would appreciate it if it could be resolved.
yours yang,
thank you !
已解决! 转到解答。
Hello,
Use MCUXpresso configuration tool can just configure the clock, baud rate as your requirement, then it
generate code automatically , you can compare the code with your code to check whether the code is configured well.
BR
Alice