120 lines
4.5 KiB
C
120 lines
4.5 KiB
C
#include "hw_can.h"
|
||
#include "main.h"
|
||
#include "FreeRTOS.h"
|
||
#include "task.h"
|
||
|
||
void hwCanInit(void)
|
||
{
|
||
CAN_FilterTypeDef filter;
|
||
|
||
/* 16-bit ID List 滤波: 每个 filter bank 容纳 4 个标准帧 ID
|
||
* 标准帧 ID 必须左移 5 位 (STID 在寄存器位[15:5])
|
||
*
|
||
* 本设备需接收 0x180-0x18A 全部 ID (多设备升级寻址范围)
|
||
* 0x180-0x18A = 11 个 ID, 需 3 个 bank (12 槽位)
|
||
* Bank0: 0x180-0x183 Bank1: 0x184-0x187 Bank2: 0x188-0x18B
|
||
* 具体哪个ID是本设备的, 由软件层 IAP_CAN_RX_ID 精确过滤 */
|
||
|
||
/* Bank 0: 0x180-0x183 → FIFO0 */
|
||
filter.FilterIdHigh = 0x180U << 5; /* ID0 = 0x180 */
|
||
filter.FilterIdLow = 0x181U << 5; /* ID1 = 0x181 */
|
||
filter.FilterMaskIdHigh = 0x182U << 5; /* ID2 = 0x182 */
|
||
filter.FilterMaskIdLow = 0x183U << 5; /* ID3 = 0x183 */
|
||
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
|
||
filter.FilterBank = 0;
|
||
filter.FilterMode = CAN_FILTERMODE_IDLIST; /* ID List 方式 */
|
||
filter.FilterScale = CAN_FILTERSCALE_16BIT; /* 16位 */
|
||
filter.FilterActivation = CAN_FILTER_ENABLE; /* 使能 */
|
||
filter.SlaveStartFilterBank = 14; /* 全部分配给CAN1 */
|
||
if (HAL_CAN_ConfigFilter(&hcan, &filter) != HAL_OK)
|
||
{
|
||
}
|
||
|
||
/* Bank 1: 0x184-0x187 → FIFO0 */
|
||
filter.FilterIdHigh = 0x184U << 5; /* ID0 = 0x184 */
|
||
filter.FilterIdLow = 0x185U << 5; /* ID1 = 0x185 */
|
||
filter.FilterMaskIdHigh = 0x186U << 5; /* ID2 = 0x186 */
|
||
filter.FilterMaskIdLow = 0x187U << 5; /* ID3 = 0x187 */
|
||
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
|
||
filter.FilterBank = 1;
|
||
HAL_CAN_ConfigFilter(&hcan, &filter);
|
||
|
||
/* Bank 2: 0x188-0x18B → FIFO1 (0x18A 为寻址上限, 0x18B 预留) */
|
||
filter.FilterIdHigh = 0x188U << 5; /* ID0 = 0x188 */
|
||
filter.FilterIdLow = 0x189U << 5; /* ID1 = 0x189 */
|
||
filter.FilterMaskIdHigh = 0x18AU << 5; /* ID2 = 0x18A */
|
||
filter.FilterMaskIdLow = 0x18BU << 5; /* ID3 = 0x18B (预留) */
|
||
filter.FilterFIFOAssignment = CAN_FILTER_FIFO1;
|
||
filter.FilterBank = 2;
|
||
HAL_CAN_ConfigFilter(&hcan, &filter);
|
||
|
||
HAL_CAN_Start(&hcan);
|
||
|
||
/* 使能接收 FIFO 中断 + 发送完成中断 */
|
||
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING
|
||
| CAN_IT_RX_FIFO1_MSG_PENDING
|
||
| CAN_IT_TX_MAILBOX_EMPTY);
|
||
}
|
||
|
||
uint8_t hwCanSend(uint32_t id, uint8_t *data, uint8_t dlc)
|
||
{
|
||
#if 1
|
||
CAN_TxHeaderTypeDef tx_header;
|
||
uint32_t tx_mailbox;
|
||
uint32_t wait = 20000;
|
||
|
||
/* 无空闲发送邮箱时短超时忙等(不osDelay,避免任务挂起导致积压) */
|
||
/* 500kbps下一帧约130µs,3个邮箱最慢约400µs释放 */
|
||
while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) == 0)
|
||
{
|
||
if (--wait == 0)
|
||
{
|
||
return 0; /* 超时放弃(总线异常) */
|
||
}
|
||
}
|
||
|
||
/* 组织发送帧头 */
|
||
tx_header.StdId = id; /* 标准帧ID */
|
||
tx_header.ExtId = 0; /* 扩展帧ID未用 */
|
||
tx_header.IDE = CAN_ID_STD; /* 标准帧 */
|
||
tx_header.RTR = CAN_RTR_DATA;/* 数据帧 */
|
||
tx_header.DLC = dlc; /* 数据长度 0~8 */
|
||
|
||
/* 临界区保护HAL_CAN_AddTxMessage,防止RX中断中HAL_CAN_GetRxMessage
|
||
的HAL_LOCK冲突(仅几μs,不影响实时性) */
|
||
taskENTER_CRITICAL();
|
||
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(&hcan, &tx_header, data, &tx_mailbox);
|
||
taskEXIT_CRITICAL();
|
||
|
||
if (status != HAL_OK)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
return 1;
|
||
#else
|
||
uint32_t mailbox;
|
||
|
||
/* 选择空闲邮箱(直接读TSR寄存器) */
|
||
if (hcan.Instance->TSR & CAN_TSR_TME0) mailbox = 0;
|
||
else if (hcan.Instance->TSR & CAN_TSR_TME1) mailbox = 1;
|
||
else if (hcan.Instance->TSR & CAN_TSR_TME2) mailbox = 2;
|
||
else return 0; /* 无空闲邮箱 */
|
||
|
||
/* 设置ID(标准帧,ID左移21位) */
|
||
hcan.Instance->sTxMailBox[mailbox].TIR = (id << 21) | CAN_RTR_DATA | CAN_ID_STD;
|
||
|
||
/* 设置DLC */
|
||
hcan.Instance->sTxMailBox[mailbox].TDTR = dlc;
|
||
|
||
/* 设置数据(直接写TDLR/TDHR寄存器,立即拷贝) */
|
||
hcan.Instance->sTxMailBox[mailbox].TDLR = ((uint32_t)data[3]<<24)|((uint32_t)data[2]<<16)|((uint32_t)data[1]<<8)|data[0];
|
||
hcan.Instance->sTxMailBox[mailbox].TDHR = ((uint32_t)data[7]<<24)|((uint32_t)data[6]<<16)|((uint32_t)data[5]<<8)|data[4];
|
||
|
||
/* 请求发送 */
|
||
hcan.Instance->sTxMailBox[mailbox].TIR |= CAN_TI0R_TXRQ;
|
||
|
||
return 1;
|
||
#endif
|
||
}
|