LPC546XX的rt-thread CAN驱动改造

本文介绍了rt-thread CAN驱动中发现的发送卡死与数据线断开后的错误,针对这些问题,作者对rt-thread的CAN驱动框架及FSL库进行了针对性的改造,包括发送重试机制和错误中断处理的改进。此外,还展示了如何在初始化程序中增加对CANFD模式的支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、rt-thread的CAN框架参考了很多linux机制,例如completion与workqueue,熟悉rt-thread系统学习linux驱动会很轻松,能写linux驱动的也能写rt-thread驱动。
二、在测试过程中发现rt-thread的CAN驱动天生有缺陷
1、如没有接收端接收CAN数据,发送端会卡死在发送函数
2、CAN数据线断开后,发送程序也会卡死错误中断处理函数
3、rt-thread的CAN只支持普通CAN,让其同时支持CANFD与CAN
三、针对以上问题,对rt-thread的CAN驱动框架及LPC的FSL驱动库进行改造
1、发送3次后,接收方没应答停止重发功能

case kStatus_MCAN_ErrorStatus:
		if( resend_cnt++>=3 ){
			resend_cnt = 0;
			MCAN_TransferAbortSend(can->base, &can->handle, can->send_bufferIdx);
			rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | can->handle.txbufferIdx << 8);
		}
        break;

2、对FSL库的错误中断处理函数进行改造

void MCAN_TransferHandleIRQ(CAN_Type *base, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(handle);

    status_t status = kStatus_MCAN_UnHandled;
    uint32_t result;

    /* Store Current MCAN Module Error and Status. */
    result = base->IR;

//	LOG_E("can ir reg %04x\r\n",result);
    do
    {
        /* Solve Rx FIFO, Tx interrupt. */
        if (result & kMCAN_TxTransmitCompleteFlag)
        {
            status = kStatus_MCAN_TxIdle;
            MCAN_TransferAbortSend(base, handle, handle->txbufferIdx);
        }
        else if (result & kMCAN_RxFifo0NewFlag)
        {
            MCAN_ReadRxFifo(base, 0, handle->rxFifo0FrameBuf);	//modify by ken
            status = kStatus_MCAN_RxFifo0Idle;
            MCAN_TransferAbortReceiveFifo(base, 0, handle);
        }
        else if (result & kMCAN_RxFifo0LostFlag)
        {
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else if (result & kMCAN_RxFifo1NewFlag)
        {
            MCAN_ReadRxFifo(base, 1, handle->rxFifo1FrameBuf);	//modify by ken
            status = kStatus_MCAN_RxFifo1Idle;
            MCAN_TransferAbortReceiveFifo(base, 1, handle);
        }
        else if (result & kMCAN_RxFifo1LostFlag)
        {
            status = kStatus_MCAN_RxFifo1Lost;	//modify by ken  kStatus_MCAN_RxFifo0Lost ?? fsl lib bug
        }
		else if( result & CAN_IR_BO_MASK ){
			status = kStatus_MCAN_BusOffStatus;
		}
		else if( result & kMCAN_TxTransmitProtocolErrorDataFlag ){
			status = kStatus_MCAN_ErrorStatus;
		}
		else if( result & kMCAN_TxTransmitProtocolErrorArbitrationFlag ){
			status = kStatus_MCAN_ErrorStatus;
		}
        else
        {
            ;
        }

        /* Clear resolved Rx FIFO, Tx Buffer IRQ. */
        MCAN_ClearStatusFlag(base, result);

        /* Calling Callback Function if has one. */
        if (handle->callback != NULL)
        {
            handle->callback(base, handle, status, result, handle->userData);
        }

        /* Reset return status */
        status = kStatus_MCAN_UnHandled;

        /* Store Current MCAN Module Error and Status. */
        result = base->IR;
    } while ((0 != MCAN_GetStatusFlag(base, 0xFFFFFFFFU)) ||
             (0 != (result & (kMCAN_ErrorWarningIntFlag | kMCAN_BusOffIntFlag | kMCAN_ErrorPassiveIntFlag))));
}

3、对rt-thread的CAN初始化程序改造,增加CANFD模式

static const struct can_configure config = {
	.baud_rate = CAN125kBaud,
    .msgboxsz = RT_CANMSG_BOX_SZ,
    .sndboxnumber = RT_CANSND_BOX_NUM,
    .mode = RT_CAN_MODE_CANFD,
	.privmode = 0,
    .ticks = 50,
    .sndboxnumber = TX_MB_COUNT,             /* send Mailbox count */
    .msgboxsz = RX_MB_COUNT,        /* RX msg buffer count */
	#ifdef RT_CAN_USING_HDR
    .maxhdr = FILTER_LIST_COUNT,          /* filter count */
	#endif
};

完整代码如下
drv_can.c

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-12-11     zwc          the first version
 *
 */

//#define DRV_DEBUG
#define LOG_TAG             "drv.can"
#include <drv_log.h>
#include "fsl_canfd.h"
#ifdef RT_USING_CAN
#include "drv_can.h"
//#include "rtm.h"

#define RX_MB_COUNT     	(64U)
#define TX_MB_COUNT     	(32U)
#define FILTER_LIST_COUNT	(64U)
#define MSG_RAM_BASE 		0x4000000 			//将CAN通信缓冲放在SRAMx(0x40000000~0x40001200)
#define STD_FILTER_OFS 		0x0U
#define EXT_FILTER_OFS 		0x200U
#define RX_FIFO0_OFS 		0x400U
#define RX_FIFO1_OFS 		0x1600U
#define TX_BUFFER_OFS 		0x3B00U
#define STDID_OFFSET 		(18U)
#define EXTID_OFFSET 		(0U)
#define CAN_DATASIZE 		(64U)
//#define CAN_DLC 			(15U)
#define CAN_DATAFIELD		kMCAN_64ByteDatafield
#define CAN_ECR_TX_ERR_COUNTER_MASK             (0xFFU)
#define CAN_ECR_TX_ERR_COUNTER_SHIFT            (0U)
#define CAN_ECR_TXERRCNT_MASK         			CAN_ECR_TX_ERR_COUNTER_MASK
#define CAN_ECR_TXERRCNT_SHIFT        			CAN_ECR_TX_ERR_COUNTER_SHIFT
#define CAN_ECR_RX_ERR_COUNTER_MASK             (0x7F00U)
#define CAN_ECR_RX_ERR_COUNTER_SHIFT            (8U)
#define CAN_ECR_RXERRCNT_MASK         			CAN_ECR_RX_ERR_COUNTER_MASK
#define CAN_ECR_RXERRCNT_SHIFT        			CAN_ECR_RX_ERR_COUNTER_SHIFT
#define CAN_FIFO0                   			(0U)  /*!< CAN FIFO 0 used to receive */
#define CAN_FIFO1                   			(1U)  /*!< CAN FIFO 1 used to receive */

static rt_uint64_t std_filter_mask = 0;
static rt_uint64_t ext_filter_mask = 0;
static mcan_rx_buffer_frame_t rxFrame[2];
static mcan_fifo_transfer_t rxXfer[2];

__align(4) uint8_t msg_ram[(RX_MB_COUNT * (8U + CAN_DATASIZE) * sizeof(uint8_t))] __attribute__ ((at(MSG_RAM_BASE)));;

static const struct can_configure config = {
	.baud_rate = CAN125kBaud,
    .msgboxsz = RT_CANMSG_BOX_SZ,
    .sndboxnumber = RT_CANSND_BOX_NUM,
    .mode = RT_CAN_MODE_CANFD,
	.privmode = 0,
    .ticks = 50,
    .sndboxnumber = TX_MB_COUNT,             /* send Mailbox count */
    .msgboxsz = RX_MB_COUNT,        /* RX msg buffer count */
	#ifdef RT_CAN_USING_HDR
    .maxhdr = FILTER_LIST_COUNT,          /* filter count */
	#endif
};

/*
 *    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.
 *
 */
struct DLC_2_DATAFIELD{
	uint8_t dlc;
	uint8_t data_fileld;
};
const struct DLC_2_DATAFIELD dlc_2_datafield[]={
	0,0,
	1,1,
	2,2,
	3,3,
	4,4,
	5,5,
	6,6,
	7,7,
	8,8,
	9,12,
	10,16,
	11,20,
	12,24,
	13,32,
	14,48,
	15,64,
};

struct lpc_can
{
    char *name;
    CAN_Type *base;
	uint8_t	send_bufferIdx;
	clock_name_t clock_name;
    IRQn_Type irqn[2];
    mcan_handle_t handle;
    struct rt_can_device can_dev;
	uint8_t bus_off;
};

struct lpc_can lpccans[] =
{
#ifdef BSP_USING_CAN0
    {
        .name = "can0",
        .base = CAN0,
        .clock_name = kCLOCK_MCAN0,
        .irqn = {CAN0_IRQ0_IRQn, CAN0_IRQ1_IRQn},
    },
#endif
#ifdef BSP_USING_CAN1
    {
        .name = "can1",
        .base = CAN1,
        .clock_name = kCLOCK_MCAN1,
        .irqn = {CAN1_IRQ0_IRQn, CAN1_IRQ1_IRQn},
    },
#endif
};

static uint8_t can_2_datafield(uint8_t dlc)
{
	if( config.mode == RT_CAN_MODE_CANFD ){
		if( dlc<16 ){
			return dlc_2_datafield[dlc].data_fileld;
		}
		else{
			return 0xff;
		}
	}
	else{
		return 0x08;
	}
}

uint8_t can_2_dlc(uint8_t datafiled)
{
	if( config.mode == RT_CAN_MODE_CANFD ){
		uint8_t i;
		for( i=0; i<sizeof(dlc_2_datafield)/sizeof(struct DLC_2_DATAFIELD); i++ ){
			if( dlc_2_datafield[i].data_fileld>=datafiled )
				return dlc_2_datafield[i].dlc;
		}
		if( i==sizeof(dlc_2_datafield)/sizeof(struct DLC_2_DATAFIELD) ){
			return 0xff;
		}
	}
	else{
		return 0x08;
	}
}

static inline void MCAN_GetBusErrCount(CAN_Type *base, uint8_t *txErrBuf, uint8_t *rxErrBuf)
{
    if (txErrBuf)
    {
        *txErrBuf = (uint8_t)((base->ECR & CAN_ECR_TXERRCNT_MASK) >> CAN_ECR_TXERRCNT_SHIFT);
    }

    if (rxErrBuf)
    {
        *rxErrBuf = (uint8_t)((base->ECR & CAN_ECR_RXERRCNT_MASK) >> CAN_ECR_RXERRCNT_SHIFT);
    }
}

static void mcan_callback(CAN_Type *base, mcan_handle_t *handle, status_t status, uint32_t result, void *userData)
{
    struct lpc_can *can;
    can = (struct lpc_can *)userData;
	static uint8_t resend_cnt=0;

    switch (status)
    {
    case kStatus_MCAN_RxFifo0Idle:
        rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RX_IND | 0 << 8);
        rxFrame[0].size = CAN_DATASIZE;
    	rxXfer[0].frame = &rxFrame[0];
    	MCAN_TransferReceiveFifoNonBlocking(can->base, 0, &can->handle, &rxXfer[0]);
        break;

	case kStatus_MCAN_RxFifo1Idle:
        rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RX_IND | 1 << 8);
        rxFrame[1].size = CAN_DATASIZE;
    	rxXfer[1].frame = &rxFrame[1];
    	MCAN_TransferReceiveFifoNonBlocking(can->base, 1, &can->handle, &rxXfer[1]);
        break;

    case kStatus_MCAN_TxIdle:
		resend_cnt = 0;
        rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_DONE | can->handle.txbufferIdx << 8);
        break;

	case kStatus_MCAN_RxFifo0Lost:
		rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RXOF_IND | 0 << 8);
		break;

	case kStatus_MCAN_RxFifo1Lost:
		rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RXOF_IND | 1 << 8);
		break;
		
    case kStatus_MCAN_ErrorStatus:
		if( resend_cnt++>=3 ){
			resend_cnt = 0;
			MCAN_TransferAbortSend(can->base, &can->handle, can->send_bufferIdx);
			rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | can->handle.txbufferIdx << 8);
		}
        break;
	case kStatus_MCAN_BusOffStatus:
		can->bus_off = 1;
		MCAN_TransferAbortSend(can->base, &can->handle, can->send_bufferIdx);
		rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | can->handle.txbufferIdx << 8);
		break;

    default:
		//发生未定义的需记录入log文件
		LOG_E("Undef interupt handle\r\n");
		//MCAN_Deinit(can->base);
        break;
    }
}

static rt_err_t can_cfg(struct rt_can_device *can_dev, struct can_configure *cfg)
{
    struct lpc_can *can;
    mcan_config_t mcanConfig;
	mcan_timing_config_t timing_config;
	mcan_frame_filter_config_t rxFilter;
	mcan_std_filter_element_config_t stdFilter;
	mcan_ext_filter_element_config_t extFilter;
	mcan_rx_fifo_config_t rxFifo0;
	mcan_rx_fifo_config_t rxFifo1;
    mcan_tx_buffer_config_t txBuffer;
    rt_uint32_t res = RT_EOK;
    rt_uint8_t i;

    RT_ASSERT(can_dev != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    can = (struct lpc_can *)can_dev->parent.user_data;
    RT_ASSERT(can != RT_NULL);

    MCAN_GetDefaultConfig(&mcanConfig);
    
	//mcanConfig.enableLoopBackExt = true;
	LOG_D("%s : can clock freq = %u", __func__, CLOCK_GetFreq(can->clock_name));
	
    memset(&timing_config, 0, sizeof(timing_config));
	
	if( cfg->mode == RT_CAN_MODE_NORMAL ){
		
		mcanConfig.baudRateA= cfg->baud_rate;
		mcanConfig.enableCanfdNormal = false;
		mcanConfig.enableCanfdSwitch = false;
		
		if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, CLOCK_GetFreq(can->clock_name), &timing_config))
		{
			/* Update the improved timing configuration*/
			memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
		}
		else
		{
			LOG_D("No found Improved Timing Configuration. Just used default configuration");
		}
	}
	else if( cfg->mode == RT_CAN_MODE_CANFD ){
		
		mcanConfig.baudRateA= cfg->baud_rate;
		mcanConfig.baudRateD= cfg->baud_rate;
		mcanConfig.enableCanfdNormal = true;
		mcanConfig.enableCanfdSwitch = true;
		
		if (MCAN_FDCalculateImprovedTimingValues(mcanConfig.baudRateA, mcanConfig.baudRateD, CLOCK_GetFreq(can->clock_name), &timing_config))
		{
			/* Update the improved timing configuration*/
			memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
		}
		else
		{
			LOG_D("No found Improved Timing Configuration. Just used default configuration\r\n\r\n");
		}
	}
	else{
		mcanConfig.baudRateA= cfg->baud_rate;
		mcanConfig.enableCanfdNormal = false;
		mcanConfig.enableCanfdSwitch = false;
		
		if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, CLOCK_GetFreq(can->clock_name), &timing_config))
		{
			/* Update the improved timing configuration*/
			memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
		}
		else
		{
			LOG_D("No found Improved Timing Configuration. Just used default configuration");
		}
	}
	
    MCAN_Init(can->base, &mcanConfig, CLOCK_GetFreq(can->clock_name));
	
//	can_config_t config;
//	CAN_GetDefaultConfig(&config);
//    config.baseAddress = 0x20010000;
//    config.nominalBaudRate = 100000;
//    config.dataBaudRate = 100000;
//    config.timestampClock_Hz = 100000;
////    CAN_Init(CAN0, &config, SystemCoreClock);
//    CAN_Init(CAN1, &config, SystemCoreClock);
//	
//	CAN_Enable(CAN1, true);
	
    MCAN_TransferCreateHandle(can->base, &can->handle, mcan_callback, can);
	/* Set Message RAM base address and clear to avoid BEU/BEC error. */
    //MCAN_SetMsgRAMBase(can->base, MSG_RAM_BASE);
	MCAN_SetMsgRAMBase(can->base, (uint32_t)msg_ram);
    uint32_t *p = (uint32_t *)((uint32_t)msg_ram);
    memset(p, 0, (RX_MB_COUNT * (8U + CAN_DATASIZE) * sizeof(uint8_t)));

	/* STD filter config. */
    rxFilter.address  = STD_FILTER_OFS;
    rxFilter.idFormat = kMCAN_FrameIDStandard;
    rxFilter.listSize = FILTER_LIST_COUNT;
    rxFilter.nmFrame  = kMCAN_reject0;
    rxFilter.remFrame = kMCAN_filterFrame;
    MCAN_SetFilterConfig(can->base, &rxFilter);
	
    stdFilter.sfec = kMCAN_storeinFifo0;
    /* Classic filter mode, only filter matching ID. */
    stdFilter.sft   = kMCAN_classic;
    stdFilter.sfid1 = 0x0U;
    stdFilter.sfid2 = 0x7FFU;
	for (i = 0; i < FILTER_LIST_COUNT; i++)
	{
		MCAN_SetSTDFilterElement(can->base, &rxFilter, &stdFilter, i);
	}

	/* EXT filter config. */
	rxFilter.address  = EXT_FILTER_OFS;
	rxFilter.idFormat = kMCAN_FrameIDExtend;
	rxFilter.listSize = FILTER_LIST_COUNT;
	rxFilter.nmFrame  = kMCAN_reject0;
	rxFilter.remFrame = kMCAN_filterFrame;
	MCAN_SetFilterConfig(can->base, &rxFilter);

	extFilter.efec = kMCAN_storeinFifo1;
	/* Classic filter mode, only filter matching ID. */
	extFilter.eft = kMCAN_classic;
	extFilter.efid1 = 0x0U;
	extFilter.efid2 = 0x1FFFFFFFU;
	for (i = 0; i < FILTER_LIST_COUNT; i++)
	{
		MCAN_SetEXTFilterElement(can->base, &rxFilter, &extFilter, i);
	}

    /* RX fifo0 config. */
    rxFifo0.address       = RX_FIFO0_OFS;
    rxFifo0.elementSize   = RX_MB_COUNT;
    rxFifo0.watermark     = 0;
    rxFifo0.opmode        = kMCAN_FifoBlocking;
    rxFifo0.datafieldSize = CAN_DATAFIELD;
    MCAN_SetRxFifo0Config(can->base, &rxFifo0);

	/* RX fifo1 config. */
    rxFifo1.address       = RX_FIFO1_OFS;
    rxFifo1.elementSize   = RX_MB_COUNT;
    rxFifo1.watermark     = 0;
    rxFifo1.opmode        = kMCAN_FifoBlocking;
    rxFifo1.datafieldSize = CAN_DATAFIELD;
    MCAN_SetRxFifo1Config(can->base, &rxFifo1);

	/* TX buffer config. */
    memset(&txBuffer, 0, sizeof(txBuffer));
    txBuffer.address       = TX_BUFFER_OFS;
    txBuffer.dedicatedSize = TX_MB_COUNT;
    txBuffer.fqSize        = 0;
    txBuffer.datafieldSize = CAN_DATAFIELD;
    MCAN_SetTxBufferConfig(can->base, &txBuffer);
	
	switch (cfg->mode)
    {
		case RT_CAN_MODE_NORMAL:
			/* default mode */
			MCAN_EnterNormalMode(can->base);
			break;
		case RT_CAN_MODE_LISEN:
			break;
		case RT_CAN_MODE_LOOPBACK:
			break;
		case RT_CAN_MODE_LOOPBACKANLISEN:
			break;
		case RT_CAN_MODE_CANFD:
			MCAN_EnterNormalMode(can->base);
			break;
    }

	rxFrame[0].size = CAN_DATASIZE;
    rxXfer[0].frame = &rxFrame[0];
    MCAN_TransferReceiveFifoNonBlocking(can->base, 0, &can->handle, &rxXfer[0]);
	
	rxFrame[1].size = CAN_DATASIZE;
    rxXfer[1].frame = &rxFrame[1];
    MCAN_TransferReceiveFifoNonBlocking(can->base, 1, &can->handle, &rxXfer[1]);
	
    return res;
}

static rt_err_t can_control(struct rt_can_device *can_dev, int cmd, void *arg)
{
    struct lpc_can *can;
	mcan_frame_filter_config_t rxFilter;
	mcan_std_filter_element_config_t stdFilter;
	mcan_ext_filter_element_config_t extFilter;
    rt_uint32_t argval;
    rt_uint32_t res = RT_EOK;
	struct rt_can_filter_config  *cfg;
    struct rt_can_filter_item *item;
    rt_uint8_t i, count, index;

	RT_ASSERT(can_dev != RT_NULL);

    can = (struct lpc_can *)can_dev->parent.user_data;
    RT_ASSERT(can != RT_NULL);

	switch (cmd)
    {
    case RT_DEVICE_CTRL_SET_INT:
        argval = (rt_uint32_t) arg;
        if (argval == RT_DEVICE_FLAG_INT_RX)
        {
        	LOG_D("RT_DEVICE_FLAG_INT_RX");
        }
        else if (argval == RT_DEVICE_FLAG_INT_TX)
        {
        	LOG_D("RT_DEVICE_FLAG_INT_TX");
        }
        else if (argval == RT_DEVICE_CAN_INT_ERR)
        {
        	LOG_D("RT_DEVICE_CAN_INT_ERR");
        }
        EnableIRQ(can->irqn[0]);
        break;
    case RT_DEVICE_CTRL_CLR_INT:
        /* each CAN device have two IRQ number, use irq0 */
        DisableIRQ(can->irqn[0]);
        break;
    case RT_CAN_CMD_SET_FILTER:
        cfg = (struct rt_can_filter_config *)arg;
        item = cfg->items;
        count = cfg->count;
        
        while (count)
        {
            if (item->ide)
            {
				if (ext_filter_mask == 0xffffffffffffffff)
		        {
		            LOG_E("%s ext filter is full!\n", can->name);
					item++;
            		count--;
		            continue;
		        }	
				if (item->hdr == -1)
	            {

	                for (i = 0; i < 64; i++)
	                {
	                    if (!(ext_filter_mask & (1 << i)))
	                    {
	                        index = i;
	                        break;
	                    }
	                }
	            }
	            else    /* use user specified hdr */
	            {
	                if (ext_filter_mask & (1 << item->hdr))
	                {
	                    LOG_E("%s hdr%d filter already set!\n", can->name, item->hdr);
						item++;
            			count--;
	                    continue;
	                }
	                else
	                {
	                    index = item->hdr;
	                }
	            }
				/* EXT filter config. */
				rxFilter.address  = EXT_FILTER_OFS;
				rxFilter.idFormat = kMCAN_FrameIDExtend;
				rxFilter.listSize = FILTER_LIST_COUNT;
				rxFilter.nmFrame  = kMCAN_reject0;
				rxFilter.remFrame = kMCAN_filterFrame;
				MCAN_SetFilterConfig(can->base, &rxFilter);

				extFilter.efec = kMCAN_storeinFifo1;
				/* Classic filter mode, only filter matching ID. */
				extFilter.eft = kMCAN_classic;
				extFilter.efid1 = (uint32_t)item->id;
				extFilter.efid2 = (uint32_t)item->mask; //0x1FFFFFFFU;
				MCAN_SetEXTFilterElement(can->base, &rxFilter, &extFilter, index);
				ext_filter_mask |= 1 << index;
			}
			else
			{
				if (std_filter_mask == 0xffffffffffffffff)
			        {
			            LOG_E("%s std filter is full!\n", can->name);
						item++;
            			count--;
			            continue;
			        }	
					if (item->hdr == -1)
		            {

		                for (i = 0; i < 64; i++)
		                {
		                    if (!(std_filter_mask & (1 << i)))
		                    {
		                        index = i;
		                        break;
		                    }
		                }
		            }
		            else    /* use user specified hdr */
		            {
		                if (std_filter_mask & (1 << item->hdr))
		                {
		                    LOG_E("%s hdr%d filter already set!\n", can->name, item->hdr);
							item++;
            				count--;
		                    continue;
		                }
		                else
		                {
		                    index = item->hdr;
		                }
		            }
					/* STD filter config. */
				    rxFilter.address  = STD_FILTER_OFS;
				    rxFilter.idFormat = kMCAN_FrameIDStandard;
				    rxFilter.listSize = FILTER_LIST_COUNT;
				    rxFilter.nmFrame  = kMCAN_reject0;
				    rxFilter.remFrame = kMCAN_filterFrame;
				    MCAN_SetFilterConfig(can->base, &rxFilter);

					stdFilter.sfec = kMCAN_storeinFifo0;
				    /* Classic filter mode, only filter matching ID. */
				    stdFilter.sft   = kMCAN_classic;
				    stdFilter.sfid1 = (uint32_t)item->id;
				    stdFilter.sfid2 = (uint32_t)item->mask; //0x7FFU;
					MCAN_SetSTDFilterElement(can->base, &rxFilter, &stdFilter, index);
					std_filter_mask |= 1 << index;
			}
			item++;
            count--;
        }
        break;

    case RT_CAN_CMD_SET_BAUD:
	case RT_CAN_CMD_SET_MODE:
		{
			struct rt_can_baudrate_config  *cfg = (struct rt_can_baudrate_config *)arg;
			mcan_config_t mcanConfig;
			mcan_timing_config_t timing_config;
			
			MCAN_GetDefaultConfig(&mcanConfig);
    
			//mcanConfig.enableLoopBackExt = true;
			LOG_D("%s : can clock freq = %u", __func__, CLOCK_GetFreq(can->clock_name));
			
			memset(&timing_config, 0, sizeof(timing_config));
			
			if( cfg->mode == RT_CAN_MODE_NORMAL ){
				
				mcanConfig.baudRateA= cfg->baudRateD;
				mcanConfig.enableCanfdNormal = false;
				mcanConfig.enableCanfdSwitch = false;
				
				if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, CLOCK_GetFreq(can->clock_name), &timing_config))
				{
					/* Update the improved timing configuration*/
					memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
				}
				else
				{
					LOG_W("No found Improved Timing Configuration. Just used default configuration");
				}
			}
			else if( cfg->mode == RT_CAN_MODE_CANFD ){
				
				mcanConfig.baudRateA= cfg->baudRateA;
				mcanConfig.baudRateD= cfg->baudRateD;
				mcanConfig.enableCanfdNormal = true;
				mcanConfig.enableCanfdSwitch = true;
				
				if (MCAN_FDCalculateImprovedTimingValues(mcanConfig.baudRateA, mcanConfig.baudRateD, CLOCK_GetFreq(can->clock_name), &timing_config))
				{
					/* Update the improved timing configuration*/
					memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
				}
				else
				{
					LOG_W("No found Improved Timing Configuration. Just used default configuration\r\n\r\n");
				}
			}
			else{
				mcanConfig.baudRateA= cfg->baudRateD;
				mcanConfig.enableCanfdNormal = false;
				mcanConfig.enableCanfdSwitch = false;
				
				if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, CLOCK_GetFreq(can->clock_name), &timing_config))
				{
					/* Update the improved timing configuration*/
					memcpy(&(mcanConfig.timingConfig), &timing_config, sizeof(mcan_timing_config_t));
				}
				else
				{
					LOG_W("No found Improved Timing Configuration. Just used default configuration");
				}
			}
			
			MCAN_Init(can->base, &mcanConfig, CLOCK_GetFreq(can->clock_name));
			
			switch (cfg->mode)
			{
				case RT_CAN_MODE_NORMAL:
					/* default mode */
					MCAN_EnterNormalMode(can->base);
					break;
				case RT_CAN_MODE_LISEN:
					break;
				case RT_CAN_MODE_LOOPBACK:
					break;
				case RT_CAN_MODE_LOOPBACKANLISEN:
					break;
				case RT_CAN_MODE_CANFD:
					MCAN_EnterNormalMode(can->base);
					break;
			}
		}
        break;

    case RT_CAN_CMD_SET_PRIV:
        res = RT_ERROR;
        break;
    case RT_CAN_CMD_GET_STATUS:
        MCAN_GetBusErrCount(can->base, (rt_uint8_t *)(&can->can_dev.status.snderrcnt), (rt_uint8_t *)(&can->can_dev.status.rcverrcnt));
        rt_memcpy(arg, &can->can_dev.status, sizeof(can->can_dev.status));
        break;
    default:
        res = RT_ERROR;
        break;
    }

    return res;
}

static int can_send(struct rt_can_device *can_dev, const void *buf, rt_uint32_t boxno)
{
    struct lpc_can *can;
    struct rt_can_msg *msg;
    status_t ret;
	uint8_t tx_data[CAN_DATASIZE],dlc;
	uint8_t wait_send_ok;
	mcan_tx_buffer_frame_t txFrame;
	mcan_buffer_transfer_t txXfer;

    RT_ASSERT(can_dev != RT_NULL);
    RT_ASSERT(buf != RT_NULL);

    can = (struct lpc_can *)can_dev->parent.user_data;
    msg = (struct rt_can_msg *) buf;
    RT_ASSERT(can != RT_NULL);
    RT_ASSERT(msg != RT_NULL);

	dlc = can_2_dlc(msg->len);
	//必需为指定发送的数据长度
	if( dlc==0xff )
		return RT_ERROR;
	
	//等待总线恢复
	if( can->bus_off ){
		uint8_t last_tec=0xff,new_tec;
		uint8_t tec_add=0;
		while(1){
			if( can->base->CCCR&0x01 ){
				MCAN_EnterNormalMode(can->base);
			}
			uint8_t test_buf[]={1,2,3,4,5,6,7,8};
			txFrame.dlc = 0;
			txFrame.fdf = 1;
			txFrame.brs = 1;
			txFrame.size = 8;
			txFrame.data = test_buf;
			txFrame.id = 0xffffff;
	
			txXfer.frame     = &txFrame;
			txXfer.bufferIdx = (uint8_t)boxno;
			can->send_bufferIdx = (uint8_t)boxno;
			
			ret = MCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
			
			rt_thread_delay(15);
		
			new_tec = (can->base->ECR&0xff);
			
			if( (new_tec == 0 &&  last_tec==0) || (new_tec == 0x80 &&  last_tec==0x80) || tec_add>=8 ){
				can->bus_off = 0;
				break;
			}
			
			if( last_tec-new_tec==1 )
				tec_add++;
			else
				tec_add=0;
			
			last_tec = new_tec;
		}
	}
	
	rt_memcpy(tx_data,msg->data,CAN_DATASIZE);

    if (RT_CAN_STDID == msg->ide)
    {
        txFrame.id   = msg->id << STDID_OFFSET;
        txFrame.xtd = kMCAN_FrameIDStandard;
    }
    else if (RT_CAN_EXTID == msg->ide)
    {
        txFrame.id   = msg->id << EXTID_OFFSET;
        txFrame.xtd = kMCAN_FrameIDExtend;
    }

    if (RT_CAN_DTR == msg->rtr)
    {
        txFrame.rtr = kMCAN_FrameTypeData;
    }
    else if (RT_CAN_RTR == msg->rtr)
    {
        txFrame.rtr = kMCAN_FrameTypeRemote;
    }

	txFrame.dlc = dlc;
	txFrame.fdf = 1;
	txFrame.brs = 1;
	txFrame.size = msg->len;
	txFrame.data = tx_data;
    
    txXfer.frame     = &txFrame;
    txXfer.bufferIdx = (uint8_t)boxno;
	can->send_bufferIdx = (uint8_t)boxno;
    ret = MCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
	
	wait_send_ok = 0;
	while (!MCAN_IsTransmitOccurred(can->base, txXfer.bufferIdx) && wait_send_ok<10 ){
		rt_thread_delay(1);
		wait_send_ok++;
	}
	if( wait_send_ok>=10 )
		return RT_ERROR;
	
    switch (ret)
    {
    case kStatus_Success:
		ret = RT_EOK;
        break;
    case kStatus_Fail:
        ret = RT_ERROR;
        break;
    case kStatus_MCAN_TxBusy:
        ret = RT_EBUSY;
        break;
    }

    return ret;
}

static int can_recv(struct rt_can_device *can_dev, void *buf, rt_uint32_t boxno)
{
    struct lpc_can *can;
    struct rt_can_msg *pmsg;
	mcan_rx_buffer_frame_t *prxFrame = NULL;
	uint8_t rx_data[CAN_DATASIZE];

    RT_ASSERT(can_dev != RT_NULL);

    can = (struct lpc_can *)can_dev->parent.user_data;
    pmsg = (struct rt_can_msg *) buf;
    RT_ASSERT(can != RT_NULL);

	/* get FIFO */
    switch (boxno)
    {
        case CAN_FIFO0:
            prxFrame = &rxFrame[0];
            break;
        case CAN_FIFO1:
            prxFrame = &rxFrame[1];
            break;
        default:
            RT_ASSERT(0);
            break;
    }

    if (prxFrame->xtd == kMCAN_FrameIDStandard)
    {
        pmsg->ide = RT_CAN_STDID;
        pmsg->id = prxFrame->id >> STDID_OFFSET;
		LOG_D("%s : standard frame id = 0x%x", __func__, pmsg->id);
    }
    else
    {
        pmsg->ide = RT_CAN_EXTID;
        pmsg->id = prxFrame->id >> EXTID_OFFSET;
		LOG_D("%s : ext frame id = 0x%x", __func__, pmsg->id);
    }

    if (prxFrame->rtr == kMCAN_FrameTypeData)
    {
        pmsg->rtr = RT_CAN_DTR;
    }
    else if (prxFrame->rtr == kMCAN_FrameTypeRemote)
    {
        pmsg->rtr = RT_CAN_RTR;
    }
    pmsg->hdr = prxFrame->fidx;
    pmsg->len = can_2_datafield(prxFrame->dlc);
	
	//返回DLC长度错误处理
	if( pmsg->len <= 64 ){
		rt_memcpy(pmsg->data, prxFrame->data, pmsg->len);
	}
	//rt_memcpy(rx_data, prxFrame->data, prxFrame->size);
	//rt_memcpy(pmsg->data, prxFrame->data, prxFrame->size);

    return 0;
}

static struct rt_can_ops lpc_can_ops =
{
    .configure    = can_cfg,
    .control      = can_control,
    .sendmsg      = can_send,
    .recvmsg      = can_recv,
};

int rt_hw_can_init(void)
{
    int i;
    rt_err_t ret = RT_EOK;
	
#ifdef BSP_USING_CAN0	
	CLOCK_SetClkDiv(kCLOCK_DivCan0Clk, 6U, true);
#endif	
#ifdef BSP_USING_CAN1	
	CLOCK_SetClkDiv(kCLOCK_DivCan1Clk, 6U, true);
#endif
	Can_InitPins();

    for (i = 0; i < sizeof(lpccans) / sizeof(lpccans[0]); i++)
    {
        lpccans[i].can_dev.config = config;
        ret = rt_hw_can_register(&lpccans[i].can_dev, lpccans[i].name, &lpc_can_ops, &lpccans[i]);
    }

    return ret;
}
INIT_BOARD_EXPORT(rt_hw_can_init);
#endif /* RT_USING_CAN */

fsl_mcan.c
fsl版本为2.1.0

/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "fsl_mcan.h"

/*******************************************************************************
 * Definitons
 ******************************************************************************/

#define MCAN_TIME_QUANTA_NUM (16U)

/* add by zwc start from MCAN driver version 2.1.0 */
#define IDEAL_SP_LOW (750U)
#define IDEAL_SP_MID (800U)
#define IDEAL_SP_HIGH (875U)
#define IDEAL_SP_FACTOR (1000U)

#define MAX_DSJW (CAN_DBTP_DSJW_MASK >> CAN_DBTP_DSJW_SHIFT)
#define MAX_DTSEG2 (CAN_DBTP_DTSEG2_MASK >> CAN_DBTP_DTSEG2_SHIFT)
#define MAX_DTSEG1 (CAN_DBTP_DTSEG1_MASK >> CAN_DBTP_DTSEG1_SHIFT)
#define MAX_DBRP (CAN_DBTP_DBRP_MASK >> CAN_DBTP_DBRP_SHIFT)

#define MAX_NSJW (CAN_NBTP_NSJW_MASK >> CAN_NBTP_NBRP_SHIFT)
#define MAX_NTSEG2 (CAN_NBTP_NTSEG2_MASK >> CAN_NBTP_NTSEG2_SHIFT)
#define MAX_NTSEG1 (CAN_NBTP_NTSEG1_MASK >> CAN_NBTP_NTSEG1_SHIFT)
#define MAX_NBRP (CAN_NBTP_NBRP_MASK >> CAN_NBTP_NBRP_SHIFT)

#define DBTP_MAX_TIME_QUANTA (1U + MAX_DTSEG2 + 1U + MAX_DTSEG1 + 1U)
#define DBTP_MIN_TIME_QUANTA (3U)
#define NBTP_MAX_TIME_QUANTA (1U + MAX_NTSEG2 + 1U + MAX_NTSEG1 + 1U)
#define NBTP_MIN_TIME_QUANTA (3U)

#define MAX_CANFD_BAUDRATE (8000000U)
#define MAX_CAN_BAUDRATE (1000000U)
/* add by zwc end */

/*! @brief MCAN Internal State. */
enum _mcan_state
{
    kMCAN_StateIdle = 0x0,     /*!< MB/RxFIFO idle.*/
    kMCAN_StateRxData = 0x1,   /*!< MB receiving.*/
    kMCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
    kMCAN_StateTxData = 0x3,   /*!< MB transmitting.*/
    kMCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
    kMCAN_StateRxFifo = 0x5,   /*!< RxFIFO receiving.*/
};

/* Typedef for interrupt handler. */
typedef void (*mcan_isr_t)(CAN_Type *base, mcan_handle_t *handle);

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*!
 * @brief Get the MCAN instance from peripheral base address.
 *
 * @param base MCAN peripheral base address.
 * @return MCAN instance.
 */
uint32_t MCAN_GetInstance(CAN_Type *base);

/*!
 * @brief Reset the MCAN instance.
 *
 * @param base MCAN peripheral base address.
 */
static void MCAN_Reset(CAN_Type *base);

/*!
 * @brief Set Baud Rate of MCAN.
 *
 * This function set the baud rate of MCAN.
 *
 * @param base MCAN peripheral base address.
 * @param sourceClock_Hz Source Clock in Hz.
 * @param baudRate_Bps Baud Rate in Bps.
 */
static void MCAN_SetBaudRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRateA_Bps);

#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
/*!
 * @brief Set Baud Rate of MCAN FD.
 *
 * This function set the baud rate of MCAN FD.
 *
 * @param base MCAN peripheral base address.
 * @param sourceClock_Hz Source Clock in Hz.
 * @param baudRateD_Bps Baud Rate in Bps.
 */
static void MCAN_SetBaudRateFD(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRateD_Bps);
#endif /* FSL_FEATURE_CAN_SUPPORT_CANFD */

/*!
 * @brief Get the element's address when read receive fifo 0.
 *
 * @param base MCAN peripheral base address.
 * @return Address of the element in receive fifo 0.
 */
static uint32_t MCAN_GetRxFifo0ElementAddress(CAN_Type *base);

/*!
 * @brief Get the element's address when read receive fifo 1.
 *
 * @param base MCAN peripheral base address.
 * @return Address of the element in receive fifo 1.
 */
static uint32_t MCAN_GetRxFifo1ElementAddress(CAN_Type *base);

/*!
 * @brief Get the element's address when read receive buffer.
 *
 * @param base MCAN peripheral base address.
 * @param idx Number of the erceive buffer element.
 * @return Address of the element in receive buffer.
 */
static uint32_t MCAN_GetRxBufferElementAddress(CAN_Type *base, uint8_t idx);

/*!
 * @brief Get the element's address when read transmit buffer.
 *
 * @param base MCAN peripheral base address.
 * @param idx Number of the transmit buffer element.
 * @return Address of the element in transmit buffer.
 */
static uint32_t MCAN_GetTxBufferElementAddress(CAN_Type *base, uint8_t idx);

/*******************************************************************************
 * Variables
 ******************************************************************************/
/* Array of MCAN handle. */
static mcan_handle_t *s_mcanHandle[FSL_FEATURE_SOC_LPC_CAN_COUNT];

/* Array of MCAN peripheral base address. */
static CAN_Type *const s_mcanBases[] = CAN_BASE_PTRS;

/* Array of MCAN IRQ number. */
static const IRQn_Type s_mcanIRQ[][2] = CAN_IRQS;

#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Array of MCAN clock name. */
static const clock_ip_name_t s_mcanClock[] = MCAN_CLOCKS;
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */

/* MCAN ISR for transactional APIs. */
static mcan_isr_t s_mcanIsr;

/*******************************************************************************
 * Code
 ******************************************************************************/

uint32_t MCAN_GetInstance(CAN_Type *base)
{
    uint32_t instance;

    /* Find the instance index from base address mappings. */
    for (instance = 0; instance < ARRAY_SIZE(s_mcanBases); instance++)
    {
        if (s_mcanBases[instance] == base)
        {
            break;
        }
    }

    assert(instance < ARRAY_SIZE(s_mcanBases));

    return instance;
}

static void MCAN_Reset(CAN_Type *base)
{
    /* Set INIT bit. */
    base->CCCR |= CAN_CCCR_INIT_MASK;
    /* Confirm the value has been accepted. */
    while (!((base->CCCR & CAN_CCCR_INIT_MASK) >> CAN_CCCR_INIT_SHIFT))
    {
    }

    /* Set CCE bit to have access to the protected configuration registers,
       and clear some status registers. */
    base->CCCR |= CAN_CCCR_CCE_MASK;
}

static void MCAN_SetBaudRate(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRateA_Bps)
{
    mcan_timing_config_t timingConfigA;
    uint32_t preDivA = baudRateA_Bps * MCAN_TIME_QUANTA_NUM;

    if (0 == preDivA)
    {
        preDivA = 1U;
    }

    preDivA = (sourceClock_Hz / preDivA) - 1U;

    /* Desired baud rate is too low. */
    if (preDivA > 0x1FFU)
    {
        preDivA = 0x1FFU;
    }

    /* MCAN timing setting formula:
     * MCAN_TIME_QUANTA_NUM = 1 + (xTSEG1 + 1) + (xTSEG2 + 1));
     */
    timingConfigA.preDivider = preDivA;
    timingConfigA.seg1 = 0xAU;
    timingConfigA.seg2 = 0x3U;
    timingConfigA.rJumpwidth = 0x3U;

    /* Update actual timing characteristic. */
    MCAN_SetArbitrationTimingConfig(base, &timingConfigA);
}

#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
static void MCAN_SetBaudRateFD(CAN_Type *base, uint32_t sourceClock_Hz, uint32_t baudRateD_Bps)
{
    mcan_timing_config_t timingConfigD;
    uint32_t preDivD = baudRateD_Bps * MCAN_TIME_QUANTA_NUM;

    if (0 == preDivD)
    {
        preDivD = 1U;
    }

    preDivD = (sourceClock_Hz / preDivD) - 1U;

    /* Desired baud rate is too low. */
    if (preDivD > 0x1FU)
    {
        preDivD = 0x1FU;
    }

    /* MCAN timing setting formula:
     * MCAN_TIME_QUANTA_NUM = 1 + (xTSEG1 + 1) + (xTSEG2 + 1));
     */
    timingConfigD.preDivider = preDivD;
    timingConfigD.seg1 = 0xAU;
    timingConfigD.seg2 = 0x3U;
    timingConfigD.rJumpwidth = 0x3U;

    /* Update actual timing characteristic. */
    MCAN_SetDataTimingConfig(base, &timingConfigD);
}
#endif

void MCAN_Init(CAN_Type *base, const mcan_config_t *config, uint32_t sourceClock_Hz)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    /* Enable MCAN clock. */
    CLOCK_EnableClock(s_mcanClock[MCAN_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */

    MCAN_Reset(base);

    if (config->enableLoopBackInt)
    {
        base->CCCR |= CAN_CCCR_TEST_MASK | CAN_CCCR_MON_MASK;
        base->TEST |= CAN_TEST_LBCK_MASK;
    }
    if (config->enableLoopBackExt)
    {
        base->CCCR |= CAN_CCCR_TEST_MASK;
        base->TEST |= CAN_TEST_LBCK_MASK;
    }
    if (config->enableBusMon)
    {
        base->CCCR |= CAN_CCCR_MON_MASK;
    }
	//base->CCCR |= CAN_CCCR_DAR_MASK;
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
    if (config->enableCanfdNormal)
    {
        base->CCCR |= CAN_CCCR_FDOE_MASK;
    }
    if (config->enableCanfdSwitch)
    {
        base->CCCR |= CAN_CCCR_FDOE_MASK | CAN_CCCR_BRSE_MASK;
    }
#endif

    /* Set baud rate of arbitration and data phase. */
    MCAN_SetBaudRate(base, sourceClock_Hz, config->baudRateA);
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
    MCAN_SetBaudRateFD(base, sourceClock_Hz, config->baudRateD);
#endif
}

void MCAN_Deinit(CAN_Type *base)
{
    /* Reset all Register Contents. */
    MCAN_Reset(base);

#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
    /* Disable MCAN clock. */
    CLOCK_DisableClock(s_mcanClock[MCAN_GetInstance(base)]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}

void MCAN_EnterNormalMode(CAN_Type *base)
{
    /* Reset INIT bit to enter normal mode. */
    base->CCCR &= ~CAN_CCCR_INIT_MASK;
    while (((base->CCCR & CAN_CCCR_INIT_MASK) >> CAN_CCCR_INIT_SHIFT))
    {
    }
}

/* add by zwc 20191212 */
/*!
 * brief Gets the default configuration structure.
 *
 * This function initializes the MCAN configuration structure to default values. The default
 * values are as follows.
 *   config->baudRateA = 500000U;
 *   config->baudRateD = 1000000U;
 *   config->enableCanfdNormal = false;
 *   config->enableCanfdSwitch = false;
 *   config->enableLoopBackInt = false;
 *   config->enableLoopBackExt = false;
 *   config->enableBusMon = false;
 *
 * param config Pointer to the MCAN configuration structure.
 */
void MCAN_GetDefaultConfig(mcan_config_t *config)
{
    /* Assertion. */
    assert(config);

    /* Initializes the configure structure to zero. */
    memset(config, 0, sizeof(*config));

    /* Initialize MCAN Module config struct with default value. */
    config->baudRateA         = 500000U;
    config->baudRateD         = 1000000U;
    config->enableCanfdNormal = true;
    config->enableCanfdSwitch = true;
    config->enableLoopBackInt = false;
    config->enableLoopBackExt = false;
    config->enableBusMon      = false;
    /* Default protocol timing configuration, time quantum is 16. */
    config->timingConfig.seg1       = 0xAU;
    config->timingConfig.seg2       = 0x3U;
    config->timingConfig.rJumpwidth = 0x3U;
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
    config->timingConfig.dataseg1       = 0xAU;
    config->timingConfig.dataseg2       = 0x3U;
    config->timingConfig.datarJumpwidth = 0x3U;
#endif
}

/* modify by zwc 20191212 */
#if 0
void MCAN_GetDefaultConfig(mcan_config_t *config)
{
    /* Assertion. */
    assert(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;
}
#endif

/* add by zwc start from MCAN driver version 2.1.0 */
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
/*!
 * @brief Calculates the segment values for a single bit time for CANFD bus data baud Rate
 *
 * @param baudRate The canfd bus data speed in bps
 * @param tqNum Number of time quanta per bit
 * @param pconfig Pointer to the MCAN timing configuration structure.
 *
 */
static void MCAN_FDGetSegments(uint32_t baudRateFD, uint32_t tqNum, mcan_timing_config_t *pconfig)
{
    uint32_t ideal_sp;
    uint32_t p1;

    /* get ideal sample point. */
    if (baudRateFD >= 1000000)
        ideal_sp = IDEAL_SP_LOW;
    else if (baudRateFD >= 800000)
        ideal_sp = IDEAL_SP_MID;
    else
        ideal_sp = IDEAL_SP_HIGH;

    /* distribute time quanta. */
    p1                = tqNum * (uint32_t)ideal_sp;
    pconfig->dataseg1 = p1 / IDEAL_SP_FACTOR - 1U;
    if (pconfig->dataseg1 > MAX_DTSEG1)
    {
        pconfig->dataseg1 = MAX_DTSEG1;
    }

    pconfig->dataseg2 = tqNum - (1U + pconfig->dataseg1 + 1U + 1U);

    assert(pconfig->dataseg2 <= MAX_DTSEG2);

    /* subtract one TQ for sync seg. */
    /* sjw is 20% of total TQ, rounded to nearest int. */
    pconfig->datarJumpwidth = (tqNum + (5 - 1)) / 5 - 1U;

    if (pconfig->datarJumpwidth > MAX_DSJW)
    {
        pconfig->datarJumpwidth = MAX_DSJW;
    }
}

/*!
 * @brief Calculates the segment values for a single bit time for classical CAN
 *
 * @param baudRate The data speed in bps
 * @param tqNum Number of time quantas per bit
 * @param pconfig Pointer to the MCAN timing configuration structure.
 */
static void MCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, mcan_timing_config_t *pconfig)
{
    uint32_t ideal_sp;
    uint32_t p1;

    /* get ideal sample point. */
    if (baudRate >= 1000000)
        ideal_sp = IDEAL_SP_LOW;
    else if (baudRate >= 800000)
        ideal_sp = IDEAL_SP_MID;
    else
        ideal_sp = IDEAL_SP_HIGH;

    /* distribute time quanta. */
    p1            = tqNum * (uint32_t)ideal_sp;
    pconfig->seg1 = p1 / IDEAL_SP_FACTOR - 1U;

    pconfig->seg2 = tqNum - (1U + pconfig->seg1 + 1U + 1U);
    assert(pconfig->seg2 <= MAX_NTSEG2);

    /* subtract one TQ for sync seg. */
    /* sjw is 20% of total TQ, rounded to nearest int. */
    pconfig->rJumpwidth = (tqNum + (5 - 1)) / 5 - 1U;
}

/*!
 * @brief Calculates the improved timing values by specific baudrates for classical CAN
 *
 * @param baudRate  The classical CAN speed in bps defined by user
 * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
 * @param pconfig Pointer to the MCAN timing configuration structure.
 *
 * @return TRUE if timing configuration found, FALSE if failed to find configuration
 */
bool MCAN_CalculateImprovedTimingValues(uint32_t baudRate, uint32_t sourceClock_Hz, mcan_timing_config_t *pconfig)
{
    uint32_t clk;   /* the clock is tqNumb x baudRateFD. */
    uint32_t clk2;  /* the clock2 is clk2 / Pre-scaler Division Factor. */
    uint32_t tqNum; /* Numbers of TQ. */

    /* observe baud rate maximums. */
    assert(baudRate <= MAX_CAN_BAUDRATE);

    /*  Auto Improved Protocal timing for CBT. */
    for (tqNum = NBTP_MAX_TIME_QUANTA; tqNum >= NBTP_MIN_TIME_QUANTA; tqNum--)
    {
        clk = baudRate * tqNum;
        if (clk > sourceClock_Hz)
        {
            continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
        }

        for (pconfig->preDivider = 0x0U; pconfig->preDivider <= MAX_NBRP; (pconfig->preDivider)++)
        {
            /* Consider some proessor not contain FPU, the parameter need to be exact division. */
            if ((clk / (pconfig->preDivider + 1U) * (pconfig->preDivider + 1U)) != clk)
            {
                continue; /* clk need to be exact division by preDivider + 1. */
            }
            clk2 = clk / (pconfig->preDivider + 1U);
            if (((sourceClock_Hz / clk2) * clk2) != sourceClock_Hz)
            {
                continue; /* sourceClock_Hz need to be exact division by preDivider. */
            }
            MCAN_GetSegments(baudRate, tqNum, pconfig);
            return true;
        }
    }
    /* failed to find solution. */
    return false;
}

/*!
 * @brief Calculates the improved timing values by specific baudrates for CANFD
 *
 * @param baudRate  The CANFD bus control speed in bps defined by user
 * @param baudRateFD  The CANFD bus data speed in bps defined by user
 * @param sourceClock_Hz The Source clock data speed in bps.
 * @param pconfig Pointer to the MCAN timing configuration structure.
 *
 * @return TRUE if timing configuration found, FALSE if failed to find configuration
 */
bool MCAN_FDCalculateImprovedTimingValues(uint32_t baudRate,
                                          uint32_t baudRateFD,
                                          uint32_t sourceClock_Hz,
                                          mcan_timing_config_t *pconfig)
{
    uint32_t clk;
    uint32_t clk2;
    uint32_t tqNum; /* Numbers of TQ. */

    /* observe baud rate maximums */
    assert(baudRate <= MAX_CAN_BAUDRATE);
    assert(baudRateFD <= MAX_CANFD_BAUDRATE);

    /*  Auto Improved Protocal timing for Nominal register. */
    if (MCAN_CalculateImprovedTimingValues(baudRate, sourceClock_Hz, pconfig))
    {
        /* After calculate for Nominal timing, continue to calculate Data timing configuration. */
        for (tqNum = DBTP_MAX_TIME_QUANTA; tqNum >= DBTP_MIN_TIME_QUANTA; tqNum--)
        {
            clk = baudRateFD * tqNum;
            if (clk > sourceClock_Hz)
            {
                continue; /* tqNumbrs too large, clkbrs x tqNumbrs has been exceed sourceClock_Hz. */
            }
            for (pconfig->datapreDivider = 0U; pconfig->datapreDivider <= MAX_DBRP; (pconfig->datapreDivider)++)
            {
                /* Consider some proessor not contain FPU, the parameter need to be exact division. */
                if ((clk / (pconfig->datapreDivider + 1U) * (pconfig->datapreDivider + 1U)) != clk)
                {
                    continue; /* clk need to be exact division by preDivider + 1. */
                }
                clk2 = clk / (pconfig->datapreDivider + 1U);
                if ((sourceClock_Hz / clk2 * clk2) != sourceClock_Hz)
                {
                    continue; /* sourceClock_Hz need to be exact division by preDivider. */
                }
                MCAN_FDGetSegments(baudRateFD, tqNum, pconfig);
                return true;
            }
        }
    }

    /* failed to find solution. */
    return false;
}

/*!
 * brief Sets the MCAN protocol data phase timing characteristic.
 *
 * This function gives user settings to CAN bus timing characteristic.
 * The function is for an experienced user. For less experienced users, call
 * the MCAN_Init() and fill the baud rate field with a desired value.
 * This provides the default data phase timing characteristics.
 *
 * Note that calling MCAN_SetArbitrationTimingConfig() overrides the baud rate
 * set in MCAN_Init().
 *
 * param base MCAN peripheral base address.
 * param config Pointer to the timing configuration structure.
 */
void MCAN_SetDataTimingConfig(CAN_Type *base, const mcan_timing_config_t *config)
{
    /* Assertion. */
    assert(config);

    /* Cleaning previous Timing Setting. */
    base->DBTP &= ~(CAN_DBTP_DSJW_MASK | CAN_DBTP_DTSEG2_MASK | CAN_DBTP_DTSEG1_MASK | CAN_DBTP_DBRP_MASK);

    /* Updating Timing Setting according to configuration structure. */
    base->DBTP |= (CAN_DBTP_DBRP(config->datapreDivider) | CAN_DBTP_DSJW(config->datarJumpwidth) |
                   CAN_DBTP_DTSEG1(config->dataseg1) | CAN_DBTP_DTSEG2(config->dataseg2));
}
#endif /* FSL_FEATURE_CAN_SUPPORT_CANFD */
/* add by zwc end from MCAN driver version 2.1.0 */

/*modify by zwc start*/
#if 0
#if (defined(FSL_FEATURE_CAN_SUPPORT_CANFD) && FSL_FEATURE_CAN_SUPPORT_CANFD)
void MCAN_SetDataTimingConfig(CAN_Type *base, const mcan_timing_config_t *config)
{
    /* Assertion. */
    assert(config);

    /* Cleaning previous Timing Setting. */
    base->DBTP &= ~(CAN_DBTP_DSJW_MASK | CAN_DBTP_DTSEG2_MASK | CAN_DBTP_DTSEG1_MASK | CAN_DBTP_DBRP_MASK);

    /* Updating Timing Setting according to configuration structure. */
    base->DBTP |= (CAN_DBTP_DBRP(config->preDivider) | CAN_DBTP_DSJW(config->rJumpwidth) |
                   CAN_DBTP_DTSEG1(config->seg1) | CAN_DBTP_DTSEG2(config->seg2));
}
#endif /* FSL_FEATURE_CAN_SUPPORT_CANFD */
#endif
/*modify by zwc end*/

void MCAN_SetArbitrationTimingConfig(CAN_Type *base, const mcan_timing_config_t *config)
{
    /* Assertion. */
    assert(config);

    /* Cleaning previous Timing Setting. */
    base->NBTP &= ~(CAN_NBTP_NSJW_MASK | CAN_NBTP_NTSEG2_MASK | CAN_NBTP_NTSEG1_MASK | CAN_NBTP_NBRP_MASK);

    /* Updating Timing Setting according to configuration structure. */
    base->NBTP |= (CAN_NBTP_NBRP(config->preDivider) | CAN_NBTP_NSJW(config->rJumpwidth) |
                   CAN_NBTP_NTSEG1(config->seg1) | CAN_NBTP_NTSEG2(config->seg2));
}

void MCAN_SetFilterConfig(CAN_Type *base, const mcan_frame_filter_config_t *config)
{
    /* Set global configuration of remote/nonmasking frames, set filter address and list size. */
    if (config->idFormat == kMCAN_FrameIDStandard)
    {
        base->GFC |= CAN_GFC_RRFS(config->remFrame) | CAN_GFC_ANFS(config->nmFrame);
        base->SIDFC |= CAN_SIDFC_FLSSA(config->address >> CAN_SIDFC_FLSSA_SHIFT) | CAN_SIDFC_LSS(config->listSize);
    }
    else
    {
        base->GFC |= CAN_GFC_RRFE(config->remFrame) | CAN_GFC_ANFE(config->nmFrame);
        base->XIDFC |= CAN_XIDFC_FLESA(config->address >> CAN_XIDFC_FLESA_SHIFT) | CAN_XIDFC_LSE(config->listSize);
    }
}

void MCAN_SetRxFifo0Config(CAN_Type *base, const mcan_rx_fifo_config_t *config)
{
    /* Set Rx FIFO 0 start address, element size, watermark, operation mode. */
    base->RXF0C |= CAN_RXF0C_F0SA(config->address >> CAN_RXF0C_F0SA_SHIFT) | CAN_RXF0C_F0S(config->elementSize) |
                   CAN_RXF0C_F0WM(config->watermark) | CAN_RXF0C_F0OM(config->opmode);
    /* Set Rx FIFO 0 data field size */
    base->RXESC |= CAN_RXESC_F0DS(config->datafieldSize);
}

void MCAN_SetRxFifo1Config(CAN_Type *base, const mcan_rx_fifo_config_t *config)
{
    /* Set Rx FIFO 1 start address, element size, watermark, operation mode. */
    base->RXF1C |= CAN_RXF1C_F1SA(config->address >> CAN_RXF1C_F1SA_SHIFT) | CAN_RXF1C_F1S(config->elementSize) |
                   CAN_RXF1C_F1WM(config->watermark) | CAN_RXF1C_F1OM(config->opmode);
    /* Set Rx FIFO 1 data field size */
    base->RXESC |= CAN_RXESC_F1DS(config->datafieldSize);
}

void MCAN_SetRxBufferConfig(CAN_Type *base, const mcan_rx_buffer_config_t *config)
{
    /* Set Rx Buffer start address. */
    base->RXBC |= CAN_RXBC_RBSA(config->address >> CAN_RXBC_RBSA_SHIFT);
    /* Set Rx Buffer data field size */
    base->RXESC |= CAN_RXESC_RBDS(config->datafieldSize);
}

void MCAN_SetTxEventFifoConfig(CAN_Type *base, const mcan_tx_fifo_config_t *config)
{
    /* Set TX Event FIFO start address, element size, watermark. */
    base->TXEFC |= CAN_TXEFC_EFSA(config->address >> CAN_TXEFC_EFSA_SHIFT) | CAN_TXEFC_EFS(config->elementSize) |
                   CAN_TXEFC_EFWM(config->watermark);
}

void MCAN_SetTxBufferConfig(CAN_Type *base, const mcan_tx_buffer_config_t *config)
{
    assert((config->dedicatedSize + config->fqSize) <= 32U);

    /* Set Tx Buffer start address, size, fifo/queue mode. */
    base->TXBC |= CAN_TXBC_TBSA(config->address >> CAN_TXBC_TBSA_SHIFT) | CAN_TXBC_NDTB(config->dedicatedSize) |
                  CAN_TXBC_TFQS(config->fqSize) | CAN_TXBC_TFQM(config->mode);
    /* Set Tx Buffer data field size */
    base->TXESC |= CAN_TXESC_TBDS(config->datafieldSize);
}

void MCAN_SetSTDFilterElement(CAN_Type *base,
                              const mcan_frame_filter_config_t *config,
                              const mcan_std_filter_element_config_t *filter,
                              uint8_t idx)
{
    uint8_t *elementAddress = 0;
    elementAddress = (uint8_t *)(MCAN_GetMsgRAMBase(base) + config->address + idx * 4U);
    memcpy(elementAddress, filter, sizeof(*filter));
}

void MCAN_SetEXTFilterElement(CAN_Type *base,
                              const mcan_frame_filter_config_t *config,
                              const mcan_ext_filter_element_config_t *filter,
                              uint8_t idx)
{
    uint8_t *elementAddress = 0;
    elementAddress = (uint8_t *)(MCAN_GetMsgRAMBase(base) + config->address + idx * 8U);
    memcpy(elementAddress, filter, sizeof(*filter));
}

static uint32_t MCAN_GetRxFifo0ElementAddress(CAN_Type *base)
{
    uint32_t eSize;
    eSize = (base->RXESC & CAN_RXESC_F0DS_MASK) >> CAN_RXESC_F0DS_SHIFT;
    if (eSize < 5U)
    {
        eSize += 4U;
    }
    else
    {
        eSize = eSize * 4U - 10U;
    }
    return (base->RXF0C & CAN_RXF0C_F0SA_MASK) +
           ((base->RXF0S & CAN_RXF0S_F0GI_MASK) >> CAN_RXF0S_F0GI_SHIFT) * eSize * 4U;
}

static uint32_t MCAN_GetRxFifo1ElementAddress(CAN_Type *base)
{
    uint32_t eSize;
    eSize = (base->RXESC & CAN_RXESC_F1DS_MASK) >> CAN_RXESC_F1DS_SHIFT;
    if (eSize < 5U)
    {
        eSize += 4U;
    }
    else
    {
        eSize = eSize * 4U - 10U;
    }
    return (base->RXF1C & CAN_RXF1C_F1SA_MASK) +
           ((base->RXF1S & CAN_RXF1S_F1GI_MASK) >> CAN_RXF1S_F1GI_SHIFT) * eSize * 4U;
}

static uint32_t MCAN_GetRxBufferElementAddress(CAN_Type *base, uint8_t idx)
{
    assert(idx <= 63U);
    uint32_t eSize;
    eSize = (base->RXESC & CAN_RXESC_RBDS_MASK) >> CAN_RXESC_RBDS_SHIFT;
    if (eSize < 5U)
    {
        eSize += 4U;
    }
    else
    {
        eSize = eSize * 4U - 10U;
    }
    return (base->RXBC & CAN_RXBC_RBSA_MASK) + idx * eSize * 4U;
}

static uint32_t MCAN_GetTxBufferElementAddress(CAN_Type *base, uint8_t idx)
{
    assert(idx <= 31U);
    uint32_t eSize;
    eSize = (base->TXESC & CAN_TXESC_TBDS_MASK) >> CAN_TXESC_TBDS_SHIFT;
    if (eSize < 5U)
    {
        eSize += 4U;
    }
    else
    {
        eSize = eSize * 4U - 10U;
    }
    return (base->TXBC & CAN_TXBC_TBSA_MASK) + idx * eSize * 4U;
}

uint32_t MCAN_IsTransmitRequestPending(CAN_Type *base, uint8_t idx)
{
    return (base->TXBRP & (uint32_t)(1U << idx)) >> (uint32_t)idx;
}

uint32_t MCAN_IsTransmitOccurred(CAN_Type *base, uint8_t idx)
{
    return (base->TXBTO & (uint32_t)(1U << idx)) >> (uint32_t)idx;
}

status_t MCAN_WriteTxBuffer(CAN_Type *base, uint8_t idx, const mcan_tx_buffer_frame_t *txFrame)
{
    if (!MCAN_IsTransmitRequestPending(base, idx))
    {
        uint8_t *elementAddress = 0;
        elementAddress = (uint8_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetTxBufferElementAddress(base, idx));

        /* Write 2 words configuration field. */
        memcpy(elementAddress, (uint8_t *)txFrame, 8U);
        /* Write data field. */
        memcpy(elementAddress + 8U, txFrame->data, txFrame->size);
        return kStatus_Success;
    }
    else
    {
        return kStatus_Fail;
    }
}

status_t MCAN_ReadRxBuffer(CAN_Type *base, uint8_t idx, mcan_rx_buffer_frame_t *rxFrame)
{
    mcan_rx_buffer_frame_t *elementAddress = 0;
    elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxBufferElementAddress(base, idx));
    memcpy(rxFrame, elementAddress, (rxFrame->size + 8U) * 4U);
    return kStatus_Success;
}

status_t MCAN_ReadRxFifo(CAN_Type *base, uint8_t fifoBlock, mcan_rx_buffer_frame_t *rxFrame)
{
    assert((fifoBlock == 0) || (fifoBlock == 1U));
    mcan_rx_buffer_frame_t *elementAddress = 0;
    if (0 == fifoBlock)
    {
        elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxFifo0ElementAddress(base));
    }
    else
    {
        elementAddress = (mcan_rx_buffer_frame_t *)(MCAN_GetMsgRAMBase(base) + MCAN_GetRxFifo1ElementAddress(base));
    }
    memcpy(rxFrame, elementAddress, 8U);
    rxFrame->data = (uint8_t *)elementAddress + 8U;
	
    /* Acknowledge the read. */
    if (0 == fifoBlock)
    {
        base->RXF0A = (base->RXF0S & CAN_RXF0S_F0GI_MASK) >> CAN_RXF0S_F0GI_SHIFT;
    }
    else
    {
        base->RXF1A = (base->RXF1S & CAN_RXF1S_F1GI_MASK) >> CAN_RXF1S_F1GI_SHIFT;
    }
    return kStatus_Success;
}

status_t MCAN_TransferSendBlocking(CAN_Type *base, uint8_t idx, mcan_tx_buffer_frame_t *txFrame)
{
    if (kStatus_Success == MCAN_WriteTxBuffer(base, idx, txFrame))
    {
        MCAN_TransmitAddRequest(base, idx);

        /* Wait until message sent out. */
        while (!MCAN_IsTransmitOccurred(base, idx))
        {
        }
        return kStatus_Success;
    }
    else
    {
        return kStatus_Fail;
    }
}

status_t MCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t bufferIdx, mcan_rx_buffer_frame_t *rxFrame)
{
    assert(bufferIdx <= 63U);

    while (!MCAN_GetRxBufferStatusFlag(base, bufferIdx))
    {
    }
    MCAN_ClearRxBufferStatusFlag(base, bufferIdx);
    return MCAN_ReadRxBuffer(base, bufferIdx, rxFrame);
}

status_t MCAN_TransferReceiveFifoBlocking(CAN_Type *base, uint8_t fifoBlock, mcan_rx_buffer_frame_t *rxFrame)
{
    assert((fifoBlock == 0) || (fifoBlock == 1U));
    if (0 == fifoBlock)
    {
        while (!MCAN_GetStatusFlag(base, CAN_IR_RF0N_MASK))
        {
        }
        MCAN_ClearStatusFlag(base, CAN_IR_RF0N_MASK);
    }
    else
    {
        while (!MCAN_GetStatusFlag(base, CAN_IR_RF1N_MASK))
        {
        }
        MCAN_ClearStatusFlag(base, CAN_IR_RF1N_MASK);
    }
    return MCAN_ReadRxFifo(base, fifoBlock, rxFrame);
}

void MCAN_TransferCreateHandle(CAN_Type *base, mcan_handle_t *handle, mcan_transfer_callback_t callback, void *userData)
{
    assert(handle);

    uint8_t instance;

    /* Clean MCAN transfer handle. */
    memset(handle, 0, sizeof(*handle));

    /* Get instance from peripheral base address. */
    instance = MCAN_GetInstance(base);

    /* Save the context in global variables to support the double weak mechanism. */
    s_mcanHandle[instance] = handle;

    /* Register Callback function. */
    handle->callback = callback;
    handle->userData = userData;

    s_mcanIsr = MCAN_TransferHandleIRQ;

    /* We Enable Error & Status interrupt here, because this interrupt just
     * report current status of MCAN module through Callback function.
     * It is insignificance without a available callback function.
     */
    if (handle->callback != NULL)
    {
        MCAN_EnableInterrupts(base, 0,
                              kMCAN_BusOffInterruptEnable | kMCAN_ErrorInterruptEnable | kMCAN_WarningInterruptEnable | CAN_IE_PEDE_MASK | CAN_IE_PEAE_MASK);
    }
    else
    {
        MCAN_DisableInterrupts(base,
                               kMCAN_BusOffInterruptEnable | kMCAN_ErrorInterruptEnable | kMCAN_WarningInterruptEnable | CAN_IE_PEDE_MASK | CAN_IE_PEAE_MASK);
    }

    /* Enable interrupts in NVIC. */
    EnableIRQ((IRQn_Type)(s_mcanIRQ[instance][0]));
    EnableIRQ((IRQn_Type)(s_mcanIRQ[instance][1]));
}

status_t MCAN_TransferSendNonBlocking(CAN_Type *base, mcan_handle_t *handle, mcan_buffer_transfer_t *xfer)
{
    /* Assertion. */
    assert(handle);
    assert(xfer);
    assert(xfer->bufferIdx <= 63U);

    /* Check if Tx Buffer is idle. */
    if (kMCAN_StateIdle == handle->bufferState[xfer->bufferIdx])
    {
        handle->txbufferIdx = xfer->bufferIdx;
        /* Distinguish transmit type. */
        if (kMCAN_FrameTypeRemote == xfer->frame->xtd)
        {
            handle->bufferState[xfer->bufferIdx] = kMCAN_StateTxRemote;

            /* Register user Frame buffer to receive remote Frame. */
            handle->bufferFrameBuf[xfer->bufferIdx] = xfer->frame;
        }
        else
        {
            handle->bufferState[xfer->bufferIdx] = kMCAN_StateTxData;
        }
		
        if (kStatus_Success == MCAN_WriteTxBuffer(base, xfer->bufferIdx, xfer->frame))
        {
            /* Enable Buffer Interrupt. */
            MCAN_EnableTransmitBufferInterrupts(base, xfer->bufferIdx);
            MCAN_EnableInterrupts(base, 0, CAN_IE_TCE_MASK);

            MCAN_TransmitAddRequest(base, xfer->bufferIdx);

            return kStatus_Success;
        }
        else
        {
            handle->bufferState[xfer->bufferIdx] = kMCAN_StateIdle;
            return kStatus_Fail;
        }
    }
    else
    {
        return kStatus_MCAN_TxBusy;
    }
}

/* modify by zwc 20191230 */
#if 0
status_t MCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
                                             uint8_t fifoBlock,
                                             mcan_handle_t *handle,
                                             mcan_fifo_transfer_t *xfer)
{
    /* Assertion. */
    assert((fifoBlock == 0) || (fifoBlock == 1U));
    assert(handle);
    assert(xfer);

    /* Check if Message Buffer is idle. */
    if (kMCAN_StateIdle == handle->rxFifoState)
    {
        handle->rxFifoState = kMCAN_StateRxFifo;

        /* Register Message Buffer. */
        handle->rxFifoFrameBuf = xfer->frame;

        /* Enable FIFO Interrupt. */
        if (fifoBlock)
        {
            MCAN_EnableInterrupts(base, 0, CAN_IE_RF1NE_MASK);
        }
        else
        {
            MCAN_EnableInterrupts(base, 0, CAN_IE_RF0NE_MASK);
        }
        return kStatus_Success;
    }
    else
    {
        return fifoBlock ? kStatus_MCAN_RxFifo1Busy : kStatus_MCAN_RxFifo0Busy;
    }
}
#endif

/* add by zwc 20191230 */
status_t MCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
                                             uint8_t fifoBlock,
                                             mcan_handle_t *handle,
                                             mcan_fifo_transfer_t *xfer)
{
    /* Assertion. */
    assert((fifoBlock == 0) || (fifoBlock == 1U));
    assert(handle);
    assert(xfer);

	if (fifoBlock)
	{
		/* Check if Message Buffer is idle. */
		if (kMCAN_StateIdle == handle->rxFifo1State)
		{
		    handle->rxFifo1State = kMCAN_StateRxFifo;

		    /* Register Message Buffer. */
		    handle->rxFifo1FrameBuf = xfer->frame;

		    /* Enable FIFO Interrupt. */
		    MCAN_EnableInterrupts(base, 0, CAN_IE_RF1NE_MASK);
		    return kStatus_Success;
		}
		else
		{
		    return kStatus_MCAN_RxFifo1Busy;
		}
	}
	else
	{
		/* Check if Message Buffer is idle. */
		if (kMCAN_StateIdle == handle->rxFifo0State)
		{
		    handle->rxFifo0State = kMCAN_StateRxFifo;

		    /* Register Message Buffer. */
		    handle->rxFifo0FrameBuf = xfer->frame;

		    /* Enable FIFO Interrupt. */
		    MCAN_EnableInterrupts(base, 0, CAN_IE_RF0NE_MASK);
		    return kStatus_Success;
		}
		else
		{
		    return kStatus_MCAN_RxFifo0Busy;
		}
	}
}

void MCAN_TransferAbortSend(CAN_Type *base, mcan_handle_t *handle, uint8_t bufferIdx)
{
    /* Assertion. */
    assert(handle);
    assert(bufferIdx <= 63U);

    /* Disable Buffer Interrupt. */
    MCAN_DisableTransmitBufferInterrupts(base, bufferIdx);
    MCAN_DisableInterrupts(base, CAN_IE_TCE_MASK);

    /* Cancel send request. */
    MCAN_TransmitCancelRequest(base, bufferIdx);

    /* Un-register handle. */
    handle->bufferFrameBuf[bufferIdx] = 0x0;

    handle->bufferState[bufferIdx] = kMCAN_StateIdle;
}

/* modify by zwc 20191230 */
#if 0
void MCAN_TransferAbortReceiveFifo(CAN_Type *base, uint8_t fifoBlock, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(handle);
    assert((fifoBlock == 0) || (fifoBlock == 1));

    /* Check if Rx FIFO is enabled. */
    if (fifoBlock)
    {
        /* Disable Rx Message FIFO Interrupts. */
        MCAN_DisableInterrupts(base, CAN_IE_RF1NE_MASK);
    }
    else
    {
        MCAN_DisableInterrupts(base, CAN_IE_RF0NE_MASK);
    }
    /* Un-register handle. */
    handle->rxFifoFrameBuf = 0x0;

    handle->rxFifoState = kMCAN_StateIdle;
}
#endif

/* add by zwc 20191230 */
void MCAN_TransferAbortReceiveFifo(CAN_Type *base, uint8_t fifoBlock, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(handle);
    assert((fifoBlock == 0) || (fifoBlock == 1));

    /* Check if Rx FIFO is enabled. */
    if (fifoBlock)
    {
        /* Disable Rx Message FIFO Interrupts. */
        MCAN_DisableInterrupts(base, CAN_IE_RF1NE_MASK);
		/* Un-register handle. */
    	handle->rxFifo1FrameBuf = 0x0;
		handle->rxFifo1State = kMCAN_StateIdle;
    }
    else
    {
        MCAN_DisableInterrupts(base, CAN_IE_RF0NE_MASK);
		/* Un-register handle. */
    	handle->rxFifo0FrameBuf = 0x0;
		handle->rxFifo0State = kMCAN_StateIdle;
    }
}
#include <drv_log.h>
void MCAN_TransferHandleIRQ(CAN_Type *base, mcan_handle_t *handle)
{
    /* Assertion. */
    assert(handle);

    status_t status = kStatus_MCAN_UnHandled;
    uint32_t result;

    /* Store Current MCAN Module Error and Status. */
    result = base->IR;

//	LOG_E("can ir reg %04x\r\n",result);
    do
    {
        /* Solve Rx FIFO, Tx interrupt. */
        if (result & kMCAN_TxTransmitCompleteFlag)
        {
            status = kStatus_MCAN_TxIdle;
            MCAN_TransferAbortSend(base, handle, handle->txbufferIdx);
        }
        else if (result & kMCAN_RxFifo0NewFlag)
        {
            MCAN_ReadRxFifo(base, 0, handle->rxFifo0FrameBuf);	//modify by zwc 20191230
            status = kStatus_MCAN_RxFifo0Idle;
            MCAN_TransferAbortReceiveFifo(base, 0, handle);
        }
        else if (result & kMCAN_RxFifo0LostFlag)
        {
            status = kStatus_MCAN_RxFifo0Lost;
        }
        else if (result & kMCAN_RxFifo1NewFlag)
        {
            MCAN_ReadRxFifo(base, 1, handle->rxFifo1FrameBuf);	//modify by zwc 20191230
            status = kStatus_MCAN_RxFifo1Idle;
            MCAN_TransferAbortReceiveFifo(base, 1, handle);
        }
        else if (result & kMCAN_RxFifo1LostFlag)
        {
            status = kStatus_MCAN_RxFifo1Lost;	//modify by zwc 20191230  kStatus_MCAN_RxFifo0Lost ?? fsl lib bug
        }
		else if( result & CAN_IR_BO_MASK ){
			status = kStatus_MCAN_BusOffStatus;
		}
		else if( result & kMCAN_TxTransmitProtocolErrorDataFlag ){
			status = kStatus_MCAN_ErrorStatus;
		}
		else if( result & kMCAN_TxTransmitProtocolErrorArbitrationFlag ){
			status = kStatus_MCAN_ErrorStatus;
		}
        else
        {
            ;
        }

        /* Clear resolved Rx FIFO, Tx Buffer IRQ. */
        MCAN_ClearStatusFlag(base, result);

        /* Calling Callback Function if has one. */
        if (handle->callback != NULL)
        {
            handle->callback(base, handle, status, result, handle->userData);
        }

        /* Reset return status */
        status = kStatus_MCAN_UnHandled;

        /* Store Current MCAN Module Error and Status. */
        result = base->IR;
    } while ((0 != MCAN_GetStatusFlag(base, 0xFFFFFFFFU)) ||
             (0 != (result & (kMCAN_ErrorWarningIntFlag | kMCAN_BusOffIntFlag | kMCAN_ErrorPassiveIntFlag))));
}

#if defined(CAN0)
void CAN0_IRQ0_DriverIRQHandler(void)
{
    assert(s_mcanHandle[0]);

    s_mcanIsr(CAN0, s_mcanHandle[0]);
}

void CAN0_IRQ1_DriverIRQHandler(void)
{
    assert(s_mcanHandle[0]);

    s_mcanIsr(CAN0, s_mcanHandle[0]);
}
#endif

#if defined(CAN1)
void CAN1_IRQ0_DriverIRQHandler(void)
{
    assert(s_mcanHandle[1]);

    s_mcanIsr(CAN1, s_mcanHandle[1]);
}

void CAN1_IRQ1_DriverIRQHandler(void)
{
    assert(s_mcanHandle[1]);

    s_mcanIsr(CAN1, s_mcanHandle[1]);
}
#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵向深耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值