随着汽车和航空航天领域嵌入式系统的飞速发展,系统内通信对数据带宽和有效载荷容量的需求日益增长。带有可变数据速率的控制器局域网络(CAN FD)协议通过增强经典 CAN 总线的功能,成功应对了这一挑战。AS32S601 作为国科安芯推出的一款高性能 32 位 RISC-V 微控制器。尽管 CAN FD 将单帧的最大载荷扩展至 64 字节^^^^^^^^,但许多应用场景,如无线固件升级(OTA)、高分辨率传感器数据流传输以及高级诊断等,仍需传输远超此限制的数据块。
本文旨在为在 AS32S601 微控制器上实现稳健的多帧数据传输解决方案提供一份全面的技术指南,讨论内容覆盖了 CAN FD 的核心概念、AS32S601 外设的架构、包括接收状态机在内的详细软件实现策略,以及确保实时性能和系统可靠性的关键系统级注意事项。
一、核心机制设计
CAN帧主要包含两个主要部分:仲裁阶段和数据阶段。在传统CAN中,全帧以一个固定的比特率发送。在CAN FD中,如果启用了BRS位,数据阶段则以更高的比特率发送。这种较高的比特率通常是标称比特率的2至8倍。CAN帧中不包含任何表明比特率具体值的内容。
就像在传统CAN中一样,比特率作为系统设计的一部分是固定值,总线上的所有设备在发送和接收数据之前都必须知道该值。只是对于CAN FD,如果BRS处于激活状态,那您必须知道标称比特率和数据比特率。
传统CAN最大8字节,而CAN FD支持单帧从8字节扩展至64字节(DLC编码对应12/16/20/24/32/48/64字节)。
CAN FD协议本身单帧最大支持64字节数据,若需处理超过64字节的数据,需通过以下方式实现:
该原理设计通过分段速率控制与协议层优化,在保持CAN总线非破坏性仲裁优势的同时,实现吞吐量5-15倍提升。实际部署时需注意电磁兼容性设计,特别是高速率下的信号完整性。
实现方法:将大数据包按CAN FD支持的DLC分段,发送端拆分数据,接收端重组。
二、多帧传输协议
在实际应用中,当数据量超过单帧CAN FD的最大容量时,就需要采用多帧处理机制。这一机制通常包括首帧(First Frame, FF)、连续帧(Consecutive Frame, CF)和流控帧(Flow Control, FC)。首帧负责携带数据总长度和首段数据,通知接收方开始接收;连续帧则按照顺序传输剩余数据。流控帧由接收方发送,用于控制发送节奏,包含连续接收最大帧数(Block Size, BS)和帧间最小间隔时间(STmin)等参数。
[首帧FF] → [流控FC] → [连续帧CF] → ... → [CRC校验]
接收方通过流控帧(FC)指定:
- 单帧(Single Frame):≤64字节直接传输
- 超时重传(默认300ms)
- CRC校验失败触发自动重传
该代码实现包含以下核心功能:
- 支持ISO-TP协议标准的多帧拆分与重组
- 采用状态机管理接收流程,处理首帧(FF)和连续帧(CF)
- 实现序列号校验和自动重传机制
- 兼容单帧传输(≤64字节)和多帧传输(>64字节)场景
#include < string.h >
#define CANFD_MAX_DLC 64
#define ISO_TP_PCI_TYPE_FF 0x10 // 首帧标识
#define ISO_TP_PCI_TYPE_CF 0x20 // 连续帧标识
typedef **struct** {
uint8_t data[CANFD_MAX_DLC];
} CANFD_Frame;
// 发送多帧数据
**void** send_multiframe(CANFD_TypeDef* CANFDx, uint8_t *data, uint16_t len) {
CANFD_Frame frame;
uint8_t chunk_size=0;
uint8_t seq=0;
uint16_t total_len = len;
// 首帧发送
**if** (len > CANFD_MAX_DLC - 2)
{
frame.data[0] = ISO_TP_PCI_TYPE_FF
frame.data[1] = len & 0xFF;
memcpy(&frame.data[2], data, CANFD_MAX_DLC - 2);
CANFD_Transmit(CANFDx, TB1, frame.data, CANFD_MAX_DLC);
// 连续帧发送
for(int i=0; i< total_len; i+=64)
{
uint8_t chunk_size = (total_len-i) > 64 ? 64 : (total_len-i);
frame.data[0] = ISO_TP_PCI_TYPE_CF| Seq;
memcpy(&frame.data[1], data[chunk_size-1], chunk_size);
CANFD_Transmit(CANFDx, TB1, frame.data, chunk_size);
Seq+=1;
}
}
// 单帧发送
**else** {
memcpy(frame.data, data, len);
CANFD_Transmit(CANFDx, TB1, frame.data, len);
}
}
// 接收状态机
typedef **enum** {
IDLE,
RECEIVING_FF,
RECEIVING_CF
} RxState;
typedef **struct** {
uint8_t buffer[4096];
uint16_t total_len;
uint16_t received;
uint8_t expected_seq;
RxState state;
} CANFD_RxHandler;
**void** process_canfd_frame(CANFD_TypeDef* CANFDx, CANFD_Frame *frame) {
uint8_t data_len =0;
data_len = CANFD_GetReceiveData(CANFD3, frame.data);
uint8_t pci_type = frame- >data[0] & 0xF0;
**switch** (handler- >state) {
**case** IDLE:
**if** (pci_type == ISO_TP_PCI_TYPE_FF) {
handler- >total_len = ((frame- >data[0] & 0x0F) < < 8) | frame- >data[1];
memcpy(handler- >buffer, &frame- >data[2], CANFD_MAX_DLC- 2);
handler- >received = CANFD_MAX_DLC- 2;
handler- >expected_seq = 1;
handler- >state = RECEIVING_CF;
}
**break** ;
**case** RECEIVING_CF:
**if** (pci_type == ISO_TP_PCI_TYPE_CF &&
((frame- >data[0] & 0x0F) == handler- >expected_seq)) {
memcpy(handler- >buffer + handler- >received,
&frame- >data[1], data_len);
handler- >received += data_len;
handler- >expected_seq = (handler- >expected_seq + 1) % 16;
**if** (handler- >received >= handler- >total_len) {
// 完整数据接收完成
handler- >state = IDLE;
}
}
**break** ;
}
}
三、定时器模拟多线程任务处理:
中断标志管理:
can_interrupt_flag 为CAN硬件中断标志,由CAN接收中断服务触发。
定时器1功能:
每100ms轮询can_interrupt_flag
检测到标志位后设置processing_interrupt阻止其他任务
模拟中断处理过程(此处用usleep模拟处理时间)
定时器2功能:
每1秒尝试执行任务
通过检查processing_interrupt决定是否执行任务
[CAN_ISR] 中断触发,设置标志位
[Timer1] 检测到中断,暂停其他任务
[Timer2] 任务暂停...
[Timer2] 任务暂停...
[Timer1] 中断处理完成,恢复任务
[Timer2] 执行常规任务
#include < stdio.h >
#include < stdlib.h >
// 全局标志位
volatile **int** can_interrupt_flag = 0;
volatile **int** processing_interrupt = 0;
// 模拟CAN中断服务程序(实际应由硬件触发)
**void** CANFD3_IRQ_Handler()
{
can_interrupt_flag = 1;
printf("[CAN_ISR] 中断触发,设置标志位n");
}
// 定时器1线程:检测CAN中断标志(每500ms检查)
**void** timer1_thread( **void** )
{
**if** (can_interrupt_flag) {
processing_interrupt = 1;
printf("[Timer1] 检测到中断,暂停其他任务n");
can_buffer_count();
can_interrupt_flag = 0; // 清除中断标志
processing_interrupt = 0; // 允许恢复任务
printf("[Timer1] 中断处理完成,恢复任务n");
}
**return** NULL;
}
// 定时器2线程:执行其他任务(每1秒执行)
**void** timer2_thread( **void** ) {
usleep(1000000); // 1000ms间隔
**if** (!processing_interrupt) {
printf("[Timer2] 执行常规任务n");
} **else** {
printf("[Timer2] 任务暂停...n");
}
**return** NULL;
}
**int** main {
// 创建两个定时器任务
TIM1_Config(99,0,0);
TIM2_Config(99,0,0);
**while** (1)
{
timer1_thread();
timer2_thread();
}
四、关键特性说明:
- 线程安全设计:通过volatile关键字确保中断与主程序间的数据可见性。
- 动态长度校验:在读取时验证数据长度是否符合预期。
- 高效内存管理:环形缓冲区避免内存碎片,适合嵌入式环境。
- 状态检测机制:通过is_full标志避免缓冲区溢出。
- 扩展性设计:可通过修改CAN_BUF_SIZE适应不同数据量需求。
实际应用时需配合CAN中断服务程序(ISR)调用can_buffer_put(),在主循环中处理完整数据帧。对于高可靠性场景,建议增加错误帧处理和BUS OFF状态恢复机制。
五、物理层要求:
- 使用ASM1042等CANFD收发器芯片
- 分支长度<1米,终端电阻120Ω
- 采样点设置在75%-82%范围
六、典型应用场景
- 车载网络升级
在车载网络中,CAN FD主要用于域控制器间的大数据传输,如ADAS(Advanced Driver Assistance Systems)传感器数据的高效传输。通过CAN FD网桥,它能够实现与传统CAN网络的兼容,使得车辆在升级过程中无需全面替换现有网络架构。然而,在实际部署时,需要特别注意电磁兼容性设计,尤其是高速率下的信号完整性,以避免数据传输错误和系统故障。
- 航天领域适配
CAN FD协议满足了卫星遥测数据高速传输的需求(5Mbps+64字节帧)。其高可靠性和低延迟特性,使得卫星能够及时、准确地将遥测数据传输回地面站。在这一领域,CAN FD通常与高性能的CAN FD收发器芯片配合使用,如ASM1042等,以确保数据传输的稳定性和准确性。同时,为了适应航天环境的特殊要求,还需要对CAN FD网络进行严格的可靠性测试和验证。
审核编辑 黄宇
-
微控制器
+关注
关注
48文章
8007浏览量
157399 -
数据传输
+关注
关注
9文章
2034浏览量
66354 -
CANFD
+关注
关注
0文章
95浏览量
5459
发布评论请先 登录
实时视频数据传输中接收端缓存区的设计
ROHM高速数据传输方式控制器
以太网控制器控制模块数据传输控制代码实现
下位机与PC机之间的数据传输问题解方法
请问连续多包数据的数据传输速度超过DSP的数据处理速度怎么解决?
DSP 内嵌CAN 控制器的邮箱方式数据传输
实时视频数据传输中接收端缓存区的设计
基于PCI总线的数据传输系统

ARM实现无线数据传输系统

DM642图像数据传输的优化

评论