feat(can): 实现CANFD协议栈及DMA优化
- 添加CANFD DMA接收功能,使用32位宽数据传输提升效率 - 实现CANFD收发队列管理,支持异步消息处理防止丢帧 - 重构CAN中断处理机制,采用FIFO0中断配合DMA完成数据接收 - 添加CANFD DLC长度转换表,规范化数据长度处理 - 实现临界区保护机制,确保多线程环境下的数据安全 - 优化发送队列机制,使用邮箱空闲中断进行消息调度 - 添加DMA错误处理,增强系统稳定性 - 移除原有8字节限制,支持CANFD最大64字节数据传输
This commit is contained in:
+335
-185
@@ -37,26 +37,38 @@ extern u32 motor_runtime_50us; // 电机驱动计算轮次(用于静默模式
|
||||
|
||||
// 添加 DMA 相关变量
|
||||
dma_parameter_struct dma_rx_parameter;
|
||||
dma_parameter_struct dma_tx_parameter;
|
||||
uint8_t can_rx_buffer[64]; // CAN 接收缓冲区(支持CAN FD最大64字节)
|
||||
uint8_t can_tx_buffer[64]; // CAN 发送缓冲区(支持CAN FD最大64字节)
|
||||
static uint32_t can_rx_dma_words[16]; // CAN FD接收DMA按32位搬运,最多64字节
|
||||
static volatile bool can_rx_dma_busy = false;
|
||||
static can_receive_message_struct can_rx_dma_message;
|
||||
|
||||
// CAN接收/发送队列结构
|
||||
#define CAN_RX_QUEUE_SIZE 32
|
||||
#define CAN_TX_QUEUE_SIZE 32
|
||||
|
||||
// CAN发送队列结构
|
||||
#define CAN_TX_QUEUE_SIZE 8
|
||||
typedef struct {
|
||||
u32 id;
|
||||
u8 length;
|
||||
u8 data[64];
|
||||
u8 valid;
|
||||
u32 id;
|
||||
u8 length;
|
||||
u8 data[64];
|
||||
} can_rx_queue_item_t;
|
||||
|
||||
typedef struct {
|
||||
can_trasnmit_message_struct message;
|
||||
u8 valid;
|
||||
} can_tx_queue_item_t;
|
||||
|
||||
static can_rx_queue_item_t rx_queue[CAN_RX_QUEUE_SIZE];
|
||||
static volatile u8 rx_queue_head = 0;
|
||||
static volatile u8 rx_queue_tail = 0;
|
||||
static volatile u8 rx_queue_count = 0;
|
||||
|
||||
static can_tx_queue_item_t tx_queue[CAN_TX_QUEUE_SIZE];
|
||||
static volatile u8 tx_queue_head = 0;
|
||||
static volatile u8 tx_queue_tail = 0;
|
||||
static volatile u8 tx_queue_count = 0;
|
||||
|
||||
// 发送队列使用的独立消息结构体
|
||||
static can_trasnmit_message_struct queue_transmit_message;
|
||||
// CAN FD DLC 9~15对应的非线性payload长度表
|
||||
static constexpr u8 CANFD_DLC_LENGTH_TABLE[7] = {12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
CAN_transmiter CAN0_transmiter; // CAN 初始化
|
||||
|
||||
@@ -288,36 +300,21 @@ void can_dma_init(void) {
|
||||
dma_struct_para_init(&dma_rx_parameter);
|
||||
dma_rx_parameter.periph_addr =
|
||||
(uint32_t)(&CAN_RFIFOMDATA0(CAN0, CAN_FIFO0)); // CAN 接收数据寄存器地址
|
||||
dma_rx_parameter.memory_addr = (uint32_t)can_rx_buffer; // 接收缓冲区地址
|
||||
dma_rx_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; // 外设到内存
|
||||
dma_rx_parameter.memory_width = DMA_MEMORY_WIDTH_8BIT; // 内存宽度 8 位
|
||||
dma_rx_parameter.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; // 外设宽度 8 位
|
||||
dma_rx_parameter.priority = DMA_PRIORITY_HIGH; // 高优先级
|
||||
dma_rx_parameter.number = 8; // 传输字节数
|
||||
dma_rx_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // 外设地址不递增
|
||||
dma_rx_parameter.memory_addr = (uint32_t)can_rx_dma_words; // 接收 DMA 缓冲区地址
|
||||
dma_rx_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; // 外设到内存
|
||||
dma_rx_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT; // 内存宽度 32 位
|
||||
dma_rx_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT; // 外设宽度 32 位
|
||||
dma_rx_parameter.priority = DMA_PRIORITY_HIGH; // 高优先级
|
||||
dma_rx_parameter.number = 16; // 最多 16 个 word = 64 字节
|
||||
dma_rx_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // CAN FIFO 数据端口不递增
|
||||
dma_rx_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE; // 内存地址递增
|
||||
dma_init(DMA0, DMA_CH4, &dma_rx_parameter); // 使用 DMA 通道 4
|
||||
dma_init(DMA0, DMA_CH4, &dma_rx_parameter); // 使用 DMA 通道 4
|
||||
dma_memory_to_memory_enable(DMA0, DMA_CH4); // CAN 无独立 DMA request 时,按帧启动 M2M 读取 FIFO 数据端口
|
||||
|
||||
// 配置发送 DMA
|
||||
dma_struct_para_init(&dma_tx_parameter);
|
||||
dma_tx_parameter.periph_addr =
|
||||
(uint32_t)(&CAN_TMI0(CAN0)); // CAN 发送数据寄存器地址
|
||||
dma_tx_parameter.memory_addr = (uint32_t)can_tx_buffer; // 发送缓冲区地址
|
||||
dma_tx_parameter.direction = DMA_MEMORY_TO_PERIPHERAL; // 内存到外设
|
||||
dma_tx_parameter.memory_width = DMA_MEMORY_WIDTH_8BIT; // 内存宽度 8 位
|
||||
dma_tx_parameter.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; // 外设宽度 8 位
|
||||
dma_tx_parameter.priority = DMA_PRIORITY_HIGH; // 高优先级
|
||||
dma_tx_parameter.number = 8; // 传输字节数
|
||||
dma_tx_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // 外设地址不递增
|
||||
dma_tx_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE; // 内存地址递增
|
||||
dma_init(DMA0, DMA_CH5, &dma_tx_parameter); // 使用 DMA 通道 5
|
||||
|
||||
// 使能 DMA 通道
|
||||
dma_channel_enable(DMA0, DMA_CH4);
|
||||
dma_channel_enable(DMA0, DMA_CH5);
|
||||
|
||||
// 使能 CAN 接收 DMA
|
||||
// can_dma_enable(CAN0, CAN_DMA_RECEIVE);
|
||||
// RX DMA 按帧启动,初始化时不使能 CH4,避免无有效帧时搬运垃圾数据
|
||||
dma_channel_disable(DMA0, DMA_CH4);
|
||||
can_rx_dma_busy = false;
|
||||
memset(can_rx_dma_words, 0, sizeof(can_rx_dma_words));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -390,7 +387,7 @@ void can_config(void) {
|
||||
*/
|
||||
void canfd_config(void) {
|
||||
can_gpio_init();
|
||||
can_dma_init(); // 初始化 DMA
|
||||
can_dma_init();
|
||||
can_parameter_struct can_parameter;
|
||||
can_fdframe_struct can_fd_parameter;
|
||||
can_fd_tdc_struct can_fd_tdc_parameter;
|
||||
@@ -451,11 +448,12 @@ void canfd_config(void) {
|
||||
|
||||
/* configure CAN0 NVIC */
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 1, 0);
|
||||
nvic_irq_enable(CAN0_TX_IRQn, 1, 1);
|
||||
/* enable can receive FIFO0 not empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
// 使能 DMA 中断
|
||||
nvic_irq_enable(DMA0_Channel4_IRQn, 1, 1);
|
||||
dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
|
||||
dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF | DMA_INT_ERR);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -651,9 +649,19 @@ u8 CAN_transmiter::init() {
|
||||
/* initialize receive message */
|
||||
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
|
||||
|
||||
// 初始化收发队列和标志位
|
||||
rx_queue_head = 0;
|
||||
rx_queue_tail = 0;
|
||||
rx_queue_count = 0;
|
||||
tx_queue_head = 0;
|
||||
tx_queue_tail = 0;
|
||||
tx_queue_count = 0;
|
||||
can0_send_flag = RESET;
|
||||
|
||||
// 初始化 DMA 缓冲区
|
||||
memset(can_rx_buffer, 0, sizeof(can_rx_buffer));
|
||||
memset(can_tx_buffer, 0, sizeof(can_tx_buffer));
|
||||
memset(can_rx_dma_words, 0, sizeof(can_rx_dma_words));
|
||||
can_rx_dma_busy = false;
|
||||
|
||||
// 初始化节点 ID 为默认值
|
||||
node_id = DEFAULT_NODE_ID;
|
||||
@@ -663,6 +671,216 @@ u8 CAN_transmiter::init() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t CAN_EnterCritical(void) {
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
return primask;
|
||||
}
|
||||
|
||||
static void CAN_ExitCritical(uint32_t primask) { __set_PRIMASK(primask); }
|
||||
|
||||
static u8 CANFD_DlcToLength(u8 dlc) {
|
||||
return (dlc <= 8U) ? dlc
|
||||
: ((dlc <= 15U) ? CANFD_DLC_LENGTH_TABLE[dlc - 9U] : 0U);
|
||||
}
|
||||
|
||||
static u8 CANFD_NormalizeLength(u8 length) {
|
||||
if (length <= 8U)
|
||||
return length;
|
||||
for (u8 i = 0; i < sizeof(CANFD_DLC_LENGTH_TABLE); i++) {
|
||||
if (length <= CANFD_DLC_LENGTH_TABLE[i]) {
|
||||
return CANFD_DLC_LENGTH_TABLE[i];
|
||||
}
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static u8 CANFD_WordCount(u8 length) { return (length + 3U) / 4U; }
|
||||
|
||||
static void CAN_RX_QueuePushFromIsr(const can_receive_message_struct &message) {
|
||||
if (rx_queue_count < CAN_RX_QUEUE_SIZE) {
|
||||
rx_queue[rx_queue_tail].id = message.rx_efid;
|
||||
rx_queue[rx_queue_tail].length = message.rx_dlen;
|
||||
if (rx_queue[rx_queue_tail].length > 64) {
|
||||
rx_queue[rx_queue_tail].length = 64;
|
||||
}
|
||||
for (int i = 0; i < rx_queue[rx_queue_tail].length; i++) {
|
||||
rx_queue[rx_queue_tail].data[i] = message.rx_data[i];
|
||||
}
|
||||
rx_queue_tail = (rx_queue_tail + 1) % CAN_RX_QUEUE_SIZE;
|
||||
rx_queue_count++;
|
||||
} else {
|
||||
CAN_DEBUG_PRINT("RX queue full, message dropped\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void CAN_RX_ReleaseFifo0(void) { CAN_RFIFO0(CAN0) |= CAN_RFIFO0_RFD0; }
|
||||
|
||||
static u8 CAN_RX_Fifo0PendingCount(void) {
|
||||
return can_receive_message_length_get(CAN0, CAN_FIFO0);
|
||||
}
|
||||
|
||||
static bool CAN_TX_HasEmptyMailbox(void) {
|
||||
return (can_flag_get(CAN0, CAN_FLAG_TME0) != RESET) ||
|
||||
(can_flag_get(CAN0, CAN_FLAG_TME1) != RESET) ||
|
||||
(can_flag_get(CAN0, CAN_FLAG_TME2) != RESET);
|
||||
}
|
||||
|
||||
static void CAN_RX_ReadMetadata(can_receive_message_struct *message) {
|
||||
uint8_t dlc;
|
||||
uint32_t rfifomi = CAN_RFIFOMI(CAN0, CAN_FIFO0);
|
||||
uint32_t rfifomp = CAN_RFIFOMP(CAN0, CAN_FIFO0);
|
||||
uint32_t canfd_en = CAN_FDCTL(CAN0) & CAN_FDCTL_FDEN;
|
||||
|
||||
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, message);
|
||||
message->rx_ff = (uint8_t)(CAN_RFIFOMI_FF & rfifomi);
|
||||
if (CAN_FF_STANDARD == message->rx_ff) {
|
||||
message->rx_sfid = (uint32_t)(GET_RFIFOMI_SFID(rfifomi));
|
||||
} else {
|
||||
message->rx_efid = (uint32_t)(GET_RFIFOMI_EFID(rfifomi));
|
||||
}
|
||||
message->rx_ft = (uint8_t)(CAN_RFIFOMI_FT & rfifomi);
|
||||
message->rx_fi = (uint8_t)(GET_RFIFOMP_FI(rfifomp));
|
||||
message->fd_flag = (uint8_t)((CAN_RFIFOMP_FDF & rfifomp) >> 7);
|
||||
dlc = (uint8_t)(GET_RFIFOMP_DLENC(rfifomp));
|
||||
if ((canfd_en != 0U) && (message->fd_flag != CAN_FDF_CLASSIC)) {
|
||||
message->rx_dlen = CANFD_DlcToLength(dlc);
|
||||
message->fd_brs = (uint8_t)((rfifomp & CAN_RFIFOMP_BRS) >> 5);
|
||||
message->fd_esi = (uint8_t)((rfifomp & CAN_RFIFOMP_ESI) >> 4);
|
||||
} else {
|
||||
message->rx_dlen = (dlc <= 8U) ? dlc : 8U;
|
||||
}
|
||||
}
|
||||
|
||||
static void CAN_RX_StartPayloadDma(const can_receive_message_struct &metadata) {
|
||||
can_rx_dma_message = metadata;
|
||||
if (can_rx_dma_message.rx_dlen > 64) {
|
||||
can_rx_dma_message.rx_dlen = 64;
|
||||
}
|
||||
|
||||
u8 word_count = CANFD_WordCount(can_rx_dma_message.rx_dlen);
|
||||
if (word_count == 0) {
|
||||
CAN_RX_QueuePushFromIsr(can_rx_dma_message);
|
||||
CAN_RX_ReleaseFifo0();
|
||||
return;
|
||||
}
|
||||
|
||||
can_rx_dma_busy = true;
|
||||
dma_channel_disable(DMA0, DMA_CH4);
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
|
||||
dma_periph_address_config(DMA0, DMA_CH4,
|
||||
(uint32_t)(&CAN_RFIFOMDATA0(CAN0, CAN_FIFO0)));
|
||||
dma_memory_address_config(DMA0, DMA_CH4, (uint32_t)can_rx_dma_words);
|
||||
dma_transfer_number_config(DMA0, DMA_CH4, word_count);
|
||||
dma_channel_enable(DMA0, DMA_CH4);
|
||||
}
|
||||
|
||||
static void CAN_RX_PumpFifo0(void) {
|
||||
while (!can_rx_dma_busy) {
|
||||
if (CAN_RX_Fifo0PendingCount() == 0U) {
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
return;
|
||||
}
|
||||
|
||||
can_receive_message_struct temp_message;
|
||||
CAN_RX_ReadMetadata(&temp_message);
|
||||
|
||||
if (temp_message.rx_ff == CAN_FF_EXTENDED) {
|
||||
CAN_RX_StartPayloadDma(temp_message);
|
||||
} else {
|
||||
CAN_RX_ReleaseFifo0();
|
||||
CAN_DEBUG_PRINT("Drop standard CAN frame in CANFD path\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 CAN_RX_QueuePop(can_rx_queue_item_t *item) {
|
||||
u8 popped = 0U;
|
||||
uint32_t primask = CAN_EnterCritical();
|
||||
if (rx_queue_count == 0) {
|
||||
CAN_ExitCritical(primask);
|
||||
return 0U;
|
||||
}
|
||||
*item = rx_queue[rx_queue_head];
|
||||
rx_queue_head = (rx_queue_head + 1) % CAN_RX_QUEUE_SIZE;
|
||||
rx_queue_count--;
|
||||
popped = 1U;
|
||||
CAN_ExitCritical(primask);
|
||||
|
||||
return popped;
|
||||
}
|
||||
|
||||
static u8 CAN_TX_QueuePush(const can_trasnmit_message_struct &message) {
|
||||
u8 queued = 0U;
|
||||
uint32_t primask = CAN_EnterCritical();
|
||||
if (tx_queue_count < CAN_TX_QUEUE_SIZE) {
|
||||
tx_queue[tx_queue_tail].message = message;
|
||||
tx_queue[tx_queue_tail].valid = 1U;
|
||||
tx_queue_tail = (tx_queue_tail + 1U) % CAN_TX_QUEUE_SIZE;
|
||||
tx_queue_count++;
|
||||
queued = 1U;
|
||||
}
|
||||
CAN_ExitCritical(primask);
|
||||
|
||||
if (queued != 0U) {
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
CAN_DEBUG_PRINT("TX queue full, message dropped\r\n");
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static u8 CAN_TX_QueuePeek(can_trasnmit_message_struct *message) {
|
||||
u8 has_message = 0U;
|
||||
uint32_t primask = CAN_EnterCritical();
|
||||
if (tx_queue_count != 0U) {
|
||||
*message = tx_queue[tx_queue_head].message;
|
||||
has_message = 1U;
|
||||
}
|
||||
CAN_ExitCritical(primask);
|
||||
return has_message;
|
||||
}
|
||||
|
||||
static u8 CAN_TX_QueuePop(can_trasnmit_message_struct *message) {
|
||||
u8 popped = 0U;
|
||||
uint32_t primask = CAN_EnterCritical();
|
||||
if (tx_queue_count != 0U) {
|
||||
*message = tx_queue[tx_queue_head].message;
|
||||
tx_queue[tx_queue_head].valid = 0U;
|
||||
tx_queue_head = (tx_queue_head + 1U) % CAN_TX_QUEUE_SIZE;
|
||||
tx_queue_count--;
|
||||
popped = 1U;
|
||||
}
|
||||
CAN_ExitCritical(primask);
|
||||
return popped;
|
||||
}
|
||||
|
||||
static void CAN_TX_DisableTmeIfQueueEmpty(void) {
|
||||
uint32_t primask = CAN_EnterCritical();
|
||||
if (tx_queue_count == 0U) {
|
||||
can_interrupt_disable(CAN0, CAN_INTEN_TMEIE);
|
||||
}
|
||||
CAN_ExitCritical(primask);
|
||||
}
|
||||
|
||||
static void CAN_TX_ServiceQueue(void) {
|
||||
can_trasnmit_message_struct queued_message;
|
||||
while (CAN_TX_HasEmptyMailbox()) {
|
||||
if (CAN_TX_QueuePeek(&queued_message) == 0U) {
|
||||
CAN_TX_DisableTmeIfQueueEmpty();
|
||||
return;
|
||||
}
|
||||
if (can_message_transmit(CAN0, &queued_message) == CAN_NOMAILBOX) {
|
||||
CAN_DEBUG_PRINT(
|
||||
"Mailbox became unavailable while draining TX queue\r\n");
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
|
||||
return;
|
||||
}
|
||||
CAN_TX_QueuePop(&queued_message);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN 数据更新
|
||||
*/
|
||||
@@ -757,9 +975,15 @@ void CAN_transmiter::communication_check() {
|
||||
can0_send_flag = RESET;
|
||||
}
|
||||
|
||||
// 处理所有接收到的 CAN 消息(从环形缓冲区中)
|
||||
can_receive_message_struct current_message;
|
||||
while (dequeue_rx_message(current_message)) {
|
||||
// 处理所有接收到的 CANFD 消息(从底层中断队列中取出)
|
||||
can_rx_queue_item_t rx_item;
|
||||
while (CAN_RX_QueuePop(&rx_item)) {
|
||||
can_receive_message_struct current_message;
|
||||
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, ¤t_message);
|
||||
current_message.rx_efid = rx_item.id;
|
||||
current_message.rx_dlen = rx_item.length;
|
||||
memcpy(current_message.rx_data, rx_item.data, rx_item.length);
|
||||
|
||||
// 提取基础 ID (低 16 位,去除高 16 位节点 ID 部分)
|
||||
u32 base_id = current_message.rx_efid & 0xFFFF;
|
||||
|
||||
@@ -771,11 +995,14 @@ void CAN_transmiter::communication_check() {
|
||||
// 判断是广播消息还是其他节点的命令
|
||||
if (sender_node_id == BROADCAST_NODE_ID || sender_node_id != node_id) {
|
||||
// 广播消息或其他节点的命令 → 进入静默模式(停发 10 秒)
|
||||
CAN_DEBUG_PRINT("Received base_id=0x0000 from node %d, entering silent mode for 10s\r\n", sender_node_id);
|
||||
CAN_DEBUG_PRINT(
|
||||
"Received base_id=0x0000 from node %d, entering silent mode for 10s\r\n",
|
||||
sender_node_id);
|
||||
enter_silent_mode();
|
||||
} else {
|
||||
// 自己节点的命令 → 执行 BOOT 功能
|
||||
CAN_DEBUG_PRINT("Received base_id=0x0000 from self, jumping to BOOT\r\n");
|
||||
CAN_DEBUG_PRINT(
|
||||
"Received base_id=0x0000 from self, jumping to BOOT\r\n");
|
||||
motor_sleep();
|
||||
flashEEP.save_system_config(false);
|
||||
fmc_unlock();
|
||||
@@ -800,8 +1027,7 @@ void CAN_transmiter::communication_check() {
|
||||
if (current_message.rx_dlen >= 2) {
|
||||
new_node_id = unpack_bytes_to_u16(current_message.rx_data, 0);
|
||||
} else {
|
||||
new_node_id =
|
||||
current_message.rx_data[0]; // 只发送 1 字节时直接使用
|
||||
new_node_id = current_message.rx_data[0]; // 只发送 1 字节时直接使用
|
||||
}
|
||||
u16 old_node_id = node_id; // 保存旧节点 ID 用于构建响应 ID
|
||||
CAN_DEBUG_PRINT(
|
||||
@@ -811,7 +1037,7 @@ void CAN_transmiter::communication_check() {
|
||||
if (new_node_id <= MAX_NODE_ID && new_node_id != BROADCAST_NODE_ID) {
|
||||
// 先发送响应(使用旧节点ID构建CAN ID)
|
||||
// 响应数据格式:[status:1byte][new_node_id:2byte] = 3 字节
|
||||
transmit_data[0] = 0x01; // 成功
|
||||
transmit_data[0] = 0x01; // 成功
|
||||
transmit_data[1] = (u8)(new_node_id & 0xFF); // 新 ID 低字节
|
||||
transmit_data[2] =
|
||||
(u8)((new_node_id >> 8) & 0xFF); // 新 ID 高字节
|
||||
@@ -819,36 +1045,39 @@ void CAN_transmiter::communication_check() {
|
||||
// 使用旧节点 ID 发送响应
|
||||
node_id = old_node_id;
|
||||
u8 send_result = CANFD_AsyncSend(build_can_id(CANFD_SET_NODE_ID), 3,
|
||||
transmit_data);
|
||||
transmit_data);
|
||||
|
||||
// 然后保存新节点 ID 到 Flash
|
||||
u8 save_status = save_node_id_to_flash(new_node_id);
|
||||
|
||||
CAN_DEBUG_PRINT("SET_NODE_ID: save_status=%d, send_result=%d\r\n",
|
||||
save_status, send_result);
|
||||
CAN_DEBUG_PRINT(
|
||||
"SET_NODE_ID: save_status=%d, send_result=%d\r\n",
|
||||
save_status, send_result);
|
||||
|
||||
if (save_status == FLASH_EEPROM_OK) {
|
||||
CAN_DEBUG_PRINT("SET_NODE_ID: SUCCESS, node_id updated from %d to %d\r\n",
|
||||
old_node_id, new_node_id);
|
||||
CAN_DEBUG_PRINT(
|
||||
"SET_NODE_ID: SUCCESS, node_id updated from %d to %d\r\n",
|
||||
old_node_id, new_node_id);
|
||||
} else {
|
||||
CAN_DEBUG_PRINT("SET_NODE_ID: Flash write FAILED, status=%d\r\n",
|
||||
save_status);
|
||||
CAN_DEBUG_PRINT(
|
||||
"SET_NODE_ID: Flash write FAILED, status=%d\r\n",
|
||||
save_status);
|
||||
// 发送错误响应
|
||||
transmit_data[0] = 0x00; // 失败
|
||||
node_id = old_node_id;
|
||||
CANFD_AsyncSend(build_can_id(CANFD_SET_NODE_ID), 3,
|
||||
transmit_data);
|
||||
transmit_data);
|
||||
}
|
||||
} else {
|
||||
// 发送错误响应 - 使用旧节点 ID 构建响应 ID
|
||||
CAN_DEBUG_PRINT("SET_NODE_ID: invalid new_id=%d (max=%d)\r\n",
|
||||
new_node_id, MAX_NODE_ID);
|
||||
new_node_id, MAX_NODE_ID);
|
||||
transmit_data[0] = 0x00; // 失败
|
||||
transmit_data[1] = (u8)(new_node_id & 0xFF);
|
||||
transmit_data[2] = (u8)((new_node_id >> 8) & 0xFF);
|
||||
node_id = old_node_id; // 临时恢复旧 ID 用于构建响应
|
||||
CANFD_AsyncSend(build_can_id(CANFD_SET_NODE_ID), 3,
|
||||
transmit_data);
|
||||
transmit_data);
|
||||
// 保持原 ID 不变
|
||||
}
|
||||
continue; // SET_NODE_ID 命令处理完跳过后续逻辑
|
||||
@@ -919,7 +1148,7 @@ void CAN_transmiter::communication_check() {
|
||||
if (first_byte >> 3 & 0x01) {
|
||||
KTH7823.angle_set(0);
|
||||
Angle_kalman.init(0); // 角度滤波
|
||||
Vel_kalman.init(0); // 角度滤波
|
||||
Vel_kalman.init(0); // 角度滤波
|
||||
}
|
||||
// 休眠
|
||||
if (eigth_byte & 0x80 >> 7) {
|
||||
@@ -939,7 +1168,7 @@ void CAN_transmiter::communication_check() {
|
||||
delay_1ms(1);
|
||||
if (app_enable == OTA_AVAL && app_check == OTA_AVAL) {
|
||||
CANFD_AsyncSend(build_can_id(CANFD_OTA_ACK_ID), 2,
|
||||
transmit_data);
|
||||
transmit_data);
|
||||
}
|
||||
}
|
||||
// 查询节点 ID 命令 (基础 ID: 0x0402)
|
||||
@@ -948,7 +1177,7 @@ void CAN_transmiter::communication_check() {
|
||||
CANFD_AsyncSend(build_can_id(CANFD_GET_NODE_ID), 2, transmit_data);
|
||||
} else {
|
||||
CAN_DEBUG_PRINT("Unknown CAN ID: %X (node_id=%d)\n",
|
||||
current_message.rx_efid, node_id);
|
||||
current_message.rx_efid, node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -982,17 +1211,10 @@ u8 CAN_transmiter::CAN_Wakeup() {
|
||||
* @retval 无
|
||||
*/
|
||||
void CAN0_RX0_IRQHandler(void) {
|
||||
// 检查是否是 FIFO0 消息挂起中断
|
||||
if (can_interrupt_flag_get(CAN0, CAN_INT_FLAG_RFL0) != RESET) {
|
||||
// 清除中断标志
|
||||
can_interrupt_flag_clear(CAN0, CAN_INT_FLAG_RFL0);
|
||||
|
||||
// 直接读取消息(包括数据),不依赖DMA
|
||||
can_receive_message_struct temp_message;
|
||||
can_message_receive(CAN0, CAN_FIFO0, &temp_message);
|
||||
|
||||
// 将接收到的消息加入环形缓冲区
|
||||
CAN0_transmiter.enqueue_rx_message_from_isr(temp_message);
|
||||
// FIFO0 非空时,关中断并持续抽空 FIFO;DMA 完成后由 DMA ISR 继续续传。
|
||||
if (CAN_RX_Fifo0PendingCount() != 0U) {
|
||||
can_interrupt_disable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
CAN_RX_PumpFifo0();
|
||||
}
|
||||
|
||||
// 检查其他可能的中断源
|
||||
@@ -1014,14 +1236,32 @@ void CAN0_RX0_IRQHandler(void) {
|
||||
* @retval 无
|
||||
*/
|
||||
void DMA0_Channel4_IRQHandler(void) {
|
||||
if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_ERR)) {
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
|
||||
dma_channel_disable(DMA0, DMA_CH4);
|
||||
if (can_rx_dma_busy) {
|
||||
CAN_RX_ReleaseFifo0();
|
||||
can_rx_dma_busy = false;
|
||||
}
|
||||
CAN_DEBUG_PRINT("CAN RX DMA error, frame dropped\r\n");
|
||||
CAN_RX_PumpFifo0();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_FTF)) {
|
||||
// 清除 DMA 传输完成中断标志
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);
|
||||
// 将 DMA 缓冲区的数据复制到接收消息结构体
|
||||
for (int i = 0; i < CAN0_transmiter.receive_message.rx_dlen && i < 8;
|
||||
i++) {
|
||||
CAN0_transmiter.receive_message.rx_data[i] = can_rx_buffer[i];
|
||||
dma_channel_disable(DMA0, DMA_CH4);
|
||||
if (!can_rx_dma_busy) {
|
||||
CAN_RX_PumpFifo0();
|
||||
return;
|
||||
}
|
||||
memcpy(can_rx_dma_message.rx_data, can_rx_dma_words,
|
||||
can_rx_dma_message.rx_dlen);
|
||||
CAN_RX_QueuePushFromIsr(can_rx_dma_message);
|
||||
CAN_RX_ReleaseFifo0();
|
||||
can_rx_dma_busy = false;
|
||||
CAN_RX_PumpFifo0();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,12 +1270,7 @@ void DMA0_Channel4_IRQHandler(void) {
|
||||
* @retval 无
|
||||
*/
|
||||
void DMA0_Channel5_IRQHandler(void) {
|
||||
if (dma_interrupt_flag_get(DMA0, DMA_CH5, DMA_INT_FLAG_FTF)) {
|
||||
// DMA 传输完成,可以在此处执行后续处理
|
||||
// 清除 DMA 传输完成中断标志
|
||||
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_FTF);
|
||||
// 可以在此添加后续处理逻辑,如发送下一个数据包等
|
||||
}
|
||||
// 保留空实现:发送链路改用 CAN mailbox + TME 中断队列。
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1087,50 +1322,6 @@ u8 CAN_transmiter::CAN_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向发送队列添加消息
|
||||
* @param id CAN消息ID
|
||||
* @param length CAN消息长度
|
||||
* @param data CAN消息数据
|
||||
* @retval 1=成功, 0=队列满
|
||||
*/
|
||||
static u8 CAN_TX_QueuePush(u32 id, u8 length, u8 *data) {
|
||||
if (tx_queue_count >= CAN_TX_QUEUE_SIZE) {
|
||||
CAN_DEBUG_PRINT("TX queue full, message dropped\r\n");
|
||||
return 0; // 队列满,丢弃消息
|
||||
}
|
||||
|
||||
tx_queue[tx_queue_tail].id = id;
|
||||
tx_queue[tx_queue_tail].length = length;
|
||||
for (int i = 0; i < length && i < 64; i++) {
|
||||
tx_queue[tx_queue_tail].data[i] = data[i];
|
||||
}
|
||||
tx_queue[tx_queue_tail].valid = 1;
|
||||
|
||||
tx_queue_tail = (tx_queue_tail + 1) % CAN_TX_QUEUE_SIZE;
|
||||
tx_queue_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从发送队列取出消息
|
||||
* @param item 指向队列项的指针
|
||||
* @retval 1=成功, 0=队列空
|
||||
*/
|
||||
static u8 CAN_TX_QueuePop(can_tx_queue_item_t *item) {
|
||||
if (tx_queue_count == 0) {
|
||||
return 0; // 队列空
|
||||
}
|
||||
|
||||
*item = tx_queue[tx_queue_head];
|
||||
tx_queue[tx_queue_head].valid = 0;
|
||||
tx_queue_head = (tx_queue_head + 1) % CAN_TX_QUEUE_SIZE;
|
||||
tx_queue_count--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异步 CANFD 数据发送 (使用队列机制防止丢帧)
|
||||
* @param id CAN 消息 ID
|
||||
@@ -1138,42 +1329,32 @@ static u8 CAN_TX_QueuePop(can_tx_queue_item_t *item) {
|
||||
* @param data CAN 消息数据
|
||||
*/
|
||||
u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
u8 valid_length = length;
|
||||
u8 valid_length = 0U;
|
||||
// 检查 CANFD 模式是否启用
|
||||
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
|
||||
if ((CAN_FDCTL(CAN0) & CAN_FDCTL_FDEN) == 0U) {
|
||||
CAN_DEBUG_PRINT("CANFD mode not enabled\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
if (data == nullptr && length != 0U) {
|
||||
CAN_DEBUG_PRINT("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据长度是否符合 CANFD 规范
|
||||
if (length > 8) {
|
||||
if (length > 8 and length < 13) {
|
||||
valid_length = 12;
|
||||
} else if (length > 12 and length < 17) {
|
||||
valid_length = 16;
|
||||
} else if (length > 16 and length < 21) {
|
||||
valid_length = 20;
|
||||
} else if (length > 20 and length < 25) {
|
||||
valid_length = 24;
|
||||
} else if (length > 24 and length < 33) {
|
||||
valid_length = 32;
|
||||
} else if (length > 32 and length < 49) {
|
||||
valid_length = 48;
|
||||
} else if (length > 48 and length < 65) {
|
||||
valid_length = 64;
|
||||
} else {
|
||||
CAN_DEBUG_PRINT("CANFD data length error\r\n");
|
||||
return 0;
|
||||
}
|
||||
// 检查数据长度是否符合 CANFD 规范,并映射到合法 DLC 长度
|
||||
if (length == 0U) {
|
||||
valid_length = 0U;
|
||||
} else {
|
||||
valid_length = CANFD_NormalizeLength(length);
|
||||
}
|
||||
if ((length != 0U) && (valid_length == 0U)) {
|
||||
CAN_DEBUG_PRINT("CANFD data length error\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
|
||||
transmit_message.tx_efid = id; // 扩展帧 ID
|
||||
@@ -1183,12 +1364,10 @@ u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD 帧格式
|
||||
transmit_message.fd_brs = ENABLE; // 使能比特率切换
|
||||
transmit_message.fd_esi = DISABLE; // 错误状态指示
|
||||
// 复制数据到发送缓冲区
|
||||
memset(transmit_message.tx_data, 0, sizeof(transmit_message.tx_data));
|
||||
for (int i = 0; i < valid_length; i++) {
|
||||
if (i < length) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
} else {
|
||||
transmit_message.tx_data[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,7 +1378,7 @@ u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
if (transmit_mailbox == CAN_NOMAILBOX) {
|
||||
// 没有可用的 mailbox,将消息加入发送队列
|
||||
CAN_DEBUG_PRINT("No available mailbox, adding to TX queue\r\n");
|
||||
return CAN_TX_QueuePush(id, valid_length, data);
|
||||
return CAN_TX_QueuePush(transmit_message);
|
||||
}
|
||||
|
||||
// 启用 CAN 发送中断以检测传输完成(用于队列发送)
|
||||
@@ -1211,36 +1390,7 @@ u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
|
||||
* @brief CAN 传输中断处理函数(支持队列发送)
|
||||
*/
|
||||
void CAN0_TX_IRQHandler(void) {
|
||||
// 检查是否有发送邮箱空闲
|
||||
if (can_flag_get(CAN0, CAN_FLAG_TME0) != RESET ||
|
||||
can_flag_get(CAN0, CAN_FLAG_TME1) != RESET ||
|
||||
can_flag_get(CAN0, CAN_FLAG_TME2) != RESET) {
|
||||
|
||||
can_tx_queue_item_t next_msg;
|
||||
// 尝试从队列中取出下一条消息发送
|
||||
if (CAN_TX_QueuePop(&next_msg)) {
|
||||
// 配置并发送队列中的消息(使用独立的队列消息结构体)
|
||||
queue_transmit_message.tx_ft = CAN_FT_DATA;
|
||||
queue_transmit_message.tx_ff = CAN_FF_EXTENDED;
|
||||
queue_transmit_message.tx_efid = next_msg.id;
|
||||
queue_transmit_message.tx_dlen = next_msg.length;
|
||||
queue_transmit_message.fd_flag = CAN_FDF_FDFRAME;
|
||||
queue_transmit_message.fd_brs = ENABLE;
|
||||
queue_transmit_message.fd_esi = DISABLE;
|
||||
|
||||
for (int i = 0; i < next_msg.length; i++) {
|
||||
queue_transmit_message.tx_data[i] = next_msg.data[i];
|
||||
}
|
||||
|
||||
can_message_transmit(CAN0, &queue_transmit_message);
|
||||
} else {
|
||||
// 队列为空,禁用发送中断
|
||||
can_interrupt_disable(CAN0, CAN_INTEN_TMEIE);
|
||||
}
|
||||
|
||||
// 清除发送中断标志
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME0);
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME1);
|
||||
can_flag_clear(CAN0, CAN_FLAG_TME2);
|
||||
if (CAN_TX_HasEmptyMailbox()) {
|
||||
CAN_TX_ServiceQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ u8 can_gpio_init(void); // CAN 引脚初始化
|
||||
void can_config(void); // CAN 初始化
|
||||
void canfd_config(void); // CANFD 初始化
|
||||
void can_dma_init(void); // CAN DMA 初始化
|
||||
void CAN0_TX_IRQHandler(void); // CAN 发送中断处理函数
|
||||
void CAN0_RX0_IRQHandler(void); // CAN 接收中断处理函数
|
||||
void DMA0_Channel4_IRQHandler(void); // DMA 通道 4 中断处理函数 (CAN 接收)
|
||||
void DMA0_Channel5_IRQHandler(void); // DMA 通道 5 中断处理函数 (CAN 发送)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
#ifndef _CAN_H
|
||||
#define _CAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include "gd32c10x_can.h"
|
||||
#include "config.h"
|
||||
|
||||
// 定义一个联合体类型用于 float 和 byte 数组之间的转换
|
||||
typedef union {
|
||||
float f;
|
||||
u8 b[4];
|
||||
} float_union_t;
|
||||
|
||||
// 添加辅助函数用于将 u16 类型数据打包到 u8 数组中
|
||||
static inline void pack_u16_to_bytes(u8 *buffer, u16 offset, u16 value) {
|
||||
buffer[offset] = (u8)(value & 0xFF);
|
||||
buffer[offset + 1] = (u8)((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
// 添加辅助函数用于将 float 类型数据打包到 u8 数组中
|
||||
static inline void pack_float_to_bytes(u8 *buffer, u16 offset,
|
||||
float_union_t &float_union) {
|
||||
buffer[offset] = float_union.b[0];
|
||||
buffer[offset + 1] = float_union.b[1];
|
||||
buffer[offset + 2] = float_union.b[2];
|
||||
buffer[offset + 3] = float_union.b[3];
|
||||
}
|
||||
|
||||
// 添加辅助函数用于从 u8 数组中解包 short 类型数据
|
||||
static inline short unpack_bytes_to_short(u8 *buffer, u16 offset) {
|
||||
short value = (short)(buffer[offset] | (buffer[offset + 1] << 8));
|
||||
return value;
|
||||
}
|
||||
|
||||
// 添加辅助函数用于从 u8 数组中解包 u16 类型数据
|
||||
static inline u16 unpack_bytes_to_u16(u8 *buffer, u16 offset) {
|
||||
u16 value = (u16)(buffer[offset] | (buffer[offset + 1] << 8));
|
||||
return value;
|
||||
}
|
||||
|
||||
// 添加辅助函数用于从 u8 数组中解包 float 类型数据
|
||||
static inline float_union_t unpack_bytes_to_float(u8 *buffer, u16 offset) {
|
||||
float_union_t float_union;
|
||||
float_union.b[0] = buffer[offset];
|
||||
float_union.b[1] = buffer[offset + 1];
|
||||
float_union.b[2] = buffer[offset + 2];
|
||||
float_union.b[3] = buffer[offset + 3];
|
||||
return float_union;
|
||||
}
|
||||
|
||||
u8 can_gpio_init(void); // CAN 引脚初始化
|
||||
void can_config(void); // CAN 初始化
|
||||
void canfd_config(void); // CANFD 初始化
|
||||
void can_dma_init(void); // CAN DMA 初始化
|
||||
void CAN0_RX0_IRQHandler(void); // CAN 接收中断处理函数
|
||||
void DMA0_Channel4_IRQHandler(void); // DMA 通道 4 中断处理函数 (CAN 接收)
|
||||
void DMA0_Channel5_IRQHandler(void); // DMA 通道 5 中断处理函数 (CAN 发送)
|
||||
void jumpToBOOT();
|
||||
|
||||
void can_loopback_init(void);
|
||||
void can_loopback_test(void);
|
||||
|
||||
/*!
|
||||
\brief CAN 通信类
|
||||
\note 封装 CAN 发送和接收功能,支持多电机节点 ID 隔离
|
||||
*/
|
||||
class CAN_transmiter {
|
||||
|
||||
private:
|
||||
static const uint8_t CAN_RX_BUFFER_SIZE = 8; // CAN 接收缓冲区大小
|
||||
static const u32 CAN_SILENT_DURATION_MS = 10000; // CAN 静默时长 10 秒
|
||||
|
||||
bool is_sleep = false; // 是否休眠
|
||||
bool is_silent = false; // 是否静默(收到 base_id=0x0000 后进入静默)
|
||||
u32 silent_start_time = 0; // 静默开始时间(ms)
|
||||
|
||||
u16 node_id; // 本节点 ID(0-254),使用 CAN ID 高 8 位存储 (在 init() 中初始化为 DEFAULT_NODE_ID)
|
||||
u8 Target_Control_Mode = 0; // 目标控制模式
|
||||
u8 controller_Mode = 0; // 当前模式
|
||||
short mcu_temp = 0; // MCU 温度
|
||||
short motor_temp = 0; // 电机温度
|
||||
u16 Power_Voltage = 0; // 电源电压
|
||||
|
||||
u16 limit_voltage = 0; // 限制电压
|
||||
|
||||
float_union_t rt_angle_union = {0}; // 实时角度
|
||||
float_union_t rt_velocity_union = {0}; // 实时速度
|
||||
float_union_t rt_current_union = {0}; // 实时电流
|
||||
|
||||
float_union_t target_angle_union = {0}; // 目标角度
|
||||
float_union_t target_velocity_union = {0}; // 目标速度
|
||||
float_union_t target_current_union = {0}; // 目标电流
|
||||
|
||||
float_union_t u_current_union = {0}; // U 相电流
|
||||
float_union_t w_current_union = {0}; // W 相电流
|
||||
float_union_t v_current_union = {0}; // V 相电流
|
||||
|
||||
bool MotorStatus = 0; // 电机状态码
|
||||
u8 EEPROMStatus = 0; // EEPROM 状态码
|
||||
|
||||
can_trasnmit_message_struct transmit_message; // 发送消息结构体
|
||||
u8 transmit_mailbox = CAN_NOMAILBOX; // 初始化为无 mailbox 状态
|
||||
u8 transmit_data[64]; // CANFD 最大 64 字节
|
||||
|
||||
// CAN 接收消息队列
|
||||
can_receive_message_struct rx_message_buffer[CAN_RX_BUFFER_SIZE];
|
||||
volatile uint8_t rx_buffer_head = 0;
|
||||
volatile uint8_t rx_buffer_tail = 0;
|
||||
|
||||
void update(); // 更新数据
|
||||
u8 CAN_Receive(); // CAN 接收
|
||||
u8 CANFD_Receive(); // CANFD 接收
|
||||
bool is_rx_buffer_full();
|
||||
bool is_rx_buffer_empty();
|
||||
bool dequeue_rx_message(can_receive_message_struct& message);
|
||||
void check_silent_mode(); // 检查静默模式是否结束
|
||||
|
||||
public:
|
||||
// 节点 ID 相关辅助函数 (使用高 16 位存储节点 ID)
|
||||
u32 build_can_id(u32 base_id); // 根据节点 ID 构建 CAN ID,格式:[节点 ID(16 位)][基础 ID(16 位)]
|
||||
bool is_message_for_me(u32 received_id); // 判断消息是否发给本节点
|
||||
|
||||
public:
|
||||
// 添加构造函数声明
|
||||
u8 init(void);
|
||||
|
||||
can_receive_message_struct receive_message; // 接收消息结构体
|
||||
FlagStatus can0_send_flag; // CAN0 发送标志
|
||||
float_union_t testfloat_union = {0}; // 测试用
|
||||
u16 test_u16 = 0;
|
||||
|
||||
bool MagStatus = 0; // 磁状态码
|
||||
bool ThermalStatus = 0; // 热能状态码
|
||||
void communication_check(); // 通信检查
|
||||
u8 CAN_Sleep(); // CAN 进入睡眠
|
||||
u8 CAN_Wakeup(); // CAN 唤醒
|
||||
u8 CAN_AsyncSend(u32 ID, u8 length, u8 *data); // CAN 异步发送 (使用 DMA)
|
||||
u8 CANFD_AsyncSend(u32 ID, u8 length, u8 *data); // CANFD 异步发送 (使用 DMA)
|
||||
u8 CAN_all_Send(); // CAN 发送
|
||||
u8 CANFD_all_Send(); // CANFD 发送
|
||||
void enter_silent_mode(); // 进入静默模式(停发 10 秒)
|
||||
bool is_in_silent_mode(); // 检查是否在静默模式中
|
||||
|
||||
// 节点 ID 管理接口
|
||||
u16 get_node_id(); // 获取当前节点 ID
|
||||
void set_node_id(u16 new_id); // 设置节点 ID
|
||||
u8 load_node_id_from_flash(); // 从 Flash 加载节点 ID
|
||||
u8 save_node_id_to_flash(u16 new_id); // 保存节点 ID 到 Flash
|
||||
|
||||
// 中断处理函数需要访问的公共接口
|
||||
void enqueue_rx_message_from_isr(const can_receive_message_struct& message) {
|
||||
if (!is_rx_buffer_full()) {
|
||||
rx_message_buffer[rx_buffer_head] = message;
|
||||
rx_buffer_head = (rx_buffer_head + 1) % CAN_RX_BUFFER_SIZE;
|
||||
}
|
||||
// 如果缓冲区满,丢弃新消息
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user