FPGA设计-基于SJA1000的can控制器设计

目录

简介

芯片方案

设计注意点

设计代码


简介

般来说, 每个CAN 模块能够被分成3 个不同的功能块,其结构如图1所示。CAN总线收发器提供CAN协议控制器与物理总线之间的接口, 控制从CAN 控制器到总线物理层或相反的逻辑电平信号。它的性能决定了总线接口、总线终端、总线长度和节点数, 是影响整个总线网络通信性能的关键因素之一。CAN 控制器执行在CAN 规范里规定的完整的CAN 协议, 它通常用于报文缓冲和验收滤波, 对外具有与主控制器和总线收发器的接口。主控制器负责执行应用的功能, 例如控制命令的发送、读传感器和处理人机接口等。它通过对CAN 控制器进行编程, 来控制CAN 总线的工作方式和工作状态, 以及进行数据的发送和接收。

芯片方案

SJA1000的AD0~ AD7地址数据复用端口、ALE地址锁存端口、RD、WR、片选CS端口均通过转换芯片与FPGA的I /O口相连

SJA1000 的中断输出信号INT连入FPGA, 使CAN通信可以采用中断或查询方式。RST 端口的电路实现SJA1000的上电自动复位功能。MODE 模式选择端接+ 5 V, 设置SJA1000控制器为Intel模式。SJA1000 的时钟晶振采用16MH z, 频率调整电容取15 pF. R16为终端电阻,设计中取120Ω。CAN 驱动器PCA82C250 的RS脚为工作模式选择位, 接地工作于高速模式, 接高工作于待机模式。系统通过电阻R14将芯片设定于斜率控制模式, 电阻值为47 kΩ , 这时CAN 总线应工作于低速模式, 可提高CAN 总线抵抗射频干扰的能力。在这种情况下, 可直接使用非屏蔽双绞线作为总线。

设计注意点

设计中有2点需要特别注意:第一点是FPGA 并没有与SJA1000直接相连。这是因为对于设计选取的FPGAXCV600, 其接口电平不支持5 V TTL的I/O 标准, 如果与5 VI/O标准的SJA1000直接相连, 将可能导致FPGA 管脚电流过大, 造成器件锁死或者烧毁。为此采用双向总线收发器74ALVC164245, 把SJA1000的5 V TTL电平信号AD0 ~ AD7、

设计代码

`timescale 1ns/1ps

//-----------------------------------------------------------------------------------------------------------------------------------------//

// Project : sja1000驱动

// File :

// Version : 1.0

// Description: sja1000物理接口。

// Test Note : Intel Mode

//

//-----------------------------------------------------------------------------------------------------------------------------------------//

module sja1000_phy_intf

(

input sys_clk, //板载系统时钟50MHz

//内部寄存器读写接口

(* MARK_DEBUG="true" *)input wr_wvalid_i,

(* MARK_DEBUG="true" *)output reg wr_wready_o,

(* MARK_DEBUG="true" *)input [7:0] wr_addr_i,

(* MARK_DEBUG="true" *)input [7:0] wr_data_i,

(* MARK_DEBUG="true" *)output reg wr_done_o,

(* MARK_DEBUG="true" *)input rd_rready_i,

(* MARK_DEBUG="true" *)output reg rd_ack_o,

(* MARK_DEBUG="true" *)output reg rd_rvalid_o,

(* MARK_DEBUG="true" *)input [7:0] rd_addr_i,

(* MARK_DEBUG="true" *)output reg rd_done_o,

(* MARK_DEBUG="true" *)output wire [7:0] rd_data_o,

//sja1000物理接口

inout [7:0] sja1000_ad,

(* MARK_DEBUG="true" *)output reg sja1000_ale,

(* MARK_DEBUG="true" *)output reg sja1000_cs_n,

(* MARK_DEBUG="true" *)output reg sja1000_wr_n,

(* MARK_DEBUG="true" *)output reg sja1000_rd_n,

//电平转换器件控制信号

(* MARK_DEBUG="true" *)output wire sja1000_dir

);

(* MARK_DEBUG="true" *)reg sja_op_dir = 1'b1;

(* MARK_DEBUG="true" *)reg [7:0] wr_sja_adr_data = 8'b0;

//assign sja1000_dir = ~sja_op_dir;

assign sja1000_dir = sja_op_dir;

generate

genvar i;

for (i = 0; i < 8; i = i + 1) begin : gen_data

IOBUF #

(

.DRIVE ( 12 ), // Specify the output drive strength

.IBUF_LOW_PWR ( "TRUE" ), // Low Power - "TRUE", High Performance = "FALSE"

.IOSTANDARD ( "LVCMOS33" ), // Specify the I/O standard

.SLEW ( "SLOW" ) // Specify the output slew rate

) IOBUF_inst

(

.O ( rd_data_o[i] ), // Buffer output

.IO ( sja1000_ad[i] ), // Buffer inout port (connect directly to top-level port)

.I ( wr_sja_adr_data[i] ), // Buffer input

.T ( ~sja_op_dir ) // 3-state enable input, high=input, low=output

);

end

endgenerate

reg [3:0] sja_op_cnt = 4'd0;

localparam SJA_IDLE = 6'b00_0001, //01

WR_SJA_ADR = 6'b00_0010, //02

WR_SJA_DATA = 6'b00_0100, //04

WR_SJA_DONE = 6'b00_1000, //08

RD_SJA_ADR = 6'b01_0000, //10

RD_SJA_DATA = 6'b10_0000; //20

reg [5:0] sja_state = SJA_IDLE;

always@(posedge sys_clk)

begin

case(sja_state)

SJA_IDLE: begin

sja_op_dir <= 1'b0;

wr_sja_adr_data <= 8'd0;

wr_wready_o <= 1'b1;

wr_done_o <= 1'b0;

rd_rvalid_o <= 1'b0;

rd_done_o <= 1'b0;

sja1000_ale <= 1'b0;

sja1000_cs_n <= 1'b1;

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= 1'b1;

sja_op_cnt <= 4'd0;

if( wr_wvalid_i == 1'b1 ) //写寄存器操作

begin

sja_state <= WR_SJA_ADR;

wr_sja_adr_data <= wr_addr_i; //先写地址

end

else if( rd_rready_i == 1'b1 ) //读寄存器操作

begin

sja_state <= RD_SJA_ADR;

wr_sja_adr_data <= rd_addr_i; //先写地址

rd_ack_o <= 1'b1;

end

else begin

sja_state <= SJA_IDLE;

wr_sja_adr_data <= 8'b0;

rd_ack_o <= 1'b0;

end

end

//写地址

WR_SJA_ADR: begin

sja_op_dir <= 1'b1; //写进程中......

wr_wready_o <= 1'b0;

wr_sja_adr_data <= wr_addr_i;

//写器件触发

sja1000_ale <= ( sja_op_cnt >= 4'd0 && sja_op_cnt <= 4'd2 ) ? 1'b1 : 1'b0;

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= 1'b1;

sja1000_cs_n <= 1'b1;

sja_op_cnt <= ( sja_op_cnt != 4'd4) ? ( sja_op_cnt + 1 ) : 4'd0;

sja_state <= ( sja_op_cnt == 4'd4) ? WR_SJA_DATA:WR_SJA_ADR;

end

//写数据

WR_SJA_DATA: begin

sja_op_cnt <= ( sja_op_cnt != 4'd4 ) ? ( sja_op_cnt + 1 ) : 4'd0;

wr_sja_adr_data <= wr_data_i; //再写数据

sja1000_ale <= 1'b0; //写器件触发

sja1000_wr_n <= ( sja_op_cnt >= 4'd0 && sja_op_cnt <= 4'd3 ) ? 1'b0 : 1'b1;

sja1000_rd_n <= 1'b1;

sja1000_cs_n <= ( sja_op_cnt >= 4'd0 && sja_op_cnt <= 4'd3 ) ? 1'b0 : 1'b1;

sja_state <= ( sja_op_cnt == 4'd4 ) ? WR_SJA_DONE : WR_SJA_DATA;

end

//写操作完成

WR_SJA_DONE: begin //延迟2个时钟后再允许操作

//sja_op_cnt <= ( sja_op_cnt != 4'd1 ) ? ( sja_op_cnt + 1 ) : 4'd0;

sja_op_dir <= 1'b1;

wr_wready_o <= 1'b1;

//wr_done_o <= ( sja_op_cnt == 4'd1 ) ? 1'b1 : 1'b0;

wr_done_o <= 1'b1;

sja1000_ale <= 1'b0;

sja1000_cs_n <= 1'b1;

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= 1'b1;

//sja_state <= ( sja_op_cnt == 4'd1 ) ? SJA_IDLE : WR_SJA_DONE;

sja_state <= SJA_IDLE;

end

//读地址信息

RD_SJA_ADR: begin

rd_ack_o <= 1'b0; //读应答

sja_op_dir <= 1'b1; //写进程中......

wr_sja_adr_data <= rd_addr_i; //先传递地址信息

//写器件触发

sja1000_ale <= ( sja_op_cnt >= 4'd0 && sja_op_cnt <= 4'd2 ) ? 1'b1 : 1'b0;

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= 1'b1;

sja1000_cs_n <= 1'b1;

sja_op_cnt <= ( sja_op_cnt != 4'd4) ? ( sja_op_cnt + 1 ) : 4'd0;

sja_state <= ( sja_op_cnt == 4'd4) ? RD_SJA_DATA:RD_SJA_ADR;

end

//读数据

RD_SJA_DATA: begin

sja_op_cnt <= ( sja_op_cnt != 4'd5 ) ? ( sja_op_cnt + 1 ) : 4'd0;

sja_op_dir <= 1'b0;

rd_rvalid_o <= 1'b1;

sja1000_ale <= 1'b0;

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= ( sja_op_cnt >= 4'd1 && sja_op_cnt <= 4'd3 ) ? 1'b0 : 1'b1;

sja1000_cs_n <= ( sja_op_cnt >= 4'd0 && sja_op_cnt <= 4'd4 ) ? 1'b0 : 1'b1;

rd_done_o <= ( sja_op_cnt == 4'd4 ) ? 1'b1 : 1'b0;

sja_state <= ( sja_op_cnt == 4'd5 ) ? SJA_IDLE : RD_SJA_DATA;

end

default: begin

sja_state <= SJA_IDLE;

sja_op_dir <= 1'b0;

wr_sja_adr_data <= 8'd0;

wr_wready_o <= 1'b0;

wr_done_o <= 1'b0;

rd_rvalid_o <= 1'b0;

rd_ack_o <= 1'b0;

rd_done_o <= 1'b0;

sja_op_cnt <= 4'd0;

sja1000_ale <= 1'b0; //写器件触发

sja1000_wr_n <= 1'b1;

sja1000_rd_n <= 1'b1;

sja1000_cs_n <= 1'b1;

end

endcase

end

endmodule

相关推荐
俺不是西瓜太郎´•ﻌ•`2 小时前
大实验:基于赛灵思csg324100T,pmodMAXsonar的危险距离警报
fpga开发
ThreeYear_s5 小时前
基于FPGA的超声波显示水位距离,通过蓝牙传输水位数据到手机,同时支持RAM存储水位数据,读取数据。
fpga开发
szxinmai主板定制专家6 小时前
【飞腾AI加固服务器】全国产化飞腾+昇腾310+PCIe Switch的AI大模型服务器解决方案
运维·服务器·arm开发·人工智能·fpga开发
GateWorld7 小时前
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (三)数据格式
fpga开发·mipi csi2
hahaha601610 小时前
FPGA静态功耗
fpga开发
碎碎思10 小时前
FPGA定点和浮点数学运算-实例对比
fpga开发
GateWorld1 天前
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析LLP (二)
fpga开发·mipi csi2
hahaha60161 天前
Xilinx 325T FPGA 中的 GT(GTP 或 GTX)收发器和普通 LVDS 接口的差模和共模电压
fpga开发
hahaha60162 天前
FPGA没有使用的IO悬空对漏电流有没有影响
fpga开发
贝塔实验室2 天前
FPGA 动态重构配置流程
驱动开发·fpga开发·硬件架构·硬件工程·射频工程·fpga·基带工程