当前位置:网站首页>系统设计精选 | 基于FPGA的CAN总线控制器的设计(附代码)
系统设计精选 | 基于FPGA的CAN总线控制器的设计(附代码)
2022-07-30 09:43:00 【碎碎思】
今天给大侠带来基于FPGA的CAN总线控制器的设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试以及总结。话不多说,上货。
前两篇这里也放上超链接:
导读
CAN 总线(Controller Area Network)是控制器局域网的简称,是 20 世纪 80 年代初德国 BOSCH 公司为解决现代汽车中众多的控制与测试仪器之间的数据交换而开发的一种串行数据通信协议。目前,CAN 总线已经被列入 ISO 国际标准,称为 ISO11898。CAN 总线已经成为工业数据通信的主流技术之一。
CAN 总线作为数字式串行通信技术,与其他同类技术相比,在可靠性、实时性和灵活性方面具有独特的技术优势,主要特点如下:
CAN 总线是一种多主总线,总线上任意节点可在任意时刻主动地向网络上其他节点发送信息而不分主次,因此可在各节点之间实现自由通信。
CAN 总线采用非破坏性总线仲裁技术。但多个节点同时向总线发送信息时,优先级低的节点会主动退出发送,而最高优先级的节点可以不受影响地继续传输数据,从而大大节省总线冲突的仲裁时间。即使在网络负载很重的情况下也不会发生网络瘫痪情况。
CAN 总线的通信介质可以是双绞线、同轴电缆或光导纤维,选择灵活。
CAN 总线的通信速率可达 1Mbit/s(此时通信距离最长为 40 米),通信距离最远可达 10km(速率在 5kbit/s 以下)。
CAN 总线上的节点信息分成不同的优先级,可以满足不同级别的实时要求,高优先级的数据可以在 134μs 内得到传输。
CAN 总线通过报文滤波即可实现点对点、一点对多点及全局广播等几种方式传送数据,无需专门的调度。
CAN 总线的数据采用短帧结构,传输时间短,受干扰概率低,具有极好的检错效果。
CAN 总线采用 CRC 检验并可提供相应的错误处理功能,保证了数据通信的可靠性。
CAN 总线上的器件可被置于无任何内部活动的睡眠方式,相当于未连接到总线上,可以有效降低系统功耗。
CAN 总线上的节点在错误严重的情况下具有自动关闭输出的功能,以使总线上其他节点的操作不受影响。CAN 总线卓越的特性、极高的可靠性和独特的设计,特别适合工业过程中监控设备的互连,因此,越来越受到工业界的重视,并被公认为是最有前途的现场总线之一。另外,CAN 总线协议已被国际标准化组织认可,技术比较成熟,控制的芯片已经商品化,性价比高,特别适用于分布式测控系统之间的数通讯。
CAN 总线插卡可以任意插在 PC AT XT 兼容机上,方便地构成分布式监控系统。因此,用 FPGA 实现 CAN 总线通信控制器具有非常重要的应用价值。本篇将通过一个实例讲解利用 FPGA 实现 CAN 总线通信控制器的实现方法。
第三篇内容摘要:本篇会介绍程序的仿真与测试以及总结等相关内容。

四、程序的仿真与测试
CAN 总线通信控制器的仿真程序,需要模拟数据的发送和接收。
下面是测试程序的部分代码:
//连接 can_top 模块
can_top i_can_top(
.cs_can_i(cs_can),
.clk_i(clk),
.rx_i(rx_and_tx),
.tx_o(tx),
.irq_on(irq),
.clkout_o(clkout)
);
//产生 24 MHz 时钟
initial
begin
clk=0;
forever #21 clk = ~clk;
end
//初始化
initial
begin
start_tb = 0;
cs_can = 0;
rx = 1;
extended_mode = 0;
tx_bypassed = 0;
rst_i = 1'b0;
ale_i = 1'b0;
rd_i = 1'b0;
wr_i = 1'b0;
port_0_o = 8'h0;
port_0_en = 0;
port_free = 1;
rst_i = 1;
#200 rst_i = 0;
#200 start_tb = 1;
end
//产生延迟的 tx 信号(CAN 发送器延迟)
always
begin
wait (tx);
repeat (4*BRP) @ (posedge clk); // 4 time quants delay
#1 delayed_tx = tx;
wait (~tx);
repeat (4*BRP) @ (posedge clk); // 4 time quants delay
#1 delayed_tx = tx;
end
assign rx_and_tx = rx & (delayed_tx | tx_bypassed); // When this signal is on, tx is not
looped back to the rx.
//主程序
initial
begin
wait(start_tb);
//设置总线时序寄存器
write_register(8'd6, {`CAN_TIMING0_SJW, `CAN_TIMING0_BRP});
write_register(8'd7, {`CAN_TIMING1_SAM, `CAN_TIMING1_TSEG2, `CAN_TIMING1_TSEG1});
// 设置时钟分频寄存器
extended_mode = 1'b0;
write_register(8'd31, {extended_mode, 3'h0, 1'b0, 3'h0}); // Setting the normal mode (not
extended)
//设置接收代码和接收寄存器
write_register(8'd16, 8'ha6); // acceptance code 0
write_register(8'd17, 8'hb0); // acceptance code 1
write_register(8'd18, 8'h12); // acceptance code 2
write_register(8'd19, 8'h30); // acceptance code 3
write_register(8'd20, 8'h0); // acceptance mask 0
write_register(8'd21, 8'h0); // acceptance mask 1
write_register(8'd22, 8'h00); // acceptance mask 2
write_register(8'd23, 8'h00); // acceptance mask 3
write_register(8'd4, 8'he8); // acceptance code
write_register(8'd5, 8'h0f); // acceptance mask
#10;
repeat (1000) @ (posedge clk);
//开关复位模式
write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});
repeat (BRP) @ (posedge clk);
// 在复位后设置总线空闲
repeat (11) send_bit(1);
test_full_fifo; // test currently switched on
send_frame; // test currently switched off
bus_off_test; // test currently switched off
forced_bus_off; // test currently switched off
send_frame_basic; // test currently switched off
send_frame_extended; // test currently switched off
self_reception_request; // test currently switched off
manual_frame_basic; // test currently switched off
manual_frame_ext; // test currently switched off
$display("CAN Testbench finished !");
$stop;
end在测试过程中通过多个任务来分别验证程序的各个功能模块。下面的程序用于验证强制关闭总线任务:
//强制关闭总线任务
task forced_bus_off; // Forcing bus-off by writinf to tx_err_cnt register
begin
//切换到复位模式
write_register(8'd0, {7'h0, `CAN_MODE_RESET});
// 设置时钟分频寄存器
write_register(8'd31, {1'b1, 7'h0}); // Setting the extended mode (not normal)
// 写数据到寄存器中
write_register(8'd15, 255);
// 切换复位模式
write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});
#2500000;
// 切换复位模式
write_register(8'd0, {7'h0, `CAN_MODE_RESET});
// 写数据到寄存器中
write_register(8'd15, 245);
//关闭复位模式
write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});
#1000000;
end
endtask // forced_bus_off下面的程序验证如何发送一个基本格式的帧数据:
//发送一个基本格式的帧
task manual_frame_basic;
begin
// 切换到复位模式
write_register(8'd0, {7'h0, (`CAN_MODE_RESET)});
//设置寄存器
write_register(8'd4, 8'h28); // acceptance code
write_register(8'd5, 8'hff); // acceptance mask
repeat (100) @ (posedge clk);
// 切换复位模式
write_register(8'd0, {7'h0, ~(`CAN_MODE_RESET)});
// 模块复位后设置总线空闲
repeat (11) send_bit(1);
write_register(8'd10, 8'h55); // Writing ID[10:3] = 0x55
write_register(8'd11, 8'h57); // Writing ID[2:0] = 0x2, rtr = 1, length = 7
write_register(8'd12, 8'h00); // data byte 1
write_register(8'd13, 8'h00); // data byte 2
write_register(8'd14, 8'h00); // data byte 3
write_register(8'd15, 8'h00); // data byte 4
write_register(8'd16, 8'h00); // data byte 5
write_register(8'd17, 8'h00); // data byte 6
write_register(8'd18, 8'h00); // data byte 7
write_register(8'd19, 8'h00); // data byte 8
tx_bypassed = 1; // When this signal is on, tx is not looped back to the rx.
fork
begin
self_reception_request_command;
end
begin
#2200;
repeat (1)
//开始发送数据
begin
send_bit(0); // 帧起始
send_bit(0); // ID
send_bit(1); // ID
send_bit(0); // ID
send_bit(1); // ID
send_bit(0); // ID
send_bit(1); // ID
send_bit(0); // ID
send_bit(1); // ID
send_bit(0); // ID
send_bit(1); // ID
send_bit(0); // ID
send_bit(1); // RTR
send_bit(0); // IDE
send_bit(0); // r0
send_bit(0); // DLC
send_bit(1); // DLC
send_bit(1); // DLC
send_bit(1); // DLC
send_bit(1); // CRC
send_bit(1); // CRC
send_bit(0); // CRC stuff
send_bit(0); // CRC 6
send_bit(0); // CRC
send_bit(0); // CRC
send_bit(0); // CRC
send_bit(1); // CRC stuff
send_bit(0); // CRC 0
send_bit(0); // CRC
send_bit(1); // CRC
send_bit(0); // CRC
send_bit(1); // CRC 5
send_bit(1); // CRC
send_bit(0); // CRC
send_bit(1); // CRC
send_bit(1); // CRC b
send_bit(1); // CRC DELIM
send_bit(0); // ACK
send_bit(1); // ACK DELIM
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // EOF
send_bit(1); // INTER
send_bit(1); // INTER
send_bit(1); // INTER
end // repeat
end
join
//从接收缓冲中读取数据
read_receive_buffer;
release_rx_buffer_command;
read_receive_buffer;
release_rx_buffer_command;
read_receive_buffer;
#4000000;
end
endtask // manual_frame_basic
五、总结
本篇通过一个实例讲解如何用 FPGA 实现 CAN 总线通信控制器。首先讲解了 CAN 总线协议的有关内容,然后介绍了一种常用的 CAN 通信控制器 SJA1000 的主要特点。接下来讲解程序的主要框架和具体代码。最后通过一个测试程序验证了程序。这个实例为读者实现自己的 CAN总线通信控制器提供了一个可以应用的案例。

本篇到此结束,各位大侠有缘再见!
- -THE END- -
边栏推荐
- leetcode 剑指 Offer 52. 两个链表的第一个公共节点
- A new generation of free open source terminal tool, so cool
- BERT预训练模型系列总结
- Nacos configuration in the project of battle
- Beijing suddenly announced big news in the Metaverse
- Meikle Studio - see the actual combat notes of Hongmeng device development 4 - kernel development
- Re18: Read the paper GCI Everything Has a Cause: Leveraging Causal Inference in Legal Text Analysis
- Online target drone prompt.ml
- Soft Exam System Architect Concise Tutorial | Case Analysis | Requirement Analysis
- Domino Server SSL Certificate Installation Guide
猜你喜欢

PyQt5-绘制不同类型的直线

Re16: Read the paper ILDC for CJPE: Indian Legal Documents Corpus for Court Judgment Prediction and Explanation

flowable workflow all business concepts

包、类及四大权限和static

Online target drone prompt.ml

nacos实战项目中的配置

Nacos configuration in the project of battle

国外资源加速下载器,代码全部开源

线上靶机prompt.ml

论文阅读:SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers
随机推荐
New in GNOME: Warn users when Secure Boot is disabled
PyQt5 - Drawing different types of straight lines
Flink_CDC construction and simple use
105. Construct binary tree from preorder and inorder traversal sequence (video explanation!!)
OC-关于alloc和dealloc(还没开始写)
Shell系统学习之函数
【HMS core】【FAQ】HMS Toolkit典型问题合集1
判断一颗树是否为完全二叉树——视频讲解!!!
Beijing suddenly announced big news in the Metaverse
Matplotlib--plot markers
Meikle Studio - see the actual combat notes of Hongmeng equipment development five - drive subsystem development
梅科尔工作室-看鸿蒙设备开发实战笔记六—无线联网开发
The creation of a large root heap (video explanation)
Mysterious APT Attack
MySQL |子查询
Meikle Studio - see the actual combat notes of Hongmeng device development 4 - kernel development
时刻铭记:总有一天你将破蛹而出
方法的参数传递
Js array operating mobile for encapsulation
线程池方式开启线程--submit()和execute()的区别