chore: 导入 Simba-OmniInfantry 基线(云台/底盘双工程)
- 云台(ROBOT_TYPE_GIMBAL)与底盘(ROBOT_TYPE_CHASSIS)完整固件源码 - 新增根级 .gitignore,排除 Keil MDK-ARM 构建产物(.o/.d/.crf/.axf/.lnp/.map/.htm/.sct/.dep/.iex/.lst 等) 与 *.uvguix.* / DebugConfig/(与机器绑定的 UI 布局) - core.autocrlf=false,避免固件源码在检出时被改动换行符
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
/* =============================================================================
|
||||
* bsp_can.c - CAN 总线板级支持包(收发中枢)
|
||||
* 职责:
|
||||
* 1. can_start() 启动两路 CAN(过滤器全开掩码 0,接收所有 ID),
|
||||
* 并使能 CAN1_RX0/CAN2_RX0 NVIC(CAN2 中断 ioc 未开,
|
||||
* 在此代码补齐,优先级 5 = FreeRTOS 管理下限)
|
||||
* 2. can_rx_register() 按 (hcan, 标准ID) 注册接收回调,查表容量 32
|
||||
* 3. HAL_CAN_RxFifo0MsgPendingCallback
|
||||
* RX0 中断里取帧并按 ID 分发到注册回调
|
||||
* (中断上下文,回调必须尽量短)
|
||||
* 4. CAN_SendTxMessage() 发送帧(等待 3 个发送邮箱空闲,最多重试 20 次)
|
||||
* 数据流: 电机反馈/板间通讯/裁判数据 --ISR--> 回调表 --> 各模块解析
|
||||
* 依赖: CubeMX 生成的 hcan1/hcan2(Core/Src/can.c)
|
||||
* 对比 legacy: 替代了"单滤波器轮询切换 ID"的脆弱接收机制
|
||||
* ========================================================================== */
|
||||
#include "bsp_can.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define CAN_RX_CALLBACK_MAX 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hcan_t * hcan;
|
||||
uint32_t std_id;
|
||||
can_rx_callback_f callback;
|
||||
} can_rx_callback_item_t;
|
||||
|
||||
static can_rx_callback_item_t can_rx_callback_table[CAN_RX_CALLBACK_MAX];
|
||||
static uint8_t can_started = 0;
|
||||
|
||||
/* 初始化过滤器并启动两路 CAN
|
||||
* 过滤器掩码全 0,接收所有 ID,由 can_rx_register 注册的回调按 ID 分发 */
|
||||
void can_filter_init(void)
|
||||
{
|
||||
CAN_FilterTypeDef can_filter_st;
|
||||
can_filter_st.FilterActivation = ENABLE;
|
||||
can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK;
|
||||
can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT;
|
||||
can_filter_st.FilterIdHigh = 0x0000;
|
||||
can_filter_st.FilterIdLow = 0x0000;
|
||||
can_filter_st.FilterMaskIdHigh = 0x0000;
|
||||
can_filter_st.FilterMaskIdLow = 0x0000;
|
||||
can_filter_st.FilterBank = 0;
|
||||
can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0;
|
||||
HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);
|
||||
HAL_CAN_Start(&hcan1);
|
||||
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
|
||||
|
||||
can_filter_st.SlaveStartFilterBank = 14;
|
||||
can_filter_st.FilterBank = 14;
|
||||
HAL_CAN_ConfigFilter(&hcan2, &can_filter_st);
|
||||
HAL_CAN_Start(&hcan2);
|
||||
HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);
|
||||
}
|
||||
|
||||
/* 应用层统一入口:启动 CAN(含 CAN2 接收中断使能,ioc 未开启,此处代码补齐)
|
||||
* FreeRTOS 管理的中断优先级不得高于 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(5) */
|
||||
void can_start(void)
|
||||
{
|
||||
if (can_started)
|
||||
return;
|
||||
can_started = 1;
|
||||
|
||||
can_filter_init();
|
||||
|
||||
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
||||
|
||||
/* CAN2 的 RX0 中断未在 CubeMX 中开启,在此手动补齐 */
|
||||
HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);
|
||||
}
|
||||
|
||||
int can_rx_register(hcan_t * hcan, uint32_t std_id, can_rx_callback_f callback)
|
||||
{
|
||||
for (uint32_t i = 0; i < CAN_RX_CALLBACK_MAX; i++)
|
||||
{
|
||||
if (can_rx_callback_table[i].callback == NULL)
|
||||
{
|
||||
can_rx_callback_table[i].hcan = hcan;
|
||||
can_rx_callback_table[i].std_id = std_id;
|
||||
can_rx_callback_table[i].callback = callback;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* HAL CAN 接收回调:在 RX0 中断上下文中按 (hcan, StdId) 查表分发 */
|
||||
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef * hcan)
|
||||
{
|
||||
CAN_RxHeaderTypeDef rx_header;
|
||||
uint8_t rx_data[8];
|
||||
|
||||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data) != HAL_OK)
|
||||
return;
|
||||
if (rx_header.IDE != CAN_ID_STD)
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < CAN_RX_CALLBACK_MAX; i++)
|
||||
{
|
||||
if (can_rx_callback_table[i].callback != NULL && can_rx_callback_table[i].hcan == hcan &&
|
||||
can_rx_callback_table[i].std_id == rx_header.StdId)
|
||||
{
|
||||
can_rx_callback_table[i].callback(rx_header.StdId, rx_data, rx_header.DLC);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送控制数据
|
||||
* @param[in] can_ctrl_data 打包好的发送结构体
|
||||
* @return none
|
||||
*/
|
||||
void CAN_SendTxMessage(CanCtrlData_s * can_ctrl_data)
|
||||
{
|
||||
uint32_t send_mail_box;
|
||||
uint8_t cnt = 20; // 重复检测次数
|
||||
|
||||
uint32_t free_TxMailbox =
|
||||
HAL_CAN_GetTxMailboxesFreeLevel(can_ctrl_data->hcan); // 检测是否有空闲邮箱
|
||||
while (free_TxMailbox < 3 && cnt--) { // 等待空闲邮箱数达到3
|
||||
free_TxMailbox = HAL_CAN_GetTxMailboxesFreeLevel(can_ctrl_data->hcan);
|
||||
}
|
||||
HAL_CAN_AddTxMessage(
|
||||
can_ctrl_data->hcan, &can_ctrl_data->tx_header, can_ctrl_data->tx_data, &send_mail_box);
|
||||
}
|
||||
Reference in New Issue
Block a user