修正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 */