简介
CAN总线作为工业和汽车领域最常用的通信总线,具有拓扑结构简洁、可靠性高、传输距离长等优点。CAN总线的非破坏性仲裁机制依赖于帧ID,CAN2.0A和CAN2.0B分别规定了11bit-ID(短ID)的标准帧和29bit-ID(长ID)的扩展帧,另外,还有远程帧这种数据请求机制。关于CAN总线的更多知识可以参考这个科普文章。
本库实现了一个轻量化但完备的FPGA CAN总线控制器,特点如下:
平台无关:纯 Verilog 编写,可以在 Altera 和 Xilinx 等各种 FPGA 上运行。
本地ID可固定配置为任意短ID。
发送: 仅支持以本地ID发送数据长度为4Byte的帧。
接收: 支持接收短ID或长ID的帧,接收帧的数据长度没有限制 (即支持0~8Byte) 。
接收帧过滤: 可针对短ID和长ID独立设置过滤器,只接收和过滤器匹配的数据帧。
自动响应远程帧: 当收到的远程帧与本地ID匹配时,自动将发送缓存中的下一个数据发送出去。若缓存为空,则重复发送上次发过的数据。
设计文件
RTL 文件夹包含3个设计代码文件,各文件功能如下表。你只需将这3个文件包含进工程,就可以调用顶层模块can_top.v进行CAN通信业务的开发。
| 文件名 | 功能 | 备注 |
|---|---|---|
| can_top.v | CAN控制器的顶层 | |
| can_level_packet.v | 帧级控制器,负责解析或生成帧,并实现非破坏性仲裁 | 被can_top.v调用 |
| can_level_bit.v | 位级控制器,负责收发bit,具有抗频率偏移的下降沿对齐机制 | 被can_level_packet.v调用 |
仿真文件
仿真相关的文件都在 SIM 文件夹中,其中:
tb_can_top.v 是针对 can_top.v 的 testbench 。
tb_can_top_run_iverilog.bat 包含了运行 iverilog 仿真的命令。
tb_can_top.v 描述了4个CAN总线设备互相进行通信的场景,每个设备都是一个 can_top 的例化,图1是每个设备的详细属性,各个设备互相接收的关系可以画成左侧的图,箭头代表了各个设备之间的接收关系。另外,每个CAN设备的驱动时钟并不严格是50MHz,而是有不同的±1%的偏移,这是为了模拟更糟糕的实际情况下,CAN控制器的“自动对齐”机制能否奏效。

图1:仿真中的4个CAN设备的详细参数
使用 iverilog 进行仿真前,需要安装 iverilog ,见:iverilog_usage
然后双击 tb_can_top_run_iverilog.bat 运行仿真。仿真运行完后,可以打开生成的 dump.vcd 文件查看波形。
顶层模块说明
本节介绍如何使用can_top.v,它的接口如下表。
| 信号名 | 方向 | 宽度 | 功能 | 备注 |
|---|---|---|---|---|
| rstn | 输入 | 1 | 低电平复位 | 在开始工作前需要拉低复位一下 |
| clk | 输入 | 1 | 驱动时钟 | 频率需要是CAN总线波特率的10倍以上,内部分频产生波特率 |
| can_rx | 输入 | 1 | CAN-PHY RX | 应通过FPGA的普通IO引出,接CAN-PHY芯片 (例如TJA1050) |
| can_tx | 输出 | 1 | CAN-PHY TX | 应通过FPGA的普通IO引出,接CAN-PHY芯片 (例如TJA1050) |
| tx_valid | 输入 | 1 | 发送有效 | 当=1时,若发送缓存未满(即tx_ready=1),则tx_data被送入发送缓存 |
| tx_ready | 输出 | 1 | 发送就绪 | 当=1时,说明发送缓存未满。与 tx_valid 构成一对握手信号 |
| tx_data | 输入 | 32 | 发送数据 | 当tx_valid=1时需要同步给出待发送数据 tx_data |
| rx_valid | 输出 | 1 | 接收有效 | 当=1时,rx_data上产生1字节的有效接收数据 |
| rx_last | 输出 | 1 | 接收最后字节指示 | 当=1时,说明当前的rx_data是一个帧的最后一个数据字节 |
| rx_data | 输出 | 8 | 接收数据 | 当rx_valid=1时,rx_data上产生1字节的有效接收数据 |
| rx_id | 输出 | 29 | 接收ID | 指示当前接收帧的ID,若为短ID则低11bit有效 |
| rx_ide | 输出 | 1 | 接收ID类型 | =1 说明当前接收帧是长ID,否则为短ID |
接入CAN总线
can_top.v的can_rx和can_tx接口需要引出到FPGA引脚上,并接CAN-PHY芯片(比如TJA1050),如图2。
图2:接入CAN总线的方式
注:这里注意一个坑,虽然FPGA的引脚(can_rx,can_tx)可以是3.3V电平的,但CAN-PHY的电源必须是5V的,否则对CAN总线的驱动力不够。另外,CAN-PHY要和FPGA共地。
用户发送接口
can_top.v的tx_valid,tx_ready,tx_data构成了流式输入接口,它们都与clk的上升沿对齐,用于向发送缓存中写入一个数据。只要发送缓冲区不为空,其中的数据会逐个被CAN控制器发送到CAN总线上。
tx_valid和tx_ready是一对握手信号,波形如下图,只有当tx_valid和tx_ready都为1时,tx_data才被写入缓存。tx_ready=0说明缓存已满,此时即使tx_valid=1,也无法写入缓存。不过,当发送频率不高而不至于让 CAN 总线达到饱和时,可以不用考虑缓存满(即tx_ready=0)的情况。
下图中,D0,D1,D2这3个数据被写入缓存,D0写入后,缓存已满,导致tx_ready=0,之后的3个周期D1都没有成功写入,但在第4个时钟周期tx_ready变成1,D1被写入。之后发送方主动空闲2个时钟周期后,D3也被写入。
每个数据都是4Byte(32bit)的,只要FIFO不为空,该CAN控制器就自动地每次发送一个帧,每帧一个数据,帧数据长度为4Byte。
_ __ __ __ __ __ __ __ __ __ __ __ clk \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ _____________________________ _____tx_valid ___________/ \___________/ \________ _________________ ________________________________tx_ready \_________________/ _____ _______________________ _____tx_data XXXXXXXXXXXX__D0_X___________D1__________XXXXXXXXXXXXX__D3_XXXXXXXXX
用户接收接口
can_top.v的rx_valid,rx_last,rx_data,rx_id,rx_ide构成了接收接口,它们都与clk的上升沿对齐。
当CAN总线上收到了一个与ID过滤器匹配的数据帧后,会将这一帧的字节逐个发送出来。设数据帧长为n字节,则rx_valid上会连续产生n个周期的高电平,同时rx_data上每拍时钟会产生一个收到的数据字节,在最后一拍会让rx_last=1,指示一帧的结束。在整个过程中,rx_id上出现该帧的ID(若为短ID,则只有低11bit有效),同时,rx_ide指示该帧为长ID还是短ID。
接收接口的波形图举例如下,该例中模块先后收到了一个短ID的,数据长度为4的数据帧,和一个长ID的,数据长度为2的数据帧。
__ __ __ __ __ __ __ __ __ __ __ clk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_ _______________________ ___________rx_valid _________/ \___________/ \_________ _____ _____rx_last ___________________________/ \_________________/ \_________ _____ _____ _____ _____ _____ _____rx_data XXXXXXXXXX__0__X__1__X__2__X__3__XXXXXXXXXXXXX__0__X__1__XXXXXXXXXX _______________________ ___________rx_id XXXXXXXXXX__________ID1__________XXXXXXXXXXXXX____ID2____XXXXXXXXXX _____________________rx_ide _____________________________________________/
与发送接口不同,接收接口无握手机制,只要收到数据就让rx_valid=1来发出,不会等待接收方是否能接受。
配置本地ID
can_top.v有一个11bit的参数(parameter)叫LOCAL_ID,它决定了该模块发送的帧的ID;同时,当can_top接收的远程帧的ID与LOCAL_ID匹配时,就会进行响应(ACK),并自动回复一个数据帧(如果发送缓存为空,则自动重复回复上次发过的数据)。
配置ID过滤器
can_top.v的RX_ID_SHORT_FILTER和RX_ID_SHORT_MASK参数用来配置短ID过滤器。设收到的数据帧的ID是rxid(短),匹配表达式为:
rxid & RX_ID_SHORT_MASK == RX_ID_SHORT_FILTER & RX_ID_SHORT_MASK
以上表达式满足 Verilog 或 C 语言的语法。表达式为真时,rxid与过滤器匹配,这样的数据帧才能被模块响应(ACK),并将其数据转发到用户接受接口上。表达式为假时,rxid与过滤器不匹配,该数据帧不仅不会被响应(ACK),也不会被转发到用户接受接口上。
同理,RX_ID_LONG_FILTER和RX_ID_LONG_MASK参数用来配置长ID过滤器。设收到的数据帧的ID是rxid(长),匹配表达式为:
rxid & RX_ID_LONG_MASK == RX_ID_LONG_FILTER & RX_ID_LONG_MASK
MASK参数可以被称为通配掩码,掩码=1的位必须匹配FILTER,掩码=0的位我们不在乎,既可以匹配1也可以匹配0。
例如你想接收 0x122, 0x123, 0x1a2, 0x1a3 这4种短ID,则可配置为:
RX_ID_SHORT_FILTER = 11'h122,RX_ID_SHORT_MASK = 11'h17e
配置时序参数
can_top.v的default_c_PTS,default_c_PBS1,default_c_PBS2这3个时序参数决定了CAN总线上的一个位的3个段(PTS段, PBS1段, PBS2段)的默认长度,这3个段的含义详见这个科普文章。总的来说,分频系数计算如下:
分频系数 = default_c_PTS + default_c_PBS1 + default_c_PBS2 + 1
而CAN总线的波特率计算方法为:
CAN波特率 = clk频率 / 分频系数
例如,在 clk=50MHz的情况下,可以使用如下参数组合来配置出各种常见的波特率。
| 分频系数 | 波特率 | default_c_PTS | default_c_PBS1 | default_c_PBS2 |
|---|---|---|---|---|
| 50 | 1MHz | 16'd34 | 16'd5 | 16'd10 |
| 100 | 500kHz | 16'd69 | 16'd10 | 16'd20 |
| 500 | 100kHz | 16'd349 | 16'd50 | 16'd100 |
| 5000 | 10kHz | 16'd3499 | 16'd500 | 16'd1000 |
| 10000 | 5kHz | 16'd6999 | 16'd1000 | 16'd2000 |
示例程序
FPGA 目录里的fpga_top.v是一个调用can_top.v进行简单的 CAN 通信的案例。要运行该案例,请建立 FPGA 工程,并加入以下源文件:
FPGA 目录里的 fpga_top.v 、 uart_tx.v 。
RTL 目录里的 can_top.v 、 can_level_packet.v 、 can_level_bit.v 。
fpga_top.v 是项目的顶层,其引脚连接方法如下:
module fpga_top ( // clock ,连接到 FPGA 板上晶振,频率必须为 50MHz input wire CLK50M, // UART (TX only), 连接到电脑串口(比如通过 USB 转 UART 模块),不方便接 UART 可以不接 outputwire UART_TX, // CAN bus, 连接到 CAN PHY 芯片,然后 CAN PHY 连接到 CAN 总线(如图2) input wire CAN_RX, outputwire CAN_TX);
该案例的行为是:
本地 (也就是 FPGA) 的 CAN ID 配置为 0x456 ,因此所有发出的数据帧的 ID 都为 0x456 。
ID 过滤器配置为只接收短ID=0x123或长ID=0x12345678的数据帧。
每一秒向发送缓存中送入一个递增的数据,该数据帧并会被发送到 CAN 总线上。
将 CAN 总线上接收到的(也就是符合过滤器配置)的数据帧通过 UART 发送给电脑。
注:该案例中,CAN 的波特率为 1MHz ; UART 的格式为 115200,8,n,1

图3:硬件连接
我在测试该例子时,将 CAN 总线与一台USB-CAN调试器相连,如图3。然后编译工程并下载FPGA,打开USB-CAN调试器的配套软件,可以看到如下现象:
软件中每秒会收到一个 FPGA 发来的帧,数据长度DLC=4,值递增。如图4中没框的部分。
在软件中发送短ID=0x123或长ID=0x12345678的数据帧,会显示“发送成功”,如图4中蓝框的部分,说明该帧被 FPGA 响应了。同时,如果你把FPGA的UART连接到了电脑的串口,则可以在“串口助手”或“HyperTerminal”等软件上看到打印出的数据内容。
在软件中发送短ID=0x456的远程帧,FPGA 会立即响应一个数据帧,如图4中红框的部分。
图4:USB-CAN调试器的配套软件上观察到的现象
- 随机文章
- 热门文章
- 热评文章
- PPP新机制重磅文件出炉 直指民企“入场难”
- 追问|味觉异常可能增加脑卒中的患病风险?
- 让辽中南城市群迸发东北振兴增长极属性
- 深挖养老市场痛点 富德生命人寿开启养老“美好生活”
- 震旦“图书馆解决方案”亮相广州家博会,让学习更得心应手
- 乖宝宠物营养研究院弗列加特(上海)研发中心盛大揭幕
- 巴黎官方承诺塞纳河可作为奥运会游泳场地,NGO则警告水质状况堪忧
- 《气象峥嵘》出版,为上海城市文化建设提供样本
- 科华控股2023年年度董事会经营评述
- 钉钉正式上线AI助理市场AI月活企业已超170万家
- 中国人民解放军信息支援部队成立大会在京举行 习近平向信息支援部队授予军旗并致训词
- 铜价处于22周高点,高盛预测至少还能涨50%
- 美联储态度转鹰?普徕仕:预计今年仍会降息两次?
- 1“赛事+”提升城市“流量” 陕西商洛拓经济发展新“赛道”
- 2“五一”临近 持基过节的投资者要注意这几点
- 3华发股份:成功入选“人民优选”品牌 五一黄金周热销30亿
- 4钟鼓楼老街区的古都新事
- 5非常危险!女子摔成粉碎性骨折!又是因为洞洞鞋,夏天多人中招……
- 6金税四期试点上线,财税体制改革拉开帷幕!或有资金借道信创ETF基金(562030)逢跌进场布局
- 7到2027年产业规模达到2000亿元 浙江发布历史经典产业高质量发展计划
- 8初步数据:我国一季度经常账户顺差392亿美元
- 9IDC:24Q1全球PC出货量恢复增长 达到疫情前水平
- 10“发现山西之美”TDC旅游发现者大会举办:共话文旅新生态 邀客体验新玩法
- 11国门“夫妻档” 国庆共坚守
- 12北交所一周审核动态:2家企业更新进展 胜业电气二轮问询回复中称家电头部客户对价格敏感度较低
- 13(中国新貌)“国宝”大熊猫:栖居更美境 云游更广天
- 1大裁员下,特斯拉两名顶级高管离职
- 2奇瑞将与欧洲高端品牌签署技术平台授权协议
- 32024中国长三角青年企业家交流大会在杭州举办
- 4雷克萨斯GX中东版 全部在售 2023款 2022款 2020款 2019款 2018款成都远卓名车雷克萨斯GX中东版团购钜惠20万 欢迎上门试驾
- 5零跑C16将搭载中创新航磷酸铁锂电池
- 6Q1净利微增7%,宁德时代股东总数较2023年年末减少10728户
- 7哪吒,需要背水一战
- 8“新”中有“机”!创新服务承接新流量 撬动消费升级
- 9非创始版SU7何时交付 小米:工厂生产爬坡 全力提高产能
- 10央媒评卧铺挂帘:谁买的票谁做主
- 11江西南昌首部“多规合一”国土空间总体规划获批
- 12方程豹旗舰硬派越野!豹8正式亮相:仰望U8“青春版”登场
- 13583家族/造型霸气 方程豹豹8量产版发布



