mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-11-16 04:24:33 +00:00
704 lines
24 KiB
C
704 lines
24 KiB
C
/*
|
|
* Copyright (c) 2006-2018, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2020-02-24 heyuan the first version
|
|
* 2020-08-17 malongwei Fix something
|
|
* 2025-10-27 pandafeng Fix some bugs
|
|
*/
|
|
|
|
#include "drv_fdcan.h"
|
|
|
|
#if defined(RT_USING_CAN) && defined(RT_CAN_USING_CANFD)
|
|
|
|
#if defined(BSP_USING_FDCAN1) || defined(BSP_USING_FDCAN2)
|
|
|
|
|
|
//#define DRV_DEBUG
|
|
#define LOG_TAG "drv_fdcan"
|
|
#include <drv_log.h>
|
|
|
|
#ifdef BSP_USING_FDCAN1
|
|
static stm32_fdcan_t st_DrvCan1=
|
|
{
|
|
.name = "fdcan1",
|
|
.fdcanHandle.Instance = FDCAN1,
|
|
};
|
|
#endif
|
|
|
|
#ifdef BSP_USING_FDCAN2
|
|
static stm32_fdcan_t st_DrvCan2=
|
|
{
|
|
.name = "fdcan2",
|
|
.fdcanHandle.Instance = FDCAN2,
|
|
};
|
|
#endif
|
|
|
|
/* 40MHz CAN clock */
|
|
static const stm32_fdcan_timing_t st_FDCAN_ArbTiming[] =
|
|
{
|
|
{CAN1MBaud, {1, 29, 10, 8, 0}}, /* 1Mbps */
|
|
{CAN800kBaud, {1, 37, 12, 8, 0}}, /* 800kbps */
|
|
{CAN500kBaud, {1, 59, 20, 8, 0}}, /* 500kbps */
|
|
{CAN250kBaud, {2, 63, 16, 8, 0}}, /* 250kbps */
|
|
{CAN125kBaud, {5, 55, 8, 8, 0}}, /* 125kbps */
|
|
{CAN100kBaud, {8, 41, 8, 8, 0}}, /* 100kbps */
|
|
{CAN50kBaud, {16, 41, 8, 8, 0}}, /* 50kbps */
|
|
{CAN20kBaud, {40,41,8,8,0}}, /* 20kbps */
|
|
{CAN10kBaud, {100,31,8,8,0}} /* 10kbps */
|
|
};
|
|
/* 40MHz CAN clock */
|
|
static const stm32_fdcan_timing_t st_FDCAN_DataTiming[] =
|
|
{
|
|
{CAN1MBaud * 8, {1, 3, 1, 1, 0}}, /* 8Mbps */
|
|
{CAN500kBaud *8, {1, 7, 2, 1, 0}}, /* 4Mbps */
|
|
{CAN250kBaud * 8, {4, 3, 1, 1, 0}}, /* 2Mbps */
|
|
{CAN125kBaud *8, {1, 31, 8, 1, 0}}, /* 1Mkbps */
|
|
{CAN100kBaud*8, {2, 19, 5, 1, 0}}, /* 800kbps */
|
|
{CAN50kBaud *8, {5, 15, 4, 1, 0}}, /* 400kbps */
|
|
};
|
|
/**
|
|
* @brief Convert CAN-FD frame length to DLC (Data Length Code)
|
|
*
|
|
* CAN-FD DLC mapping (length → DLC):
|
|
* Length 0~8 -> DLC 0~8
|
|
* Length 9~12 -> DLC 9
|
|
* Length 13~16 -> DLC 10
|
|
* Length 17~20 -> DLC 11
|
|
* Length 21~24 -> DLC 12
|
|
* Length 25~32 -> DLC 13
|
|
* Length 33~48 -> DLC 14
|
|
* Length 49~64 -> DLC 15
|
|
*
|
|
* @param len Frame length in bytes (0~64)
|
|
* @return DLC code (0~15)
|
|
*/
|
|
uint8_t length_to_dlc(uint8_t len) {
|
|
return (len <= 8) ? len :
|
|
(len <= 12) ? 9 :
|
|
(len <= 16) ? 10 :
|
|
(len <= 20) ? 11 :
|
|
(len <= 24) ? 12 :
|
|
(len <= 32) ? 13 :
|
|
(len <= 48) ? 14 : 15;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取 FDCAN 仲裁段波特率配置索引
|
|
*/
|
|
static uint32_t _inline_get_ArbBaudIndex(uint32_t baud_rate)
|
|
{
|
|
uint32_t len = sizeof(st_FDCAN_ArbTiming) / sizeof(st_FDCAN_ArbTiming[0]);
|
|
|
|
for (uint32_t i = 0; i < len; i++)
|
|
{
|
|
if (st_FDCAN_ArbTiming[i].u32Baudrate == baud_rate)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the index of the FDCAN data segment bitrate configuration.
|
|
*
|
|
* @param baud_rate The desired data phase baud rate (in bps).
|
|
* @retval uint32_t Index of the matching data segment configuration.
|
|
* Returns -1 if no matching configuration is found.
|
|
*/
|
|
static uint32_t _inline_get_DataBaudIndex(uint32_t baud_rate)
|
|
{
|
|
uint32_t len = sizeof(st_FDCAN_DataTiming) / sizeof(st_FDCAN_DataTiming[0]);
|
|
|
|
for (uint32_t i = 0; i < len; i++)
|
|
{
|
|
if (st_FDCAN_DataTiming[i].u32Baudrate == baud_rate)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static rt_err_t _inline_can_config(struct rt_can_device *can, struct can_configure *cfg)
|
|
{
|
|
stm32_fdcan_t *pdrv_can;
|
|
rt_uint32_t tmp_u32Index;
|
|
|
|
RT_ASSERT(can);
|
|
RT_ASSERT(cfg);
|
|
|
|
pdrv_can = (stm32_fdcan_t *)can->parent.user_data;
|
|
|
|
RT_ASSERT(pdrv_can);
|
|
|
|
pdrv_can->fdcanHandle.Init.FrameFormat = FDCAN_FRAME_FD_BRS;
|
|
pdrv_can->fdcanHandle.Init.Mode = FDCAN_MODE_NORMAL;
|
|
pdrv_can->fdcanHandle.Init.AutoRetransmission = ENABLE;
|
|
|
|
pdrv_can->fdcanHandle.Init.TransmitPause = DISABLE;
|
|
pdrv_can->fdcanHandle.Init.ProtocolException = ENABLE;
|
|
|
|
switch (cfg->mode)
|
|
{
|
|
case RT_CAN_MODE_NORMAL:
|
|
pdrv_can->fdcanHandle.Init.Mode = FDCAN_MODE_NORMAL;
|
|
break;
|
|
case RT_CAN_MODE_LISTEN:
|
|
pdrv_can->fdcanHandle.Init.Mode = FDCAN_MODE_BUS_MONITORING;
|
|
break;
|
|
case RT_CAN_MODE_LOOPBACK:
|
|
pdrv_can->fdcanHandle.Init.Mode = FDCAN_MODE_INTERNAL_LOOPBACK;
|
|
break;
|
|
default:
|
|
pdrv_can->fdcanHandle.Init.Mode = FDCAN_MODE_NORMAL;
|
|
break;
|
|
}
|
|
|
|
uint32_t arb_idx = _inline_get_ArbBaudIndex(cfg->baud_rate);
|
|
if (arb_idx == (uint32_t)-1)
|
|
{
|
|
LOG_E("not support %d baudrate", cfg->baud_rate);
|
|
return -RT_ERROR;
|
|
}
|
|
/* FDCAN arbitration segment */
|
|
pdrv_can->fdcanHandle.Init.NominalPrescaler = st_FDCAN_ArbTiming[arb_idx].cam_bit_timing.prescaler;
|
|
pdrv_can->fdcanHandle.Init.NominalSyncJumpWidth = st_FDCAN_ArbTiming[arb_idx].cam_bit_timing.num_sjw;
|
|
pdrv_can->fdcanHandle.Init.NominalTimeSeg1 = st_FDCAN_ArbTiming[arb_idx].cam_bit_timing.num_seg1;
|
|
pdrv_can->fdcanHandle.Init.NominalTimeSeg2 = st_FDCAN_ArbTiming[arb_idx].cam_bit_timing.num_seg2;
|
|
#ifdef RT_CAN_USING_CANFD
|
|
if(cfg->enable_canfd) {
|
|
uint32_t data_idx = _inline_get_DataBaudIndex(cfg->baud_rate_fd);
|
|
if (data_idx == (uint32_t)-1)
|
|
{
|
|
LOG_E("not support %d baudrate", cfg->baud_rate_fd);
|
|
return -RT_ERROR;
|
|
}
|
|
/* 数据段 */
|
|
pdrv_can->fdcanHandle.Init.DataPrescaler = st_FDCAN_DataTiming[data_idx].cam_bit_timing.prescaler;
|
|
pdrv_can->fdcanHandle.Init.DataSyncJumpWidth = st_FDCAN_DataTiming[data_idx].cam_bit_timing.num_sjw;
|
|
pdrv_can->fdcanHandle.Init.DataTimeSeg1 = st_FDCAN_DataTiming[data_idx].cam_bit_timing.num_seg1;
|
|
pdrv_can->fdcanHandle.Init.DataTimeSeg2 = st_FDCAN_DataTiming[data_idx].cam_bit_timing.num_seg2;
|
|
}
|
|
#endif
|
|
/* Configure Message RAM */
|
|
if(pdrv_can->fdcanHandle.Instance == FDCAN1)
|
|
{
|
|
pdrv_can->fdcanHandle.Init.MessageRAMOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
pdrv_can->fdcanHandle.Init.MessageRAMOffset = 1280;
|
|
}
|
|
pdrv_can->fdcanHandle.Init.StdFiltersNbr = 2;
|
|
pdrv_can->fdcanHandle.Init.ExtFiltersNbr = 2;
|
|
pdrv_can->fdcanHandle.Init.RxFifo0ElmtsNbr = 1;
|
|
pdrv_can->fdcanHandle.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_64;
|
|
pdrv_can->fdcanHandle.Init.RxFifo1ElmtsNbr = 0;
|
|
pdrv_can->fdcanHandle.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_64;
|
|
pdrv_can->fdcanHandle.Init.RxBuffersNbr = 0;
|
|
pdrv_can->fdcanHandle.Init.RxBufferSize = FDCAN_DATA_BYTES_64;
|
|
pdrv_can->fdcanHandle.Init.TxEventsNbr = 0;
|
|
pdrv_can->fdcanHandle.Init.TxBuffersNbr = 3;
|
|
pdrv_can->fdcanHandle.Init.TxFifoQueueElmtsNbr = 0;
|
|
pdrv_can->fdcanHandle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
|
|
pdrv_can->fdcanHandle.Init.TxElmtSize = FDCAN_DATA_BYTES_64;
|
|
|
|
if (HAL_FDCAN_Init(&pdrv_can->fdcanHandle) != HAL_OK)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
/* default filter config */
|
|
HAL_FDCAN_ConfigFilter(&pdrv_can->fdcanHandle , &pdrv_can->FilterConfig);
|
|
/*init fdcan tx header*/
|
|
pdrv_can->TxHeader.Identifier = 0x000000;
|
|
pdrv_can->TxHeader.IdType = FDCAN_EXTENDED_ID;
|
|
pdrv_can->TxHeader.TxFrameType = FDCAN_DATA_FRAME;
|
|
pdrv_can->TxHeader.DataLength = FDCAN_DLC_BYTES_8;
|
|
pdrv_can->TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
|
pdrv_can->TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
|
|
pdrv_can->TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
|
|
pdrv_can->TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
|
|
pdrv_can->TxHeader.MessageMarker = 0;
|
|
/* can start */
|
|
HAL_FDCAN_Start(&pdrv_can->fdcanHandle);
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _inline_can_filter_config(stm32_fdcan_t *pdrv_can,struct rt_can_filter_config *puser_can_filter_config)
|
|
{
|
|
int tmp_i32IndexCount;
|
|
RT_ASSERT(pdrv_can);
|
|
RT_ASSERT(puser_can_filter_config);
|
|
/* get default filter */
|
|
for (tmp_i32IndexCount = 0; tmp_i32IndexCount < puser_can_filter_config->count; tmp_i32IndexCount++)
|
|
{
|
|
pdrv_can->FilterConfig.FilterIndex = puser_can_filter_config->items[tmp_i32IndexCount].hdr_bank;
|
|
pdrv_can->FilterConfig.FilterID1 = puser_can_filter_config->items[tmp_i32IndexCount].id;
|
|
pdrv_can->FilterConfig.FilterID2 = puser_can_filter_config->items[tmp_i32IndexCount].mask;
|
|
if(puser_can_filter_config->items[tmp_i32IndexCount].ide == RT_CAN_EXTID)
|
|
{
|
|
pdrv_can->FilterConfig.IdType = FDCAN_EXTENDED_ID;
|
|
}
|
|
else
|
|
{
|
|
pdrv_can->FilterConfig.IdType = FDCAN_STANDARD_ID;
|
|
}
|
|
pdrv_can->FilterConfig.FilterType = FDCAN_FILTER_MASK;
|
|
pdrv_can->FilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
|
if(HAL_FDCAN_ConfigFilter(&pdrv_can->fdcanHandle , &pdrv_can->FilterConfig) != HAL_OK)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
}
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t _inline_can_control(struct rt_can_device *can, int cmd, void *arg)
|
|
{
|
|
|
|
rt_uint32_t argval;
|
|
stm32_fdcan_t *pdrv_can;
|
|
struct rt_can_filter_config *filter_cfg;
|
|
RT_ASSERT(can != RT_NULL);
|
|
pdrv_can = (stm32_fdcan_t *)can->parent.user_data;
|
|
RT_ASSERT(pdrv_can != RT_NULL);
|
|
switch (cmd) {
|
|
case RT_DEVICE_CTRL_CLR_INT:
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval == RT_DEVICE_FLAG_INT_RX) {
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE);
|
|
} else if (argval == RT_DEVICE_FLAG_INT_TX) {
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_TX_FIFO_EMPTY);
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_TX_COMPLETE);
|
|
} else if (argval == RT_DEVICE_CAN_INT_ERR) {
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_WARNING);
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_PASSIVE);
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_LOGGING_OVERFLOW);
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_BUS_OFF);
|
|
HAL_FDCAN_DeactivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ARB_PROTOCOL_ERROR);
|
|
}
|
|
break;
|
|
case RT_DEVICE_CTRL_SET_INT:
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval == RT_DEVICE_FLAG_INT_RX) {
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE,
|
|
FDCAN_INTERRUPT_LINE0);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
|
|
|
|
if (FDCAN1 == pdrv_can->fdcanHandle.Instance) {
|
|
HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 1);
|
|
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
|
|
} else {
|
|
HAL_NVIC_SetPriority(FDCAN2_IT0_IRQn, 0, 1);
|
|
HAL_NVIC_EnableIRQ(FDCAN2_IT0_IRQn);
|
|
}
|
|
} else if (argval == RT_DEVICE_FLAG_INT_TX) {
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_TX_COMPLETE, FDCAN_INTERRUPT_LINE1);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_TX_COMPLETE, FDCAN_TX_BUFFER0);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_TX_COMPLETE, FDCAN_TX_BUFFER1);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_TX_COMPLETE, FDCAN_TX_BUFFER2);
|
|
|
|
if (FDCAN1 == pdrv_can->fdcanHandle.Instance) {
|
|
HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 0, 2);
|
|
HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
|
|
} else {
|
|
HAL_NVIC_SetPriority(FDCAN2_IT1_IRQn, 0, 2);
|
|
HAL_NVIC_EnableIRQ(FDCAN2_IT1_IRQn);
|
|
}
|
|
} else if (argval == RT_DEVICE_CAN_INT_ERR) {
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_BUS_OFF, FDCAN_INTERRUPT_LINE1);
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_WARNING, FDCAN_INTERRUPT_LINE1);
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_PASSIVE, FDCAN_INTERRUPT_LINE1);
|
|
HAL_FDCAN_ConfigInterruptLines(&pdrv_can->fdcanHandle, FDCAN_IT_ARB_PROTOCOL_ERROR,
|
|
FDCAN_INTERRUPT_LINE1);
|
|
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_BUS_OFF, 0);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_WARNING, 0);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ERROR_PASSIVE, 0);
|
|
HAL_FDCAN_ActivateNotification(&pdrv_can->fdcanHandle, FDCAN_IT_ARB_PROTOCOL_ERROR, 0);
|
|
if (FDCAN1 == pdrv_can->fdcanHandle.Instance) {
|
|
HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 0, 2);
|
|
HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
|
|
} else {
|
|
HAL_NVIC_SetPriority(FDCAN2_IT1_IRQn, 0, 2);
|
|
HAL_NVIC_EnableIRQ(FDCAN2_IT1_IRQn);
|
|
}
|
|
}
|
|
break;
|
|
case RT_CAN_CMD_SET_FILTER:
|
|
if (RT_NULL == arg) {
|
|
/* default filter config */
|
|
HAL_FDCAN_ConfigFilter(&pdrv_can->fdcanHandle, &pdrv_can->FilterConfig);
|
|
} else {
|
|
filter_cfg = (struct rt_can_filter_config *) arg;
|
|
_inline_can_filter_config(pdrv_can, filter_cfg);
|
|
}
|
|
break;
|
|
case RT_CAN_CMD_SET_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 != pdrv_can->device.config.mode) {
|
|
pdrv_can->device.config.mode = argval;
|
|
return _inline_can_config(&pdrv_can->device, &pdrv_can->device.config);
|
|
}
|
|
break;
|
|
case RT_CAN_CMD_SET_BAUD:
|
|
argval = (rt_uint32_t) arg;
|
|
uint32_t arb_idx = _inline_get_ArbBaudIndex(argval);
|
|
if (arb_idx == (uint32_t) -1) {
|
|
return -RT_ERROR;
|
|
}
|
|
if (argval != pdrv_can->device.config.baud_rate) {
|
|
pdrv_can->device.config.baud_rate = argval;
|
|
return _inline_can_config(&pdrv_can->device, &pdrv_can->device.config);
|
|
}
|
|
break;
|
|
|
|
case RT_CAN_CMD_SET_PRIV:
|
|
argval = (rt_uint32_t) arg;
|
|
if (argval != RT_CAN_MODE_PRIV &&
|
|
argval != RT_CAN_MODE_NOPRIV) {
|
|
return -RT_ERROR;
|
|
}
|
|
if (argval != pdrv_can->device.config.privmode) {
|
|
pdrv_can->device.config.privmode = argval;
|
|
|
|
return RT_EOK;
|
|
}
|
|
break;
|
|
case RT_CAN_CMD_GET_STATUS: {
|
|
rt_uint32_t tmp_u32Errcount;
|
|
rt_uint32_t tmp_u32status;
|
|
tmp_u32Errcount = pdrv_can->fdcanHandle.Instance->ECR;
|
|
tmp_u32status = pdrv_can->fdcanHandle.Instance->PSR;
|
|
|
|
pdrv_can->device.status.rcverrcnt = (tmp_u32Errcount >> 8) & 0x000000ff;
|
|
pdrv_can->device.status.snderrcnt = (tmp_u32Errcount) & 0x000000ff;
|
|
pdrv_can->device.status.lasterrtype = tmp_u32status & 0x000000007;
|
|
|
|
rt_memcpy(arg, &pdrv_can->device.status, sizeof(pdrv_can->device.status));
|
|
}
|
|
break;
|
|
case RT_CAN_CMD_SET_BAUD_FD: {
|
|
argval = (rt_uint32_t) arg;
|
|
uint32_t data_idx = _inline_get_DataBaudIndex(argval);
|
|
if (data_idx == (uint32_t) -1) {
|
|
return -RT_ERROR;
|
|
}
|
|
if (argval != pdrv_can->device.config.baud_rate_fd) {
|
|
pdrv_can->device.config.baud_rate_fd = argval;
|
|
return _inline_can_config(&pdrv_can->device, &pdrv_can->device.config);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static int _inline_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
|
|
{
|
|
|
|
stm32_fdcan_t *pdrv_can;
|
|
struct rt_can_msg *pmsg;
|
|
uint32_t tmp_u32DataLen;
|
|
RT_ASSERT(can);
|
|
RT_ASSERT(buf);
|
|
|
|
pdrv_can = (stm32_fdcan_t *)can->parent.user_data;
|
|
|
|
RT_ASSERT(pdrv_can);
|
|
|
|
pmsg = (struct rt_can_msg *) buf;
|
|
|
|
/* Check the parameters */
|
|
tmp_u32DataLen = length_to_dlc( pmsg->len);
|
|
|
|
if(pmsg->ide == RT_CAN_EXTID)
|
|
{
|
|
pdrv_can->TxHeader.IdType = FDCAN_EXTENDED_ID;
|
|
}
|
|
else
|
|
{
|
|
pdrv_can->TxHeader.IdType = FDCAN_STANDARD_ID;
|
|
}
|
|
|
|
if (RT_CAN_DTR == pmsg->rtr)
|
|
{
|
|
pdrv_can->TxHeader.TxFrameType = FDCAN_DATA_FRAME;
|
|
}
|
|
else
|
|
{
|
|
pdrv_can->TxHeader.TxFrameType = FDCAN_REMOTE_FRAME;
|
|
}
|
|
|
|
|
|
pdrv_can->TxHeader.Identifier = pmsg->id;
|
|
|
|
pdrv_can->TxHeader.DataLength = tmp_u32DataLen;
|
|
|
|
|
|
if (pmsg->fd_frame == 1)
|
|
{
|
|
pdrv_can->TxHeader.FDFormat = FDCAN_FD_CAN;
|
|
}
|
|
else {
|
|
pdrv_can->TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
|
|
}
|
|
|
|
if(HAL_FDCAN_AddMessageToTxBuffer(&pdrv_can->fdcanHandle, &pdrv_can->TxHeader, pmsg->data, FDCAN_TX_BUFFER0 + box_num) != HAL_OK)
|
|
{
|
|
return -RT_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Request transmission */
|
|
HAL_FDCAN_EnableTxBufferRequest(&pdrv_can->fdcanHandle,FDCAN_TX_BUFFER0+box_num);
|
|
return RT_EOK;
|
|
}
|
|
}
|
|
|
|
static int _inline_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
|
|
{
|
|
struct rt_can_msg *pmsg;
|
|
stm32_fdcan_t *pdrv_can;
|
|
|
|
RT_ASSERT(can);
|
|
RT_ASSERT(buf);
|
|
|
|
pdrv_can = (stm32_fdcan_t *)can->parent.user_data;
|
|
pmsg = (struct rt_can_msg *) buf;
|
|
if(HAL_FDCAN_GetRxMessage(&pdrv_can->fdcanHandle,FDCAN_RX_FIFO0+fifo, &pdrv_can->RxHeader, pmsg->data) != HAL_OK)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if(pdrv_can->RxHeader.IdType == FDCAN_EXTENDED_ID)
|
|
{
|
|
pmsg->ide = RT_CAN_EXTID;
|
|
}
|
|
else
|
|
{
|
|
pmsg->ide = RT_CAN_STDID;
|
|
}
|
|
|
|
if(pdrv_can->RxHeader.RxFrameType == FDCAN_DATA_FRAME)
|
|
{
|
|
pmsg->rtr = RT_CAN_DTR;
|
|
}
|
|
else
|
|
{
|
|
pmsg->rtr = RT_CAN_RTR;
|
|
}
|
|
pmsg->id = pdrv_can->RxHeader.Identifier;
|
|
|
|
pmsg->len = pdrv_can->RxHeader.DataLength;
|
|
pmsg->hdr_index = pdrv_can->RxHeader.FilterIndex;
|
|
|
|
#ifdef RT_CAN_USING_CANFD
|
|
pmsg->fd_frame = (pdrv_can->RxHeader.FDFormat >> 16) && 0x20;
|
|
pmsg->brs = (pdrv_can->RxHeader.BitRateSwitch >> 16) && 0x10;
|
|
#endif
|
|
|
|
return sizeof(struct rt_can_msg);
|
|
}
|
|
}
|
|
|
|
static const struct rt_can_ops _can_ops =
|
|
{
|
|
_inline_can_config,
|
|
_inline_can_control,
|
|
_inline_can_sendmsg,
|
|
_inline_can_recvmsg,
|
|
};
|
|
|
|
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
|
|
{
|
|
if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
|
|
{
|
|
if(hfdcan->Instance == FDCAN1)
|
|
{
|
|
#ifdef BSP_USING_FDCAN1
|
|
//CAN1
|
|
/* Retreive Rx messages from RX FIFO0 */
|
|
rt_hw_can_isr(&st_DrvCan1.device, RT_CAN_EVENT_RX_IND | 0 << 8);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef BSP_USING_FDCAN2
|
|
//CAN2
|
|
/* Retreive Rx messages from RX FIFO0 */
|
|
rt_hw_can_isr(&st_DrvCan2.device, RT_CAN_EVENT_RX_IND | 0 << 8);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndexes)
|
|
{
|
|
if(hfdcan->Instance == FDCAN1)
|
|
{
|
|
#ifdef BSP_USING_FDCAN1
|
|
//can1
|
|
rt_hw_can_isr(&st_DrvCan1.device, RT_CAN_EVENT_TX_DONE | ((BufferIndexes-1) << 8));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef BSP_USING_FDCAN2
|
|
//can2
|
|
rt_hw_can_isr(&st_DrvCan2.device, RT_CAN_EVENT_TX_DONE | ((BufferIndexes-1) << 8));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void HAL_FDCAN_TxFifoEmptyCallback(FDCAN_HandleTypeDef *hfdcan)
|
|
{
|
|
if(hfdcan->Instance == FDCAN1)
|
|
{
|
|
#ifdef BSP_USING_FDCAN1
|
|
rt_hw_can_isr(&st_DrvCan1.device, RT_CAN_EVENT_TX_DONE);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef BSP_USING_FDCAN2
|
|
rt_hw_can_isr(&st_DrvCan2.device, RT_CAN_EVENT_TX_DONE);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hfdcan)
|
|
{
|
|
rt_uint32_t tmp_u32Errcount;
|
|
rt_uint32_t tmp_u32status;
|
|
uint32_t ret = HAL_FDCAN_GetError(hfdcan);
|
|
|
|
if(hfdcan->Instance == FDCAN1)
|
|
{
|
|
#ifdef BSP_USING_FDCAN1
|
|
if((ret & FDCAN_IT_ARB_PROTOCOL_ERROR) &&
|
|
(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT_Msk))
|
|
{
|
|
//hfdcan->Instance->CCCR |= FDCAN_CCCR_CCE_Msk;
|
|
hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT_Msk;
|
|
st_DrvCan1.device.status.errcode = 0xff;
|
|
}
|
|
else
|
|
{
|
|
tmp_u32Errcount = st_DrvCan1.fdcanHandle.Instance->ECR;
|
|
tmp_u32status = st_DrvCan1.fdcanHandle.Instance->PSR;
|
|
st_DrvCan1.device.status.rcverrcnt = (tmp_u32Errcount>>8)&0x000000ff;
|
|
st_DrvCan1.device.status.snderrcnt = (tmp_u32Errcount)&0x000000ff;
|
|
st_DrvCan1.device.status.lasterrtype = tmp_u32status&0x000000007;
|
|
rt_hw_can_isr(&st_DrvCan1.device, RT_CAN_EVENT_TX_FAIL);
|
|
|
|
}
|
|
#endif /*BSP_USING_FDCAN1*/
|
|
}
|
|
else
|
|
{
|
|
#ifdef BSP_USING_FDCAN2
|
|
if( (ret & FDCAN_IT_ARB_PROTOCOL_ERROR) &&
|
|
(hfdcan->Instance->CCCR & FDCAN_CCCR_INIT_Msk))
|
|
{
|
|
//hfdcan->Instance->CCCR |= FDCAN_CCCR_CCE_Msk;
|
|
hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT_Msk;
|
|
st_DrvCan2.device.status.errcode = 0xff;
|
|
}
|
|
else
|
|
{
|
|
//can2
|
|
tmp_u32Errcount = st_DrvCan2.fdcanHandle.Instance->ECR;
|
|
tmp_u32status = st_DrvCan2.fdcanHandle.Instance->PSR;
|
|
st_DrvCan2.device.status.rcverrcnt = (tmp_u32Errcount>>8)&0x000000ff;
|
|
st_DrvCan2.device.status.snderrcnt = (tmp_u32Errcount)&0x000000ff;
|
|
st_DrvCan2.device.status.lasterrtype = tmp_u32status&0x000000007;
|
|
rt_hw_can_isr(&st_DrvCan2.device, RT_CAN_EVENT_TX_FAIL);
|
|
}
|
|
#endif /*BSP_USING_FDCAN2*/
|
|
}
|
|
}
|
|
|
|
#ifdef BSP_USING_FDCAN1
|
|
void FDCAN1_IT0_IRQHandler(void) /* FDCAN1 interrupt line 0 */
|
|
{
|
|
rt_interrupt_enter();
|
|
HAL_FDCAN_IRQHandler(&st_DrvCan1.fdcanHandle);
|
|
rt_interrupt_leave();
|
|
}
|
|
|
|
void FDCAN1_IT1_IRQHandler(void) /* FDCAN1 interrupt line 1 */
|
|
{
|
|
rt_interrupt_enter();
|
|
HAL_FDCAN_IRQHandler(&st_DrvCan1.fdcanHandle);
|
|
rt_interrupt_leave();
|
|
}
|
|
#endif /*BSP_USING_FDCAN1*/
|
|
#ifdef BSP_USING_FDCAN2
|
|
void FDCAN2_IT0_IRQHandler(void) /* FDCAN2 interrupt line 0 */
|
|
{
|
|
rt_interrupt_enter();
|
|
HAL_FDCAN_IRQHandler(&st_DrvCan2.fdcanHandle);
|
|
rt_interrupt_leave();
|
|
}
|
|
|
|
void FDCAN2_IT1_IRQHandler(void) /* FDCAN2 interrupt line 1 */
|
|
{
|
|
rt_interrupt_enter();
|
|
HAL_FDCAN_IRQHandler(&st_DrvCan2.fdcanHandle);
|
|
rt_interrupt_leave();
|
|
}
|
|
#endif/*BSP_USING_FDCAN2*/
|
|
|
|
static int rt_hw_can_init(void)
|
|
{
|
|
struct can_configure config;
|
|
config.baud_rate = CAN1MBaud;
|
|
config.msgboxsz = 48;
|
|
config.sndboxnumber = 1;
|
|
config.mode = RT_CAN_MODE_NORMAL;
|
|
config.privmode = RT_CAN_MODE_NOPRIV;
|
|
config.ticks = 50;
|
|
#ifdef RT_CAN_USING_HDR
|
|
config.maxhdr = 14;
|
|
#endif
|
|
#ifdef RT_CAN_USING_CANFD
|
|
config.baud_rate_fd = CAN1MBaud * 8;
|
|
config.enable_canfd = 1;
|
|
#endif
|
|
/* config default filter */
|
|
FDCAN_FilterTypeDef sFilterConfig;
|
|
sFilterConfig.IdType = FDCAN_STANDARD_ID;
|
|
sFilterConfig.FilterIndex = 0;
|
|
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
|
|
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
|
sFilterConfig.FilterID1 = 0;
|
|
sFilterConfig.FilterID2 = 0x7FF;
|
|
#ifdef BSP_USING_FDCAN1
|
|
st_DrvCan1.FilterConfig = sFilterConfig;
|
|
st_DrvCan1.device.config = config;
|
|
/* register FDCAN1 device */
|
|
rt_hw_can_register(&st_DrvCan1.device, st_DrvCan1.name, &_can_ops, &st_DrvCan1);
|
|
#endif /* BSP_USING_FDCAN1 */
|
|
#ifdef BSP_USING_FDCAN2
|
|
st_DrvCan2.FilterConfig = sFilterConfig;
|
|
st_DrvCan2.device.config = config;
|
|
/* register FDCAN2 device */
|
|
rt_hw_can_register(&st_DrvCan2.device, st_DrvCan2.name, &_can_ops, &st_DrvCan2);
|
|
#endif /* BSP_USING_FDCAN2 */
|
|
return 0;
|
|
}
|
|
INIT_BOARD_EXPORT(rt_hw_can_init);
|
|
|
|
#endif /* BSP_USING_FDCAN1 || BSP_USING_FDCAN2 */
|
|
#endif /* RT_USING_CAN */
|