LPC54616 基于rt-thread的CAN驱动

修正lpc54616 rt-thread can驱动一些bug,可切换can与canfd通讯,补充设置波特率模式命令及掩码设置,经过10W次长时时间通讯运行测试验证

/*
 * 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
 * 2020-05-14     kun          fix some bug
 *
 */

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

#define RX_MB_COUNT     	(64U)
#define TX_MB_COUNT     	(32U)
#define FILTER_LIST_COUNT	(64U)
#define MSG_RAM_BASE 		0x04000000 			//将CAN通信缓冲放在SRAMx(0x04000000~0x04001200)
#define MSG_RAM_END			0x04001200
#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 */

#ifdef ICAN_USE_CAN_MODE
#define CAN_DRIVER_MODE							ICAN_USE_CAN_MODE
#endif

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];
static uint8_t	CAN_DATASIZE=64;

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

static const struct can_configure config = {
	.baud_rate = CAN125kBaud,
    .msgboxsz = RT_CANMSG_BOX_SZ,
    .sndboxnumber = RT_CANSND_BOX_NUM,
    #ifdef CAN_DRIVER_MODE
		#if ICAN_USE_CAN_MODE == CANFD_MODE
		.mode = RT_CAN_MODE_CANFD,
		#elif ICAN_USE_CAN_MODE == CAN_MODE
		.mode = RT_CAN_MODE_NORMAL,
		#endif
	#else
	.mode = RT_CAN_MODE_CANFD,
	#endif
	.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;
	clock_name_t clock_name;	
    IRQn_Type irqn[2];
    mcan_handle_t handle;
    struct rt_can_device can_dev;
};

struct lpc_can lpccans[] =
{
#ifdef BSP_USING_CAN0
    {
        .name = "can0",
        .base = CAN0,
        .clock_name = 0,
        .irqn = {CAN0_IRQ0_IRQn, CAN0_IRQ1_IRQn},
		.can_dev.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
		},
    },
#endif
#ifdef BSP_USING_CAN1
    {
        .name = "can1",
        .base = CAN1,
        .clock_name = 1,
        .irqn = {CAN1_IRQ0_IRQn, CAN1_IRQ1_IRQn},
		.can_dev.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
		},
    },
#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->handle.txbufferIdx);
			rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | can->handle.txbufferIdx << 8);
		}
        break;

    default:
		//发生未定义的需记录入log文件
		LOG_E("Undef interupt handle %08x\r\n",status);
//		rt_kprintf("Undef interupt handle 0x%0d\r\n",status);
		//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_GetMCanClkFreq(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;
		CAN_DATASIZE = 8;
		
		if (MCAN_CalculateImprovedTimingValues(mcanConfig.baudRateA, CLOCK_GetMCanClkFreq(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;
		CAN_DATASIZE = 64;
		
		if (MCAN_FDCalculateImprovedTimingValues(mcanConfig.baudRateA, mcanConfig.baudRateD, CLOCK_GetMCanClkFreq(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_GetMCanClkFreq(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_GetMCanClkFreq(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);
    rt_memset(p, 0, sizeof(msg_ram));//(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;
    if( cfg->mode == RT_CAN_MODE_NORMAL )
		rxFifo0.datafieldSize = kMCAN_8ByteDatafield;
	else if( cfg->mode == RT_CAN_MODE_CANFD )
		rxFifo0.datafieldSize = kMCAN_64ByteDatafield;
	else
		rxFifo0.datafieldSize = kMCAN_64ByteDatafield;
    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;
    if( cfg->mode == RT_CAN_MODE_NORMAL )
		rxFifo1.datafieldSize = kMCAN_8ByteDatafield;
	else if( cfg->mode == RT_CAN_MODE_CANFD )
		rxFifo1.datafieldSize = kMCAN_64ByteDatafield;
	else
		rxFifo1.datafieldSize = kMCAN_64ByteDatafield;
    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;
    if( cfg->mode == RT_CAN_MODE_NORMAL )
		txBuffer.datafieldSize = kMCAN_8ByteDatafield;
	else if( cfg->mode == RT_CAN_MODE_CANFD )
		txBuffer.datafieldSize = kMCAN_64ByteDatafield;
	else
		txBuffer.datafieldSize = kMCAN_64ByteDatafield;
    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_GetMCanClkFreq(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_GetMCanClkFreq(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_GetMCanClkFreq(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_GetMCanClkFreq(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[64],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;
	if( config.mode == RT_CAN_MODE_CANFD ){
		txFrame.fdf = 1;
		txFrame.brs = 1;
	}
	else if( config.mode == RT_CAN_MODE_NORMAL ){
		txFrame.fdf = 0;
		txFrame.brs = 0;
	}
	else{
		txFrame.fdf = 1;
		txFrame.brs = 1;
	}
	txFrame.size = msg->len;
	txFrame.data = tx_data;
    
    txXfer.frame     = &txFrame;
    txXfer.bufferIdx = (uint8_t)boxno;

    uint8_t re_send=0;
	do{
		ret = MCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
		if( ret != kStatus_Success ){
			MCAN_TransferAbortSend(can->base, &can->handle, boxno);
			rt_thread_delay(1);
		}
	}while(ret!=kStatus_Success && re_send++<10 );
	
	if( ret != kStatus_Success ){
		rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | boxno << 8);
	}

    return RT_EOK;
}

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 <= CAN_DATASIZE ){
		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 const 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 result = 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;
        result = rt_hw_can_register((struct rt_can_device *)&lpccans[i].can_dev, lpccans[i].name, &lpc_can_ops,(void*)&lpccans[i]);
		
		char buf[30];
		snprintf(buf,30,"%s device initialize",lpccans[i].name);
		module_init_result(buf,result);
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

纵向深耕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值