test/freetest/Core/Src/hw_can.c

120 lines
4.5 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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µs3个邮箱最慢约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
}