674 lines
22 KiB
C
674 lines
22 KiB
C
/*
|
|
* Copyright (c) 2006-2024, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2024-08-22 QT-one first version
|
|
*/
|
|
|
|
#include <rtdbg.h>
|
|
#include "drv_can.h"
|
|
#include "ht32_can_config.h"
|
|
|
|
#ifdef BSP_USING_CAN
|
|
#if !defined(BSP_USING_CAN)
|
|
#error "Please define at least one BSP_USING_CAN"
|
|
#endif
|
|
|
|
#define CAN_UMASK_MODE 0
|
|
#define CAN_MASK_MODE 1
|
|
|
|
struct ht32_can_msg_type
|
|
{
|
|
CAN_MSG_TypeDef cfg_msg;
|
|
uint32_t data_len;
|
|
uint8_t data[8];
|
|
};
|
|
|
|
/* Baud rate mapping structure */
|
|
struct ht32_baud_rate
|
|
{
|
|
enum CANBAUD rt_baud_rate;
|
|
uint32_t us_baus_rate;
|
|
};
|
|
/* CAN Filter Table Configuration Structure */
|
|
struct ht32_can_filter_config
|
|
{
|
|
/* Each bit represents a message;1: the message is occupied;0: the message is not occupied */
|
|
uint32_t filter_flag;
|
|
/* Filter table configuration information */
|
|
CAN_MSG_TypeDef filter_mag[MSG_OBJ_TOTAL_NUM];
|
|
};
|
|
/* CAN Object Structures */
|
|
struct ht32_can
|
|
{
|
|
char *name; /* Equipment name */
|
|
HT_CAN_TypeDef *can_x; /* peripheral base address */
|
|
struct can_configure cfg; /* CAN Configuration Structure */
|
|
struct rt_can_device device; /* Inherited device options */
|
|
struct ht32_can_filter_config filter_cfg; /* Filter Table Configuration */
|
|
};
|
|
/* CAN Baud Rate Mapping Table */
|
|
static const struct ht32_baud_rate can_baud_rate_tab[] =
|
|
{
|
|
{CAN1MBaud, 1000000},
|
|
{CAN800kBaud, 800000},
|
|
{CAN500kBaud, 500000},
|
|
{CAN250kBaud, 250000},
|
|
{CAN125kBaud, 125000},
|
|
{CAN100kBaud, 100000},
|
|
{CAN50kBaud, 50000},
|
|
{CAN20kBaud, 20000},
|
|
{CAN10kBaud, 10000},
|
|
};
|
|
/* CAN Object Information */
|
|
static struct ht32_can ht32_can_config =
|
|
{
|
|
.name = BSP_USING_CAN_NAME,
|
|
.can_x = HT_CAN0,
|
|
.cfg = {0},
|
|
.device = RT_NULL,
|
|
.filter_cfg = {0},
|
|
};
|
|
/**
|
|
* @brief Default Filter Table Configuration
|
|
* @param can_instance:CAN object
|
|
* @retval
|
|
*/
|
|
static rt_uint32_t cfg_can_default_filter(struct ht32_can *can_instance)
|
|
{
|
|
uint8_t filter_num = BSP_USING_CAN_MSG_NUM;
|
|
can_instance->filter_cfg.filter_flag |= 1 << filter_num;
|
|
can_instance->filter_cfg.filter_mag[filter_num].MsgNum = filter_num + 1;
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdType = (CAN_IdType_Enum)BSP_USING_CAN_ID_MODE;
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdMask = BSP_USING_CAN_MASK;
|
|
can_instance->filter_cfg.filter_mag[filter_num].FrameType = (CAN_FrameType_Enum)BSP_USING_CAN_FRAME_MODE;
|
|
can_instance->filter_cfg.filter_mag[filter_num].Id = BSP_USING_CAN_ID;
|
|
CAN_SetRxMsg(can_instance->can_x, &can_instance->filter_cfg.filter_mag[filter_num], 1);
|
|
return RT_EOK;
|
|
}
|
|
/**
|
|
* @brief Get baud rate mapping parameters for CAN
|
|
* @info This function is mainly used to convert the baud rate of RTT format to HT32 format baud rate
|
|
* @param baud:CAN baud rate in RTT format
|
|
* @retval Returns the CAN baud rate in HT32 format.
|
|
*/
|
|
static rt_uint32_t get_can_baud_index(rt_uint32_t baud)
|
|
{
|
|
rt_uint32_t len, index;
|
|
|
|
len = sizeof(can_baud_rate_tab) / sizeof(can_baud_rate_tab[0]);
|
|
for (index = 0; index < len; index++)
|
|
{
|
|
if (can_baud_rate_tab[index].rt_baud_rate == baud)
|
|
return can_baud_rate_tab[index].us_baus_rate;
|
|
}
|
|
return 0;
|
|
}
|
|
/**
|
|
* @brief Configuring CAN Structures
|
|
* @info This function depends on the ht32_can_config.h file
|
|
* @param can_ck:System clock for CAN
|
|
* @param can_buad:CAN baud rate to be configured
|
|
* @param mode:Modes of CAN
|
|
* @param nart:enable or disable the no automatic retransmission
|
|
* @param CAN_InitStruct:Structures to be configured
|
|
* @retval 1:success;0:error
|
|
*/
|
|
static rt_uint32_t config_can_struct(uint32_t can_ck,
|
|
uint32_t can_buad,
|
|
uint8_t mode,
|
|
ControlStatus nart,
|
|
CAN_InitTypeDef* CAN_InitStruct)
|
|
{
|
|
uint8_t cf0_nbt = 0;
|
|
uint32_t nominal_bit_time = 0;
|
|
|
|
for (cf0_nbt = 25; cf0_nbt > 8; cf0_nbt--)
|
|
{
|
|
if ((can_ck / can_buad / cf0_nbt) > 0)
|
|
{
|
|
if (((can_ck / (can_ck / can_buad / cf0_nbt)) / cf0_nbt) <= can_buad)
|
|
{
|
|
nominal_bit_time = cf0_nbt;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (cf0_nbt < 8)
|
|
{
|
|
return 0;
|
|
}
|
|
CAN_InitStruct->CAN_BRPrescaler = (can_ck / (can_buad * nominal_bit_time));
|
|
CAN_InitStruct->CAN_SJW = HTCFG_CAN_CF0_BIT_TIME_SJW;
|
|
CAN_InitStruct->CAN_TSEG1 = (nominal_bit_time - (nominal_bit_time * HTCFG_CAN_CF0_SAMPLE_POINT) / 100);
|
|
CAN_InitStruct->CAN_TSEG0 = (nominal_bit_time - 1 - CAN_InitStruct->CAN_TSEG1);
|
|
CAN_InitStruct->CAN_NART = nart;
|
|
CAN_InitStruct->CAN_Mode = mode;
|
|
return 1;
|
|
}
|
|
/**
|
|
* @brief CAN Configuration Functions
|
|
* @param
|
|
* @retval
|
|
*/
|
|
static rt_err_t ht32_can_configure(struct rt_can_device *can, struct can_configure *cfg)
|
|
{
|
|
CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
|
|
struct ht32_can *can_instance = RT_NULL;
|
|
rt_uint32_t can_baud = 0;
|
|
rt_uint8_t can_mode = 0;
|
|
CAN_InitTypeDef CAN_InitStruct = {0};
|
|
|
|
RT_ASSERT(can);
|
|
RT_ASSERT(cfg);
|
|
can_instance = (struct ht32_can *)can->parent.user_data;
|
|
RT_ASSERT(can_instance != RT_NULL);
|
|
|
|
CKCUClock.Bit.AFIO = 1;
|
|
CKCUClock.Bit.CAN0 = 1;
|
|
CKCU_PeripClockConfig(CKCUClock, ENABLE);
|
|
|
|
ht32_can_gpio_init(can_instance->can_x);
|
|
|
|
/* Get baud rate */
|
|
can_baud = get_can_baud_index(cfg->baud_rate);
|
|
if (can_baud == 0)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
can_instance->cfg.baud_rate = cfg->baud_rate;
|
|
can_instance->cfg.mode = cfg->mode;
|
|
|
|
/* Configuring the operating mode of CAN */
|
|
switch (cfg->mode)
|
|
{
|
|
case RT_CAN_MODE_NORMAL:
|
|
can_mode = CAN_MODE_NORMAL;
|
|
break;
|
|
case RT_CAN_MODE_LISTEN:
|
|
can_mode = CAN_MODE_SILENT;
|
|
break;
|
|
case RT_CAN_MODE_LOOPBACK:
|
|
can_mode = CAN_MODE_LBACK;
|
|
break;
|
|
case RT_CAN_MODE_LOOPBACKANLISTEN:
|
|
can_mode = CAN_MODE_SILENT | CAN_MODE_LBACK;
|
|
break;
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
if (0 == (config_can_struct(_HTCFG_CF0_CK_CAN, can_baud, can_mode, DISABLE, &CAN_InitStruct)))
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
/* Reset CAN */
|
|
CAN_DeInit(can_instance->can_x);
|
|
/* Initialising CAN */
|
|
CAN_Init(can_instance->can_x, &CAN_InitStruct);
|
|
|
|
/* Configuring the Default Filter for CAN */
|
|
cfg_can_default_filter(can_instance);
|
|
|
|
return RT_EOK;
|
|
}
|
|
/**
|
|
* @brief CAN Control Functions
|
|
* @param
|
|
* @retval
|
|
*/
|
|
rt_err_t ht32_can_control(struct rt_can_device *can, int cmd, void *arg)
|
|
{
|
|
rt_uint32_t argval;
|
|
struct ht32_can *can_instance;
|
|
struct rt_can_filter_config *filter_cfg;
|
|
|
|
RT_ASSERT(can != RT_NULL);
|
|
can_instance = (struct ht32_can *)can->parent.user_data;
|
|
RT_ASSERT(can_instance != RT_NULL);
|
|
|
|
switch (cmd)
|
|
{
|
|
case RT_DEVICE_CTRL_CLR_INT:/* Clear Interrupt */
|
|
{
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval == RT_DEVICE_FLAG_INT_RX) /* receive interruptions */
|
|
{
|
|
if (CAN_GetFlagStatus(can_instance->can_x, CAN_FLAG_RXOK))
|
|
{
|
|
/* Clear RXOK Flag */
|
|
CAN_ClearFlag(can_instance->can_x, CAN_FLAG_RXOK);
|
|
}
|
|
}
|
|
else if (argval == RT_DEVICE_FLAG_INT_TX) /* Send Interrupt */
|
|
{
|
|
if (CAN_GetFlagStatus(can_instance->can_x, CAN_FLAG_TXOK))
|
|
{
|
|
/* Clear TXOK flag*/
|
|
CAN_ClearFlag(can_instance->can_x, CAN_FLAG_TXOK);
|
|
}
|
|
}
|
|
else if (argval == RT_DEVICE_CAN_INT_ERR) /* false interruption */
|
|
{
|
|
/* Error Process*/
|
|
CAN_LastErrorCode_TypeDef lec = CAN_GetLastErrorCode(can_instance->can_x);
|
|
if (lec != NO_ERROR)
|
|
{
|
|
LOG_W("LEC: %d\r\n", lec);
|
|
}
|
|
if (CAN_GetFlagStatus(can_instance->can_x, CAN_FLAG_BOFF))
|
|
{
|
|
/* Recover from Bus off state.*/
|
|
CAN_BusOffRecovery(can_instance->can_x);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case RT_DEVICE_CTRL_SET_INT:/* Setting Up Interruptions */
|
|
{
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval == RT_DEVICE_FLAG_INT_RX) /* interrupt receive mode */
|
|
{
|
|
LOG_W("Configuring Receive Interrupts!\r\n");
|
|
CAN_IntConfig(can_instance->can_x, CAN_INT_EIE | CAN_INT_SIE | CAN_INT_IE, ENABLE);
|
|
NVIC_EnableIRQ(CAN0_IRQn);
|
|
}
|
|
else if (argval == RT_DEVICE_FLAG_INT_TX) /* interrupt transmission mode */
|
|
{
|
|
LOG_W("Configuring Transmit Interrupts!\r\n");
|
|
}
|
|
else if (argval == RT_DEVICE_CAN_INT_ERR) /* false interruption */
|
|
{
|
|
LOG_W("Configuration error interrupt!\r\n");
|
|
}
|
|
break;
|
|
}
|
|
case RT_CAN_CMD_SET_FILTER:/* Configuring the Hardware Filter Table */
|
|
{
|
|
int i = 0;
|
|
uint8_t filter_num = 0;
|
|
uint32_t idmask = 0;
|
|
if (RT_NULL == arg)
|
|
{
|
|
/* default filter config */
|
|
cfg_can_default_filter(can_instance);
|
|
}
|
|
else
|
|
{
|
|
filter_cfg = (struct rt_can_filter_config *)arg;
|
|
if (filter_cfg->count > MSG_OBJ_TOTAL_NUM)
|
|
{
|
|
LOG_W("Filter list length exceeds the limit(max 32)!");
|
|
return -RT_ERROR;
|
|
}
|
|
for (i = 0; i < filter_cfg->count; i++)
|
|
{
|
|
/* Specify the filter table number or no */
|
|
if (filter_cfg->items[i].hdr_bank == -1)
|
|
{
|
|
filter_num = i;
|
|
}
|
|
else
|
|
{
|
|
if (filter_cfg->items[i].hdr_bank > MSG_OBJ_TOTAL_NUM)
|
|
{
|
|
LOG_W("Filter List Number Out of Limits(1-32)!");
|
|
return -RT_ERROR;
|
|
}
|
|
else
|
|
{
|
|
filter_num = filter_cfg->items[i].hdr_bank;
|
|
}
|
|
}
|
|
if (can_instance->filter_cfg.filter_flag & (1 << filter_num))
|
|
{
|
|
LOG_W("This filter channel will be changed(num:%d)!", filter_num);
|
|
rt_kprintf("This filter channel will be changed(num:%d)!", filter_num);
|
|
}
|
|
can_instance->filter_cfg.filter_flag |= 1 << filter_num;
|
|
can_instance->filter_cfg.filter_mag[filter_num].MsgNum = filter_num + 1;
|
|
|
|
/* Standard or Extended Frames */
|
|
if (filter_cfg->items[i].ide == RT_CAN_STDID)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdType = CAN_STD_ID;
|
|
idmask = 0x7FF;
|
|
}
|
|
else if (filter_cfg->items[i].ide == RT_CAN_EXTID)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdType = CAN_EXT_ID;
|
|
idmask = 0x1FFFFFFF;
|
|
}
|
|
else
|
|
{
|
|
LOG_W("Frame pattern error(CAN_STD_ID/CAN_EXT_ID)!");
|
|
return -RT_ERROR;
|
|
}
|
|
/* Whether to use MASK mode */
|
|
if (filter_cfg->items[i].mode == CAN_UMASK_MODE)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdMask = idmask;
|
|
}
|
|
else if (filter_cfg->items[i].mode == CAN_MASK_MODE)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].IdMask = filter_cfg->items[i].mask;
|
|
}
|
|
else
|
|
{
|
|
LOG_W("MASK mode error(CAN_UMASK_MODE/CAN_MASK_MODE)!");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/* Remote frames or data frames */
|
|
if (filter_cfg->items[i].rtr == RT_CAN_RTR)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].FrameType = CAN_REMOTE_FRAME;
|
|
}
|
|
else if (filter_cfg->items[i].rtr == RT_CAN_DTR)
|
|
{
|
|
can_instance->filter_cfg.filter_mag[filter_num].FrameType = CAN_DATA_FRAME;
|
|
}
|
|
/* Setting ID */
|
|
can_instance->filter_cfg.filter_mag[filter_num].Id = filter_cfg->items[i].id;
|
|
/* Setting up the CAN filter table */
|
|
CAN_SetRxMsg(can_instance->can_x, &can_instance->filter_cfg.filter_mag[filter_num], 1);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case RT_CAN_CMD_SET_BAUD:/* Setting the baud rate */
|
|
{
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval != CAN1MBaud &&
|
|
argval != CAN800kBaud &&
|
|
argval != CAN500kBaud &&
|
|
argval != CAN250kBaud &&
|
|
argval != CAN125kBaud &&
|
|
argval != CAN100kBaud &&
|
|
argval != CAN50kBaud &&
|
|
argval != CAN20kBaud &&
|
|
argval != CAN10kBaud)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
if (argval != can_instance->cfg.baud_rate)
|
|
{
|
|
can_instance->cfg.baud_rate = argval;
|
|
return ht32_can_configure(&can_instance->device, &can_instance->cfg);
|
|
}
|
|
break;
|
|
}
|
|
case RT_CAN_CMD_SET_MODE:/* Setting the CAN Operating Mode */
|
|
{
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval != RT_CAN_MODE_NORMAL &&
|
|
argval != RT_CAN_MODE_LISTEN &&
|
|
argval != RT_CAN_MODE_LOOPBACK &&
|
|
argval != RT_CAN_MODE_LOOPBACKANLISTEN)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
if (argval != can_instance->cfg.mode)
|
|
{
|
|
can_instance->cfg.mode = argval;
|
|
return ht32_can_configure(&can_instance->device, &can_instance->cfg);
|
|
}
|
|
break;
|
|
}
|
|
case RT_CAN_CMD_GET_STATUS:/* Get CAN device status */
|
|
{
|
|
rt_uint32_t errtype;
|
|
|
|
errtype = can_instance->can_x->ECR;
|
|
can_instance->device.status.rcverrcnt = ((errtype >> 8) & 0x7f);
|
|
can_instance->device.status.snderrcnt = (errtype & 0xff);
|
|
|
|
errtype = can_instance->can_x->SR;
|
|
can_instance->device.status.lasterrtype = (errtype & 0x07);
|
|
can_instance->device.status.errcode = ((errtype >> 5) & 0x07);
|
|
|
|
rt_memcpy(arg, &can_instance->device.status, sizeof(can_instance->device.status));
|
|
break;
|
|
}
|
|
default:
|
|
return -RT_ERROR;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
/**
|
|
* @brief CAN sends data
|
|
* @param
|
|
* @retval
|
|
*/
|
|
rt_ssize_t ht32_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
|
|
{
|
|
struct ht32_can *can_instance = RT_NULL;
|
|
struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
|
|
struct ht32_can_msg_type tx_msg = {0};
|
|
|
|
RT_ASSERT(can != RT_NULL);
|
|
can_instance = (struct ht32_can *)can->parent.user_data;
|
|
RT_ASSERT(can_instance != RT_NULL);
|
|
|
|
/* Standard and Extended Frames */
|
|
if (CAN_STD_ID == pmsg->ide)
|
|
{
|
|
tx_msg.cfg_msg.IdType = CAN_STD_ID;
|
|
tx_msg.cfg_msg.Id = pmsg->id;
|
|
}
|
|
else if (CAN_EXT_ID == pmsg->ide)
|
|
{
|
|
tx_msg.cfg_msg.IdType = CAN_EXT_ID;
|
|
tx_msg.cfg_msg.Id = pmsg->id;
|
|
}
|
|
else
|
|
{
|
|
LOG_W("Frame pattern error(CAN_STD_ID/CAN_EXT_ID)!");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/* Teleframes and data frames */
|
|
if (RT_CAN_RTR == pmsg->rtr)
|
|
{
|
|
tx_msg.cfg_msg.FrameType = CAN_REMOTE_FRAME;
|
|
}
|
|
else if (RT_CAN_DTR == pmsg->rtr)
|
|
{
|
|
tx_msg.cfg_msg.FrameType = CAN_DATA_FRAME;
|
|
}
|
|
else
|
|
{
|
|
LOG_W("Remote frame setting error(CAN_REMOTE_FRAME/CAN_DATA_FRAME)!");
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
/* Length of sent data */
|
|
tx_msg.data_len = pmsg->len & 0x0FU;
|
|
/* data being sent */
|
|
tx_msg.data[0] = pmsg->data[0];
|
|
tx_msg.data[1] = pmsg->data[1];
|
|
tx_msg.data[2] = pmsg->data[2];
|
|
tx_msg.data[3] = pmsg->data[3];
|
|
tx_msg.data[4] = pmsg->data[4];
|
|
tx_msg.data[5] = pmsg->data[5];
|
|
tx_msg.data[6] = pmsg->data[6];
|
|
tx_msg.data[7] = pmsg->data[7];
|
|
|
|
/* Waiting tx Msg idle */
|
|
while (CAN_TransmitStatus(can_instance->can_x, &tx_msg.cfg_msg) == 0);
|
|
/* Loopback data */
|
|
CAN_Transmit(can_instance->can_x, &tx_msg.cfg_msg, tx_msg.data, tx_msg.data_len);
|
|
|
|
return RT_EOK;
|
|
}
|
|
/**
|
|
* @brief CAN receive data
|
|
* @param
|
|
* @retval
|
|
*/
|
|
rt_ssize_t ht32_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
|
|
{
|
|
uint8_t i = 0;
|
|
uint32_t msgnum = 0;
|
|
CAN_RxStatus_TypeDef rx_status;
|
|
struct ht32_can_msg_type rx_msg = {0};
|
|
struct ht32_can *can_instance = RT_NULL;
|
|
struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
|
|
|
|
RT_ASSERT(can != RT_NULL);
|
|
RT_ASSERT(pmsg != RT_NULL);
|
|
can_instance = (struct ht32_can *)can->parent.user_data;
|
|
RT_ASSERT(can_instance != RT_NULL);
|
|
|
|
msgnum = can_instance->filter_cfg.filter_flag;
|
|
for (i = 0; i < MSG_OBJ_TOTAL_NUM; i++)
|
|
{
|
|
if ((msgnum & 1) == 1)
|
|
{
|
|
rx_status = CAN_Receive(can_instance->can_x, &can_instance->filter_cfg.filter_mag[i], rx_msg.data, &rx_msg.data_len);
|
|
if (rx_status == MSG_OVER_RUN)
|
|
{
|
|
LOG_W("ID[%X] rx message over run\r\n", can_instance->filter_cfg.filter_mag[i].Id);
|
|
}
|
|
else if (rx_status == MSG_OBJ_NOT_SET)
|
|
{
|
|
LOG_W("rx message not set \r\n");
|
|
}
|
|
else if (rx_status == MSG_RX_FINISH)
|
|
{
|
|
LOG_W("rx ok \r\n");
|
|
pmsg->data[0] = rx_msg.data[0];
|
|
pmsg->data[1] = rx_msg.data[1];
|
|
pmsg->data[2] = rx_msg.data[2];
|
|
pmsg->data[3] = rx_msg.data[3];
|
|
pmsg->data[4] = rx_msg.data[4];
|
|
pmsg->data[5] = rx_msg.data[5];
|
|
pmsg->data[6] = rx_msg.data[6];
|
|
pmsg->data[7] = rx_msg.data[7];
|
|
pmsg->len = rx_msg.data_len;
|
|
|
|
if (can_instance->filter_cfg.filter_mag[i].IdType == CAN_EXT_ID)
|
|
{
|
|
pmsg->id = can_instance->filter_cfg.filter_mag[i].Id;
|
|
pmsg->ide = RT_CAN_EXTID;
|
|
}
|
|
else if (can_instance->filter_cfg.filter_mag[i].IdType == CAN_STD_ID)
|
|
{
|
|
pmsg->id = can_instance->filter_cfg.filter_mag[i].Id;
|
|
pmsg->ide = RT_CAN_EXTID;
|
|
}
|
|
|
|
if (can_instance->filter_cfg.filter_mag[i].FrameType == CAN_DATA_FRAME)
|
|
{
|
|
pmsg->rtr = RT_CAN_DTR;
|
|
}
|
|
else if (can_instance->filter_cfg.filter_mag[i].FrameType == CAN_REMOTE_FRAME)
|
|
{
|
|
pmsg->rtr = RT_CAN_RTR;
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
}
|
|
msgnum = msgnum >> 1;
|
|
if (msgnum == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
/* Mapping CAN interfaces */
|
|
static const struct rt_can_ops ht32_can_ops =
|
|
{
|
|
.configure = ht32_can_configure, /* CAN Configuration Functions */
|
|
.control = ht32_can_control, /* CAN Control Functions */
|
|
.sendmsg = ht32_can_sendmsg, /* CAN Transmit Data */
|
|
.recvmsg = ht32_can_recvmsg, /* CAN Receive Data */
|
|
};
|
|
|
|
int rt_hw_can_init(void)
|
|
{
|
|
|
|
struct can_configure config = CANDEFAULTCONFIG;
|
|
config.mode = BSP_USING_CAN_MODE;
|
|
config.baud_rate = BSP_USING_CAN_BAUD;
|
|
config.privmode = RT_CAN_MODE_NOPRIV;
|
|
config.ticks = 50;
|
|
|
|
#ifdef RT_CAN_USING_HDR
|
|
config.maxhdr = 14;
|
|
#endif
|
|
ht32_can_config.device.config = config;
|
|
/* Registration of CAN devices */
|
|
rt_hw_can_register(&ht32_can_config.device,
|
|
ht32_can_config.name,
|
|
&ht32_can_ops,
|
|
&ht32_can_config);
|
|
return RT_EOK;
|
|
}
|
|
INIT_BOARD_EXPORT(rt_hw_can_init);
|
|
|
|
void CAN0_IRQHandler(void)
|
|
{
|
|
CAN_LastErrorCode_TypeDef lec;
|
|
rt_interrupt_enter();
|
|
/* Recover from Bus off state. */
|
|
if (CAN_GetFlagStatus(ht32_can_config.can_x, CAN_FLAG_BOFF))
|
|
{
|
|
CAN_BusOffRecovery(ht32_can_config.can_x);
|
|
}
|
|
/* Transmit message finished */
|
|
if (CAN_GetFlagStatus(ht32_can_config.can_x, CAN_FLAG_TXOK))
|
|
{
|
|
rt_hw_can_isr(&ht32_can_config.device, RT_CAN_EVENT_TX_DONE);
|
|
CAN_ClearFlag(ht32_can_config.can_x, CAN_FLAG_TXOK);
|
|
}
|
|
/* Message received. */
|
|
if (CAN_GetFlagStatus(ht32_can_config.can_x, CAN_FLAG_RXOK))
|
|
{
|
|
/* Clear all message objects' interrupt pending flag */
|
|
CAN_ClearAllMsgPendingFlag(ht32_can_config.can_x);
|
|
rt_hw_can_isr(&ht32_can_config.device, RT_CAN_EVENT_RX_IND);
|
|
CAN_ClearFlag(ht32_can_config.can_x, CAN_FLAG_RXOK);
|
|
}
|
|
lec = CAN_GetLastErrorCode(ht32_can_config.can_x);
|
|
if (lec != NO_ERROR)
|
|
{
|
|
switch (lec)
|
|
{
|
|
case NO_ERROR:
|
|
break;
|
|
case STUFF_ERROR:
|
|
ht32_can_config.device.status.bitpaderrcnt++;
|
|
break;
|
|
case FORM_ERROR:
|
|
ht32_can_config.device.status.formaterrcnt++;
|
|
break;
|
|
case ACK_ERROR:
|
|
ht32_can_config.device.status.ackerrcnt++;
|
|
break;
|
|
case BIT1_EROR:
|
|
case BIT0_ERROR:
|
|
ht32_can_config.device.status.biterrcnt++;
|
|
break;
|
|
case CRC_ERROR:
|
|
ht32_can_config.device.status.crcerrcnt++;
|
|
break;
|
|
case NO_CHANGE:
|
|
break;
|
|
}
|
|
ht32_can_config.device.status.lasterrtype = lec;
|
|
ht32_can_config.device.status.rcverrcnt = CAN_GetReceiveErrorCounter(ht32_can_config.can_x);
|
|
ht32_can_config.device.status.snderrcnt = CAN_GetLSBTransmitErrorCounter(ht32_can_config.can_x);
|
|
ht32_can_config.device.status.errcode = lec;
|
|
}
|
|
|
|
rt_interrupt_leave();
|
|
}
|
|
|
|
#endif /* BSP_USING_CAN */
|