CAN协议学习(二)MCAN控制器介绍
更多细节请参看MCAN2文档mcan2_ps.pdf。
一、MCAN2简介
MCAN2是Mentor公司开发的一个CAN2.0网络控制器的软核,初版2001年末版2006年。MCAN 2控制器实现了BOSCAN消息传输协议2.0a和2.0b。规范2.0a(相当于can 1.2)涵盖标准消息格式(11位标识符);规范2.0b涵盖标准和扩展消息格式(11位和29位标识符)。
二、总体架构
下图显示了MCAN2设计的主要功能块。
CPU对mcan 2的访问是通过独立的地址、输入数据和输出数据总线进行的。由主机设备将用于传输的消息放置到发送缓冲器中,以便由位处理器进行传输。设备接收到的消息首先由接收过滤器过滤,然后放入接收FIFO中。
CPU通过称为接收缓冲区的13字节窗口访问接收FIFO.结合接收FIFO使用接收缓冲区允许CPU在接收其他消息时处理一条消息。接收FIFO的总长度为64个字节,并以循环方式使用,使其能够同时容纳最多5个扩展的帧格式消息。
位定时逻辑块负责设备的波特率,并且是可编程的。所支持的波特率范围取决于主系统时钟XTAL1的频率,并且可以容易地跨越比BOSCH规范所选择的125kbud-1MBaud更宽的波特率范围。
CAN总线的接口由发送信号tx0、tx1和接收的rx 0提供。TX1通常与tx0相反,也可以编程为输出发送时钟,这对于测试非常有用。
三、发送、接收过程
要传输的数据以标准帧格式(SFF)或扩展帧格式(EFF)写入mcan 2的发送缓冲器(如下)。发送缓冲器包括CAN地址10h和1ch之间的13个字节,一个帧最多可以发送8个字节的数据。注意:在将数据写入缓冲区之前,需要检查传输缓冲区状态(状态寄存器,位2),以确保缓冲区“释放”(SR.2=‘1’)。当缓冲区被锁定时写入缓冲区的任何数据(SR.2=‘0’)都会丢失而没有任何指示。
发送缓冲器描述符字段的位布局如下所示.
FF代表frame format:0为标准帧,1为拓展帧。
RTR代表REMOTE TRANSMISSION REQUEST:1表示为远程帧。
DLC代表DATA LENGTH CODE:范围0-8,大于8的数被自动解释为8。
ID代表IDENTIFIER:标识符充当消息的名称,用于接收过滤,并确定总线访问优先级。标识符的二进制值越低,优先级就越高。在标准帧格式(SFF)中,标识符由11位(id.28至id.18)组成。在扩展帧格式(Eff)消息中,标识符由29位(id.28到id.0)组成。id.28是最高位,首先在总线上传输。
mcan 2接收的数据首先由接收滤波器过滤,然后传递给接收FIFO。接受过滤器只传递那些具有与接收过滤器寄存器中记录的消息相匹配的标识位的消息。
接收FIFO有64个字节深,允许最多5个完整扩展帧格式(EFF)消息的空间,并以循环方式使用。
放置在接收FIFO中的数据通过一个称为接收缓冲区的13字节窗口读取。该窗口位于can地址10h-1ch,即它占用与发送缓冲器相同的地址空间。与传输缓冲区一样,它足够宽,可以容纳一条包含最多8个字节数据的消息。
四、信号&寄存器描述
信号描述:
寄存器描述:
五、接收过滤
与过滤相关的寄存器:
10h-13h ACR0–3 Acceptance Code Registers 0-3
14h-17h AMR0–3 Acceptance Mask Registers 0-3
MCAN2的接收过滤模块首先将接收到的数据帧的ID部分与ACR即接收码寄存器比较,如果一致则接收,如果不一致则丢弃;AMR是接收掩码寄存器,如果某位设为‘1’,则将ACR对应的位设为‘不关心’。根据MOD.3为0或1来设置单过滤或双过滤模式,具体如下图。
六、时序图
七、测试程序(流程图&代码)
1 //test CAN 2019.03.22 by zhou 2 3 assign F_can_rx[0]=(F_can_tx[3]==1'b1)?F_can_tx[0]:((F_can_tx[0]==1'b1)?F_can_tx[3]:1'bZ); //star 4 assign F_can_rx[3]=(F_can_tx[0]==1'b1)?F_can_tx[3]:((F_can_tx[3]==1'b1)?F_can_tx[0]:1'bZ); //earth 5 6 assign F_can_rx[1]=(F_can_tx[2]==1'b1)?F_can_tx[1]:((F_can_tx[1]==1'b1)?F_can_tx[2]:1'bZ); //star 7 assign F_can_rx[2]=(F_can_tx[1]==1'b1)?F_can_tx[2]:((F_can_tx[2]==1'b1)?F_can_tx[1]:1'bZ); //earth 8 9 10 11 task CPU_READ_NPT; //just read data, no display 12 input [17:2] addr; 13 output [15:0] rddata; 14 15 begin 16 #120ns 17 @(posedge S_cpu_clk) 18 F_nrd = 1'b1; 19 F_nwr = 1'b1; 20 F_ncs = 1'b1; 21 F_addr =addr; 22 @(posedge S_cpu_clk) 23 F_nrd = 1'b0; 24 F_nwr = 1'b1; 25 F_ncs = 1'b0; 26 F_addr =addr; 27 @(posedge S_cpu_clk) 28 wait (F_nrdy==0); 29 rddata = F_data_o; 30 //$display("the addr %h read result is %h",addr, rddata); 31 @(posedge S_cpu_clk) 32 F_nrd = 1'b1; 33 F_nwr = 1'b1; 34 F_ncs = 1'b1; 35 F_addr =0; 36 end 37 endtask 38 39 40 task CAN_TEST_ALL; 41 begin 42 CAN_TEST(16'h0700,16'h1201,16'h0500,16'h1100,8'h03); 43 //CAN_TEST(16'h0701,16'h1200,16'h0600,16'h1000,8'h12); 44 end 45 endtask 46 47 48 task CAN_TEST; 49 input [15:0] reset_reg_star; 50 input [15:0] reset_reg_earth; 51 input [15:0] base_reg_star; 52 input [15:0] base_reg_earth; 53 input [7:0] connect; 54 55 int i_cnt; 56 logic [15:0] can_rdata; 57 58 begin 59 $display("=============CAN %h TEST START=============",connect); 60 61 CPU_WRITE(reset_reg_star,16'h0000);//CAN1A RST begin 62 #170ns; 63 CPU_WRITE(reset_reg_star,16'h0001);//CAN1A RST end 64 CPU_WRITE(reset_reg_earth,16'h0000);//CAN2B RST begin 65 #170ns; 66 CPU_WRITE(reset_reg_earth,16'h0001);//CAN2B RST end 67 68 69 //////////////////can init 1A&2B begin//////////////// 70 CPU_WRITE(base_reg_star,8'h09); //CAN1A INIT [star] 71 CPU_READ_NPT(base_reg_star,can_rdata); 72 if(can_rdata != 8'h09) 73 begin 74 $display("the addr base_reg_star read result is %h,wrong!(should be 8'h09)",can_rdata); 75 $stop; 76 end 77 CPU_WRITE(base_reg_star+8'h1F,8'h08); 78 79 CPU_WRITE(base_reg_star+8'h10,8'h00); 80 CPU_WRITE(base_reg_star+8'h11,8'h00); 81 CPU_WRITE(base_reg_star+8'h12,8'h00); 82 CPU_WRITE(base_reg_star+8'h13,8'h00); 83 CPU_WRITE(base_reg_star+8'h14,8'hFF); // ////CARE ID:MUST 00 84 CPU_WRITE(base_reg_star+8'h15,8'hFF); 85 CPU_WRITE(base_reg_star+8'h16,8'hFF); 86 CPU_WRITE(base_reg_star+8'h17,8'hFF); 87 88 CPU_WRITE(base_reg_star+8'h04,8'h03); 89 CPU_WRITE(base_reg_star+8'h06,8'h00); 90 CPU_WRITE(base_reg_star+8'h07,8'h16); 91 CPU_WRITE(base_reg_star+8'h08,8'h00); 92 CPU_WRITE(base_reg_star+8'h1E,8'h00); 93 CPU_WRITE(base_reg_star+8'h00,8'h08); 94 95 CPU_WRITE(base_reg_earth+8'h00,8'h09); //CAN2B INIT [earth] 96 CPU_READ_NPT(base_reg_earth+8'h00,can_rdata); 97 if(can_rdata != 8'h09) 98 begin 99 $display("the addr base_reg_earth+8'h00 read result is %h,wrong!(should be 8'h09)",can_rdata); 100 $stop; 101 end 102 CPU_WRITE(base_reg_earth+8'h1F,8'h08); 103 104 CPU_WRITE(base_reg_earth+8'h10,8'h12); // //// ID:MUST 122X 105 CPU_WRITE(base_reg_earth+8'h11,8'h24); 106 CPU_WRITE(base_reg_earth+8'h12,8'h00); 107 CPU_WRITE(base_reg_earth+8'h13,8'h00); 108 CPU_WRITE(base_reg_earth+8'h14,8'h00); 109 CPU_WRITE(base_reg_earth+8'h15,8'h00); 110 CPU_WRITE(base_reg_earth+8'h16,8'hFF); 111 CPU_WRITE(base_reg_earth+8'h17,8'hFF); 112 113 CPU_WRITE(base_reg_earth+8'h04,8'h01); 114 CPU_WRITE(base_reg_earth+8'h06,8'h00); 115 CPU_WRITE(base_reg_earth+8'h07,8'h16); 116 CPU_WRITE(base_reg_earth+8'h08,8'h02); 117 CPU_WRITE(base_reg_earth+8'h1E,8'h00); 118 CPU_WRITE(base_reg_earth+8'h00,8'h08); 119 //////////////////can init end/////////////////////////// 120 121 122 CPU_WRITE(base_reg_star+8'h01,8'h0C); //CLR RX FIFO 123 124 CPU_READ(base_reg_star+8'h02,can_rdata); //SR[2]=?0 125 while(can_rdata[2] == 0) 126 begin 127 #1us; 128 CPU_READ_NPT(base_reg_star+8'h02,can_rdata); 129 end 130 131 132 CPU_WRITE(base_reg_star+8'h10,8'h08); //Transmit Frame Information:standard,8 data 133 CPU_WRITE(base_reg_star+8'h11,8'h56); //identifier:ff0 134 CPU_WRITE(base_reg_star+8'h12,8'h60); 135 for(i_cnt=3;i_cnt<11;i_cnt++) 136 begin 137 CPU_WRITE(base_reg_star+8'h10+i_cnt,i_cnt);//write data to transmit buffer,发送一帧标准帧数据 138 end 139 140 141 CPU_WRITE(base_reg_star+8'h01,8'h01); //trans enable 142 143 CPU_READ(base_reg_star+8'h03,can_rdata); 144 CPU_READ(base_reg_star+8'h02,can_rdata); 145 while(can_rdata[2] == 0) 146 begin 147 #1us; 148 CPU_READ_NPT(base_reg_star+8'h02,can_rdata); 149 150 end 151 CPU_READ(base_reg_star+8'h03,can_rdata); 152 CPU_READ(base_reg_star+8'h02,can_rdata); 153 154 #2ms; 155 CPU_READ(base_reg_earth+8'h10,can_rdata); 156 CPU_READ(base_reg_earth+8'h11,can_rdata); 157 CPU_READ(base_reg_earth+8'h12,can_rdata); 158 CPU_READ(base_reg_earth+8'h13,can_rdata); 159 CPU_READ(base_reg_earth+8'h14,can_rdata); 160 CPU_READ(base_reg_earth+8'h15,can_rdata); 161 CPU_READ(base_reg_earth+8'h16,can_rdata); 162 CPU_READ(base_reg_earth+8'h17,can_rdata); 163 CPU_READ(base_reg_earth+8'h18,can_rdata); 164 CPU_READ(base_reg_earth+8'h19,can_rdata); 165 //CPU_READ(base_reg_star+8'h03,can_rdata); 166 //CPU_READ(base_reg_star+8'h02,can_rdata); 167 CPU_READ(base_reg_earth+8'h1a,can_rdata); 168 169 170 ///////////////////////////////////second sending/////////////////////////////// 171 $display("####################################"); 172 CPU_WRITE(base_reg_star+8'h01,8'h0C); 173 CPU_WRITE(base_reg_earth+8'h01,8'h0C); 174 175 CPU_READ(base_reg_star+8'h02,can_rdata); //SR[2]=?0 176 while(can_rdata[2] == 0) 177 begin 178 #1us; 179 CPU_READ_NPT(base_reg_star+8'h02,can_rdata); 180 end 181 CPU_READ(base_reg_star+8'h02,can_rdata); 182 183 CPU_WRITE(base_reg_star+8'h10,8'h08); //Transmit Frame Information:standard,8 data 184 CPU_WRITE(base_reg_star+8'h11,8'h00); //identifier:00 185 CPU_WRITE(base_reg_star+8'h12,8'h00); 186 for(i_cnt=3;i_cnt<11;i_cnt++) 187 begin 188 CPU_WRITE(base_reg_star+8'h10+i_cnt,i_cnt);//write data to transmit buffer,发送一帧标准帧数据 189 end 190 191 192 CPU_WRITE(base_reg_star+8'h01,8'h01); //trans enable 193 CPU_READ(base_reg_star+8'h02,can_rdata); //SR[2]=?0 194 #2ms 195 CPU_READ(base_reg_earth+8'h10,can_rdata); 196 CPU_READ(base_reg_earth+8'h11,can_rdata); 197 CPU_READ(base_reg_earth+8'h12,can_rdata); 198 CPU_READ(base_reg_earth+8'h13,can_rdata); 199 CPU_READ(base_reg_earth+8'h14,can_rdata); 200 CPU_READ(base_reg_earth+8'h15,can_rdata); 201 CPU_READ(base_reg_earth+8'h16,can_rdata); 202 CPU_READ(base_reg_earth+8'h17,can_rdata); 203 CPU_READ(base_reg_earth+8'h18,can_rdata); 204 CPU_READ(base_reg_earth+8'h19,can_rdata); 205 //CPU_READ(base_reg_star+8'h03,can_rdata); 206 //CPU_READ(base_reg_star+8'h02,can_rdata); 207 CPU_READ(base_reg_earth+8'h1a,can_rdata); 208 209 $display("CAN %h TEST Success!\n",connect); 210 end 211 212 endtask