diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript b/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript index a9c77286c15..456327087b2 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/SConscript @@ -50,7 +50,10 @@ if GetDepend(['RT_USING_DAC']): src += ['drv_dac.c'] if GetDepend(['RT_USING_CAN']): - src += ['drv_can.c'] + if GetDepend(['SOC_SERIES_STM32H7']): + src += ['drv_fdcan.c'] + else: + src += ['drv_can.c'] if GetDepend(['RT_USING_PM']): src += ['drv_pm.c'] diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.c new file mode 100644 index 00000000000..ca41a38f10a --- /dev/null +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.c @@ -0,0 +1,703 @@ +/* + * 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 + +#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 */ diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.h b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.h new file mode 100644 index 00000000000..d341fda4deb --- /dev/null +++ b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_fdcan.h @@ -0,0 +1,46 @@ +/* + * 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 + */ + +#ifndef __DRV_FDCAN_H__ +#define __DRV_FDCAN_H__ + +#include +#include + +#if defined(RT_USING_CAN) && defined(RT_CAN_USING_CANFD) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + const char *name; + FDCAN_HandleTypeDef fdcanHandle; + FDCAN_RxHeaderTypeDef RxHeader; + FDCAN_TxHeaderTypeDef TxHeader; + uint8_t u8RxDataBuffer[8]; + uint8_t u8TxDataBuffer[8]; + FDCAN_FilterTypeDef FilterConfig; /*FDCAN filter*/ + struct rt_can_device device; /* inherit from can device */ +} stm32_fdcan_t; + +typedef struct { + uint32_t u32Baudrate; + struct rt_can_bit_timing cam_bit_timing; +}stm32_fdcan_timing_t; + +#ifdef __cplusplus +} +#endif + +#endif /* RT_USING_CAN */ +#endif /* __DRV_FDCAN_H__ */