一、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