258 lines
7.4 KiB
C
258 lines
7.4 KiB
C
#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;
|
|
}
|