基于FPGA的CAN总线控制器的设计(下)
今天给大侠带来基于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总线通信控制器提供了一个可以应用的案例。
本篇到此结束,各位大侠有缘再见!
END
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!
精彩推荐
基于FPGA的扩频系统设计(下)
基于FPGA的单目内窥镜定位系统设计(下)
在word文档中添加“原汁原味”代码
FPGA工程师就业班,9月份开课!
基于FPGA的CAN总线控制器的设计(下)相关推荐
- 基于FPGA的CAN总线控制器的设计(上)
今天给大侠带来基于FPGA的CAN总线控制器的设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,CAN 总线协议解析以及 CAN 通信控制器程序基本框架.话不多说,上货. 导读 CAN 总线(Cont ...
- 基于FPGA的智能PID控制器的设计与实现
1.问题描述: PID控制器产生于1915年,PID控制律的概念最早是由LYAPIMOV提出的,到目前为止,PID控制器以及改进的PID控制器在工业控制领域里最为常见.PID控制器(比例-积分-微分控 ...
- 基于FPGA的CAN总线控制器(支持CANFD)
前段时间在公司做了一个CAN控制器IP,支持CAN2.0B和CANFD协议,IP是通过Qsys封装成Avalon_MM接口和Avalon_ST接口,通过system console在stratixii ...
- 基于OMAPL138 + FPGA嵌入式喷涂机器人控制器的设计
喷涂是现今许多行业中喷涂是现今许多行业中应用最普遍的一种涂装方式,随着越来越多的行业对计算机数字控制技术的发展,使得现代喷涂作业中机器人喷涂已经越来越成为一种趋势.国外机器人喷涂技术较为成熟,其研究工 ...
- 基于FPGA的USB接口控制器设计(VHDL)(中)
今天给大侠带来基于 FPGA 的 USB 接口控制器设计(VHDL),由于篇幅较长,分三篇.今天带来第二篇,中篇,USB通信原理.USB 系统开发以及设计实例.话不多说,上货. 之前有关于 Veril ...
- 基于FPGA的XPT2046触摸控制器设计
基于FPGA的XPT2046触摸控制器设计 小梅哥编写,未经许可,文章内容和所涉及代码不得用于其他商业销售的板卡 本实例所涉及代码均可通过向 xiaomeige_fpga@foxmail.com 发 ...
- 基于FPGA的USB接口控制器设计(VHDL)(上)
今天给大侠带来基于 FPGA 的 USB 接口控制器设计(VHDL),由于篇幅较长,分三篇.今天带来第一篇,上篇,USB 接口简介 以及 USB 体系结构.话不多说,上货. 之前有关于 Verilio ...
- 基于FPGA的SPI FLASH控制器设计
1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...
- 基于 FPGA 的模拟 I²C协议设计(中)
今天给大侠带来基于FPGA的 模拟 I²C 协议设计,由于篇幅较长,分三篇.今天带来第二篇,中篇,I²C 协议的具体实现.话不多说,上货. 之前也有相关文章介绍,这里超链接一下,仅供各位大侠参考. 源 ...
最新文章
- less 命令(转)
- 前端面试题——HTML基础篇
- [设计模式]简单工厂和工厂方法模式适用场景
- RegExp类型exec()方法的返回值说明
- AMD 发布第二代EPYC处理器,重新定义数据中心新标准
- golang.org/x/lint安装失败
- perl语言学习笔记(3)列表与数组、子程序’、参数
- Unix环境高级编程(十九)终端I/O
- 谷粒商城:14.全文检索ElasticSearch
- matlab2010 mex,怎样在Matlab2010a中使用VS2010的mex
- Firebug工具离线安装
- 那些活在浪里的创业者最终被拍成了电影
- Windows任务栏图标变白解决方案
- 从王自如和老罗的论战中我貌似懂得了点神马...
- 如何解决C++编译错误C2280尝试引用已删除的函数【每天一个小技巧】
- PDF.js特殊字体、水印加载不出来问题解决
- Kotlin拿Android本地视频缩略图
- 遍历操作__getitem__
- (转)在日企面试如何主动给自己加分
- 下一个行业风口:NFT 数字藏品,是机遇还是泡沫?