#include "bsp_can.h" #include "FreeRTOS.h" #include "bsp_def.h" #include "bsp_sys.h" #include "bsp_time.h" #include "main.h" #include "semphr.h" #include "stm32g4xx_hal_fdcan.h" #include "task.h" typedef struct { FDCAN_RxHeaderTypeDef header; uint8_t data[64]; } can_raw_rx_t; typedef struct { FDCAN_HandleTypeDef header; uint8_t data[8]; } can_raw_tx_t; typedef struct { void (*fn)(bsp_can_t can, uint32_t id, uint8_t *data, void *arg); void *arg; } can_callback_t; extern FDCAN_HandleTypeDef hfdcan1; static can_callback_t callback_list[BSP_CAN_NUM][BSP_CAN_CB_NUM]; static bool bsp_can_initd = false; static can_raw_rx_t rx_buff[BSP_CAN_NUM]; static SemaphoreHandle_t rx_cplt_wait_sem[BSP_CAN_NUM]; FDCAN_HandleTypeDef *bsp_can_get_handle(bsp_can_t can) { switch (can) { case BSP_CAN_1: return &hfdcan1; default: return NULL; } } static bsp_can_t can_get(FDCAN_HandleTypeDef *hcan) { if (hcan->Instance == FDCAN1) { return BSP_CAN_1; } else { return BSP_CAN_ERR; } } void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hcan, uint32_t BufferIndexes) { (void)BufferIndexes; BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void HAL_FDCAN_TxBufferAbortCallback(FDCAN_HandleTypeDef *hcan, uint32_t BufferIndexes) { (void)BufferIndexes; BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hcan) { BaseType_t px_higher_priority_task_woken = 0; xSemaphoreGiveFromISR(rx_cplt_wait_sem[can_get(hcan)], &px_higher_priority_task_woken); if (px_higher_priority_task_woken != pdFALSE) { portYIELD(); } } void bsp_can_init(void) { for (int i = 0; i < BSP_CAN_NUM; i++) { rx_cplt_wait_sem[i] = xSemaphoreCreateBinary(); } FDCAN_FilterTypeDef can_filter = {0}; can_filter.IdType = FDCAN_STANDARD_ID; can_filter.FilterIndex = 0; can_filter.FilterType = FDCAN_FILTER_MASK; can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; can_filter.FilterID1 = 0x0000; can_filter.FilterID2 = 0x0000; if (HAL_FDCAN_ConfigFilter(&hfdcan1, &can_filter) != HAL_OK) { XB_ASSERT(false); } can_filter.IdType = FDCAN_EXTENDED_ID; can_filter.FilterIndex = 1; can_filter.FilterType = FDCAN_FILTER_MASK; can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; can_filter.FilterID1 = 0x0000; can_filter.FilterID2 = 0x0000; if (HAL_FDCAN_ConfigFilter(&hfdcan1, &can_filter) != HAL_OK) { XB_ASSERT(false); } HAL_FDCAN_Start(&hfdcan1); // 开启FDCAN HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_TX_FIFO_EMPTY, 0); bsp_can_initd = true; } static const uint8_t DLCtoBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; static uint32_t count = 0; static void can_rx_cb_fn(bsp_can_t can) { while (HAL_FDCAN_GetRxMessage(bsp_can_get_handle(can), FDCAN_RX_FIFO0, &rx_buff[can].header, rx_buff[can].data) == HAL_OK) { count++; if (rx_buff[can].header.FDFormat == FDCAN_CLASSIC_CAN) { if (callback_list[can][CAN_RX_MSG_CALLBACK].fn) { callback_list[can][CAN_RX_MSG_CALLBACK].fn( can, rx_buff[can].header.Identifier, rx_buff[can].data, callback_list[can][CAN_RX_MSG_CALLBACK].arg); } } else { if (callback_list[can][CANFD_RX_MSG_CALLBACK].fn) { bsp_canfd_data_t data = { .data = rx_buff[can].data, .size = DLCtoBytes[rx_buff[can].header.DataLength >> 16U]}; callback_list[can][CANFD_RX_MSG_CALLBACK].fn( can, rx_buff[can].header.Identifier, (uint8_t *)&data, callback_list[can][CANFD_RX_MSG_CALLBACK].arg); } } } } void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hcan, uint32_t RxFifo0ITs) { (void)RxFifo0ITs; can_rx_cb_fn(can_get(hcan)); } bsp_status_t bsp_can_register_callback( bsp_can_t can, bsp_can_callback_t type, void (*callback)(bsp_can_t can, uint32_t id, uint8_t *data, void *arg), void *callback_arg) { assert_param(callback); assert_param(type != BSP_CAN_CB_NUM); callback_list[can][type].fn = callback; callback_list[can][type].arg = callback_arg; return BSP_OK; } bsp_status_t bsp_can_trans_packet(bsp_can_t can, bsp_can_format_t format, uint32_t id, uint8_t *data) { FDCAN_TxHeaderTypeDef header; header.Identifier = id; if (format == CAN_FORMAT_STD) { header.IdType = FDCAN_STANDARD_ID; } else { header.IdType = FDCAN_EXTENDED_ID; } header.TxFrameType = FDCAN_DATA_FRAME; header.DataLength = FDCAN_DLC_BYTES_8; header.ErrorStateIndicator = FDCAN_ESI_PASSIVE; header.BitRateSwitch = FDCAN_BRS_OFF; header.FDFormat = FDCAN_CLASSIC_CAN; header.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; header.MessageMarker = 0x01; while ((bsp_can_get_handle(can)->Instance->TXFQS & FDCAN_TXFQS_TFQF) != 0U) { if (!xSemaphoreTake(rx_cplt_wait_sem[can], 10)) { return BSP_ERR_BUSY; } } return HAL_FDCAN_AddMessageToTxFifoQ(bsp_can_get_handle(can), &header, data) == HAL_OK ? BSP_OK : BSP_ERR; } static const uint32_t FDCAN_PACK_LEN_MAP[16] = { FDCAN_DLC_BYTES_0, FDCAN_DLC_BYTES_1, FDCAN_DLC_BYTES_2, FDCAN_DLC_BYTES_3, FDCAN_DLC_BYTES_4, FDCAN_DLC_BYTES_5, FDCAN_DLC_BYTES_6, FDCAN_DLC_BYTES_7, FDCAN_DLC_BYTES_8, FDCAN_DLC_BYTES_12, FDCAN_DLC_BYTES_16, FDCAN_DLC_BYTES_20, FDCAN_DLC_BYTES_24, FDCAN_DLC_BYTES_32, FDCAN_DLC_BYTES_48, FDCAN_DLC_BYTES_64, }; bsp_status_t bsp_canfd_trans_packet(bsp_can_t can, bsp_can_format_t format, uint32_t id, uint8_t *data, size_t size) { FDCAN_TxHeaderTypeDef header; XB_ASSERT(size <= 64); header.Identifier = id; if (format == CAN_FORMAT_STD) { header.IdType = FDCAN_STANDARD_ID; } else { header.IdType = FDCAN_EXTENDED_ID; } header.TxFrameType = FDCAN_DATA_FRAME; if (size <= 8) { header.DataLength = FDCAN_PACK_LEN_MAP[size]; } else if (size <= 24) { header.DataLength = FDCAN_PACK_LEN_MAP[(size - 9) / 4 + 1 + 8]; } else if (size < 32) { header.DataLength = FDCAN_DLC_BYTES_32; } else if (size < 48) { header.DataLength = FDCAN_DLC_BYTES_48; } else { header.DataLength = FDCAN_DLC_BYTES_64; } header.ErrorStateIndicator = FDCAN_ESI_PASSIVE; header.BitRateSwitch = FDCAN_BRS_ON; header.FDFormat = FDCAN_FD_CAN; header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; header.MessageMarker = 0x00; static uint32_t error_count = 0; while ((bsp_can_get_handle(can)->Instance->TXFQS & FDCAN_TXFQS_TFQF) != 0U) { if (error_count > 10) { return BSP_ERR; } if (!xSemaphoreTake(rx_cplt_wait_sem[can], 1)) { error_count++; return BSP_ERR_BUSY; } } error_count = 0; return HAL_FDCAN_AddMessageToTxFifoQ(bsp_can_get_handle(can), &header, data) == HAL_OK ? BSP_OK : BSP_ERR; }