你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的FDCAN

[复制链接]
STMCU小助手 发布时间:2021-12-22 14:00
一、介绍
1 o3 i5 B1 }5 a6 F; X0 v9 E  h
( b, l; \' W3 S/ |* I  E7 D1 ?- R        FDCAN(Flexible Data-Rate CAN)是CAN的升级版。特点包括:/ Y1 ~2 h0 k) }; r5 q) c
3 z; I5 W/ M) _( E/ A9 q7 _
       1、每帧数据段最大长度由8字节上升到64字节。6 U; Y" b% P# I/ t

" s( ]4 J. q7 D, E- ?% \        2、速度由1Mbps上升到5Mbps,甚至还可以更高。在一个数据帧中仲裁段(ID和ACK)的速率和CAN一样最高1Mbps,这样可以保证总线的健壮可靠,但是数据段可以5Mbps甚至更高,一个数据帧中使用不同的波特率,这就是FD(Flexible Data-Rate)的由来。+ y  m3 f& Y# z, ^' w0 x* s

* j+ z0 a! P: i7 c7 R        3、向下兼容CAN。
. m$ T4 T  i9 H7 T
0 I) Q6 {  D' @3 w/ l: _: E        H7的FDCAN包含2个可配置接收FIFO。多达64个专用接收buffer,多达32个专用发送buffer。可配置发送FIFO/队列,可配置发送事件FIFO。
5 w  M3 N% Q: E3 Q4 j  Q, m) L, r3 Q. K' f( U
二、结构
, l, p7 F# ]; j: x: I2 O! s' Z) T9 m5 Y
        先看结构框图:$ }6 w3 d1 L5 y4 a% `  K2 b

: W- N/ n! k# ?
20191121162856859.png
1 u) \- a8 Y4 p  T: G8 E; b/ `
9 f0 w+ ]1 U- B
1、两条中断线:fdcan_intr0_it和fdcan_intr1_it。可以通过FDCAN_ILE寄存器的 EINT0和 EINT1这两个位来使能或者关闭。* Z0 s1 N. W, D1 \: {. r; q

2 c! \; Y7 J  I# b8 [
20191127102816991.png
7 h1 v. B& Z3 Z+ F
$ T( S( O# M+ p. w- s
        可以通过FDCAN_ILS寄存器来选择FDCAN的中断是在fdcan_intr0_it上触发,还是在fdcan_intr1_it上触发,默认所有中断都在fdcan_intr0_it上触发,没有特殊的要求,只需要用一条中断线就可以了。% f: z: o) P# _6 ]: A" P3 E

( I9 r% f4 u# j; L+ R2、TX Handler:负责将消息RAM中的数据发送到CAN内核,最多可配置32个发送buffer进行发送。发送buffer可用作专用发送buffer、发送FIFO(发送队列的组成部分)或二者的组合。发送事件FIFO会将发送时间戳与相应的消息ID存储在一起,另外还支持取消发送。/ I( z0 k' H7 F  c8 ^1 u: F
& @8 s4 X" J2 o/ K
3、RX Handler:负责将CAN内核的数据传输到消息RAM,支持两个接收FIFO(每个FIFO的大小均可配置)以及最多64个专用接收buffer(用于存储所有通过验收过滤的消息)。专用接收buffer仅用于存储具有特定标识符的消息,与接收FIFO有所不同。每条消息均与其接收时间戳存储在一起。
0 B' @% v  a: v1 @' T/ [  Y! v/ y! A$ f; g1 a# g& t
4、CAN core:CAN内核,读RX引脚数据处理后给RX Handler,接收TX Handler处理后控制TX引脚。
: \1 E/ i" i7 }5 t9 D% q
$ ]' f4 [- T  ]( L0 |5 w5、Message RAM interface:消息RAM接口,外面连接着消息RAM。消息RAM是FDCAN的核心,本质是一段最大10KB的内存,把这段内存分成不同的区域,每个区域的作用不同,可以实现:过滤器、接收FIFO、接收buffer、发送事件FIFO、发送buffer。内存分配如下:5 ]4 Y& b9 `. @; j: |8 G5 }; R
* o: G) T' l, h: s1 Y5 p
20191121164211703.png

. w& x, p/ b3 s8 h+ Y+ V* N- {: Z1 N' Q4 w& W' E9 A
        10KB的消息RAM中,是以32位为最小单位来操作的(因此消息RAM的起始地址要32位对齐),即字(word),因此10KB共有10*1024/4=2560个字。2560个字被分成了8个功能区,从上到下为:SIDFC.FLSSA、XIDFC.FLESA、RXF0C.F0SA......每个功能区中的条目又定义为元素(element),每个元素可以占用多个字,但是同一个功能区中的元素大小是相同的。比如Rx FIFO0是接收FIFO0,消息通过过滤器后被保存到这里,它最多占用1152个字的空间,有64个元素,也就是可以保存64条消息,这64个元素的大小都相同,每个元素的大小最大为1152/64=18字。
: e  [/ C* A% r# [" B2 w) \9 u' J9 ^& `% R  ?" V
        1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,最多可以有128个元素。
- ?4 H) f9 f: p4 s/ V. o
2 h# L* ?; q# `/ Q  A        2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,最多可以有64个元素。(F1配置寄存器来设置过滤ID,H7直接划了个内存区来设置过滤ID), v* d5 O. P( Y- S

+ p4 E6 @0 Q% c( D6 g        3)、RXF0C.F0SA:接收FIFO0,最多可以有64个元素,可以接收64条消息。
4 V  i! D1 n7 ^. w! b4 o) N& @; q5 Y: N+ ^2 f
        4)、RXF1C.F1SA:接收FIFO1,最多可以有64个元素,可以接收64条消息。
+ H# T* M- F. N# u9 u( g+ p* k  ~1 e
        5)、RXBC.RBSA:接收buffer,最多可以有64个元素。, P7 J2 X( i( q3 e
- l# c3 d$ A$ ~1 @
        6)、TXEFC.EFSA:发送事件FIFO,最多可以有32个元素。(不是发送FIFO)" ]  z  R# u. E; t7 Y

2 P* B- e* D1 F' N+ e  u- H1 u        7)、TXBC.TBSA:发送buffer,最多可以有32个元素。
  O! u7 E4 r4 N  ?0 |* h
& w9 i* s8 k$ @% X7 @: k        8)、TMC.TMSA:触发存储器,最多可以有64个元素。6 D5 h4 g( f6 q! q2 P& o
7 v8 L: _' d% F9 T. ?
《注:这8个区域的元素个数和元素大小都是可以配置的,但是这8个区域的地址又是连续的。因此在初始化的时候,会根据每个区域的元素个数和大小来计算下一个区域的起始地址,并保存到相应的寄存器中》
% e- }+ w/ R9 {! N  @7 h8 Q3 g: {4 u+ n, I- J4 L0 |/ [- ^+ k
        下面来详细介绍这几个功能区域:
6 L. b# j% s1 Z: a) B. V
# M* v. r: o4 S. ?0 |& D1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,有128个元素,每个元素占一个字,定义为:8 I5 d3 b  ~6 k6 l7 L, j* L
$ b: m8 J" T( @0 @7 `7 W, S2 C) r
20191121170625565.png
# P$ v, ~: p5 J/ n( I/ I! d, \

- y0 z6 w  v2 v! JSFT[1:0](bit31:30):这两位用来表示过滤类型,一共有四种:
- y& p$ w! p% N9 ~    00:范围过滤,过滤到SFID1到SFID2中的所有信息。
: e' c. n' s0 U: f/ r    01:双过滤,过滤到SFID1和SFID2中的信息。
" Q: _4 y! q1 L5 @. F+ Q    10:传统位过滤,SFID1 是过滤值,SFID2 是掩码。8 D& O, L! k6 B. F6 ?& k
    11:禁止过滤器元素5 ]. l! B  W1 F/ G
SFEC[2:0](bit29:27):标准过滤配置
4 e* V9 {7 s3 `    000:禁止过滤器元素
+ h: a* i3 Z. R8 ^3 G0 [    001:当过滤匹配以后存储在Rx FIFO0中。
9 t* E8 F! X8 F. J, m  a# W    010:当过滤匹配以后存储在Rx FIFO1中。
) y3 l2 \! d: q6 w    011:当过滤匹配以后丢弃。
. I# z5 R; [, W3 Q7 T    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。
% f3 M! A0 {% t( \    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。
6 o+ Q# b; R/ f. }0 {# e( N7 H  C    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。
* d8 |/ {9 S8 G    111:存储到Rx buffer中或者作为debug消息,FDCAN SFT[1:0]忽略。
; H( P+ h3 B4 V7 {  pSFID1[10:0](bit26:16):标准过滤ID1,第一个要过滤的ID。$ v5 e8 Z( H( N  H) V# d4 J
SFID2[15:10](bit15:10):标准过滤ID2,此位根据SFEC的配置不同而不同,当SFEC=001~110的时候此位域表示标准过滤ID。当SFEC=111的时候此位域表示Rx buffer或者debug消息。; t- l3 }& @8 \$ @8 ^

6 U* P- k; n# [9 x# YSFID2[10:9](bit10:9):设置接收到的消息是存放在Rxbuffer中还是处理为debug消息的消息A、B或C。" @( q. k9 X8 n0 z9 c
    00:将消息存储在Rx Buffer中。" |6 v0 _3 p! l* f& l" D  y! m
  ]: Q+ i# x( B9 V* l6 U  x
    01:debug消息A。    1 @( U' K' m( m9 P0 Q

0 s9 m6 {$ [! \6 B4 [, U    10:debug消息B。" R- h( y9 y9 N# X4 }
3 V  g( f* _. `  D3 k1 l3 P: x1 _
    11:debug消息C。
% X! Y) u- }. }% P# ?( U" E0 e5 x: j& L$ C9 ]
SFID2[8:6](bit8:6):确定是否将滤波器事件引脚作为外部接口。
( [5 i1 [3 T, q# r( v2 K) e% o/ r, w( I! x; @4 y7 ?
SFID2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer 的开始地址RXBC.RBSA的偏移。/ ]+ d2 K, r# U$ T5 E1 y

2 Q: A+ t8 f. ^$ ]; Z2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,有64个元素,每个元素占2个字,定义为:
1 j, s5 _5 M6 o; ~6 P
/ V9 B0 W4 F9 K+ \0 X+ _
20191121171836710.png
6 P+ f' u, m! ~& G% `: \

( ?/ p; k' q- p4 `) f0 i( |F0 EFEC[2:0](bit31:29):扩展过滤配置& L& p- k* l/ v8 }; u. I. Y& c! ~3 h+ k
    000:禁止过滤器元素" v7 Y! P* A: y% O; X. B" U! C
    001:当过滤匹配以后存储在Rx FIFO0中。3 j% G+ D( p! a! u; K
    010:当过滤匹配以后存储在Rx FIFO1中+ d" G' N- @/ p
    011:当过滤匹配以后丢弃。) G! d9 w0 k& C
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。
! _  f; k! A6 b( P    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。
. _: M8 @9 w( y, I& M' m2 L' }6 C    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。) K8 c1 Q' D4 v6 p3 u- h, K
    111:存储到Rx buffer中,EFT[1:0]忽略。
# h; h$ |& P$ m+ H* AF0 EFID1[28:0](bit28:0):扩展过滤ID1。
+ ^8 p( C  t/ W/ L1 p8 m3 XF1 EFTI[1:0](bit31:30):扩展过滤类型
0 R  \( z/ h7 Y1 e    00:范围过滤,过滤到EF1ID到EF2ID中的所有信息。7 y5 g* S- [% l, d  y! F, D& _
    01:双过滤,过滤到EF1ID和EF2ID中的信息。, l+ H! s: Y5 t
    10:传统位过滤,EF1ID 是过滤值,EF2ID 是掩码。
0 f; `7 H; g, K1 [* H6 h. F+ w( }( C2 E    11:范围过滤,过滤到ED1ID到ED2ID中的所有信息,没有使用FDCAN XIDAM的掩码3 p! \& m& D" k
F1 EFID2[10:9](bit10:9):设置接收到的消息是存放在Rx buffer中还是处理为debug消息的消息A、B或C。+ Q6 q% U# h. B7 A; M! ~; S
    00将消息存储在Rx Buffer中。5 e& ]: }1 u& \* n2 T; t
    01:debug消息A。
/ m+ v  ]- \0 J    10:debug消息B。( ~) G& l; T) l
    11:debug消息C.1 T- x/ Z% N" t' T
F1 EFD2[8:6]bit8:6):确定是否将滤波器事件引脚作为外部接口。
, C0 w) F# d! s; l0 Z. d% |* ?" UF1EDIF2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer的开始地址RXBC.RBSA的偏移。7 P9 A) a8 b$ W" z3 P2 M

, P, `  n: y: \$ w# |) g. }3)、RXF0C.F0SA、RXF1C.F1SA和 RXBC.RBSA分别为Rx FIFO0、Rx FIFO1、Rx buffer,它们都有64个元素,元素的大小根据数据长度不同而不同,范围为4-18字,它们的位定义相同:
) ^/ }- t7 {' b& H
6 D6 ?/ M3 L- G& d/ D% x# ~, @
20191121172451477.png
. S, g  @9 q% O) z/ [% _8 Q& @2 `0 v5 o
/ F& N0 O6 Q. q8 T: a2 P0 k7 ]
R0 ESI(bit31):错误状态标志2 U, a& x4 B0 c
    0:传输节点显性错误。
% F  I# C5 P* b  P+ P) x. j: r    1:传输节点隐形错误
: @; k' {' l2 h& F& O8 W0 GR0 XTD(bit30):标记是标准ID还是扩展ID" c* y% c- y9 J; j+ f
    0:11位标准ID* P: X6 m( |* P' @+ M2 O

0 ]6 W8 i- u  q) L1 n( |$ a* G    1:29位扩展ID
+ G( c8 q0 j. A, X3 [6 J: g6 {6 \1 S  d: [+ d6 r% y; K. f
R0 RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。4 @. x5 t, Y' U7 Y( y; V& v9 j8 |9 B
    0:接收到的帧是数据帧0 a) @$ s6 A5 a4 a( X1 X7 N3 Y
& H, ~& c5 [( K
    1:接收到的帧是遥控帧
1 E3 O) a* f7 `  wR0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。% @5 U% q1 v7 H& T) `
R1 ANMF(bit31):4 N; E5 v3 t  H, U: ~
' s% v2 V2 E: v, C
    0:接收到的帧和FIDX中的过滤帧匹配
7 Z1 W6 }! M- t2 c/ z, }
$ U; t- Q: n+ N2 n    1:接收到的帧和Rx滤波器中的任何元素都不匹配  B4 y5 q! n7 c0 z. B3 c0 M+ i
R1 FIDX[6:0]bit30:24):过滤器索引,0~127,表示和Rx滤波器中的哪个元素匹配。
6 @5 C6 i1 `+ V& `7 w0 ?% I) QR1 FDF(bit21):帧格式( M& {- S) A( d5 p
    0:标准帧格式
! Y$ V# e: B7 v; ]- f    1:FDCAN帧格式。7 i) M8 M# w% X
R1 BRS(bit20):比特率切换
6 g( \/ ?1 O$ \; |    0:接收到的帧没有比特率切换
! A( ~+ ], A, z" J3 I" }( d9 C. P4 J' c- x! ~( K
    1:接收到的帧带有比特率切换
5 U: D8 D0 t) M  I% b$ ^/ N4 BR1 DLC[3:0](bit):数据长度。
% b# p( Y. V( u8 S9 G, g    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
7 M5 {# ?/ j- W  g, j) Q% x  i5 h$ y    9-15:如果是传统CAN,接收帧长度为8字节。
! I2 B; `; b3 D$ f    9-15:如果是 CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64 字节。
" O+ h$ z4 l  e) m5 x4 LR1 RXTS[15:0](bit15:0):接收时间戳。
4 q$ P3 w, i* A) sR2-Rn:接收到的数据。: j8 \& W6 j8 c9 I1 U% m. C- ~
( y5 `( u" |) B4 w1 M
4)、TXEFC.EFSA:发送事件FIFO,有32个元素,每个元素两个字。
! \  a' g3 f5 N* y$ F7 n7 X3 \- U6 m" l9 k  [* c7 q# b2 N5 l
20191121174147402.png
/ m4 Z% C- V! S3 G

$ b& U  N! v" q  A. b" kE0 ESI (bit31): 错误状态标志
+ f: t9 G( ~% @  u% ^/ `7 s
; |5 I8 |+ ^4 z: n) @% ]    0:传输节点显性错误- A5 |& e/ D; K  t+ f  Z- `; F
    1:传输节点隐形错误。' B! ]" q8 k6 o6 q* n0 Z2 [' o
E0 XTD(bit30):标记是标准D还是扩展ID5 D5 L+ r; U# y. ~
    0:11位标准ID.( }# P0 V5 `& `1 X
    1:29位扩展ID
9 j& m' I2 j; B0 G
( q' Q1 B! s, z, Q* OE0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
$ |, I9 W4 Y( z, q    0:发送的帧是数据帧4 J5 M* ^8 r+ Q
    1:发送到的帧是遥控帧
6 @8 H& e1 K/ S  \1 K" L5 YE0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11 位ID还是29位ID。( o# b5 g% G% z2 {! x
E1 MM[7:0](bit31:24):消息掩码,从Tx buffer拷贝到Tx Event FIFO中。  {! \5 \" S. Q, q( h9 m/ ~
E1 EFC(bit23:22):事件类型
( k0 @5 J2 ]$ \# R& U/ X' ^9 a6 N    00:保留。
! A7 H" {2 I+ d7 [6 {    01:发送事件。) M; r  i0 i5 [* y* t! E4 ]5 Q
    10:发送取消。
, o1 V# _0 c" U' E. W$ l( w    11 :保留。0 E5 r% @( o7 N4 C- `% V9 @- ?
E1 EDL(bit21):扩展数据长度' O2 m9 ]& P, q# a" t* C( l
    0:标准帧格式
1 l+ D7 S  a4 C0 h3 g0 |    1:FDCAN帧格式。) r4 \$ q; M! D  b  B5 O
E1 BRS(bit20):比特率切换/ g6 H* d  {3 N: d  k9 Y
    0:发送的帧没有比特率切换
% @( V2 D$ }; H( J, o: J% b+ A: t, f1 }  S- |2 c8 w
    1:发送的帧带有比特率切换6 s! v: |  o. {
E1 DLC[19:16](bit):数据长度。* D9 w5 l2 m$ c
    0-8:传统CAN+CANFD,长度为0~8字节。
. j3 y* v2 r1 P* y" W. ?* {    9-15:长度为8字节。
/ Y! ]/ C! z7 A) Q7 @: hE1 TXTS[15:0]bit15:0):时间戳。
, Z4 p% q$ D& H9 \
  `2 {+ e2 _/ Q# X* v* s5 t5)、TXBC.TBSA:发送buffer,有32个元素。
1 ^* B0 }2 z3 K- n& s3 D8 y8 y
9 w$ n6 R2 n8 E2 n8 V' A; U
20191121175121493.png

, s* u1 {$ T& z) A) Q$ E! N9 @- ]
T0 ESI(bit31):错误状态标志& P! O/ n% E2 {6 z
    0:CANFD帧中取决于被动错误标志。/ Q% i* g5 o$ ~; D9 r
    1:CANFD帧中隐形错误。; v2 }* R! I% P3 f
T0 XTD(bit30):标记是标准ID还是扩展ID: ^; |% w7 @/ h: H8 i# ~  `+ c7 }9 c5 A
    0:11位标准ID- N$ ^0 j  \1 u7 l+ k6 z' p4 L' q
# D% l( _5 v+ [( U0 G: @6 R
    1:29位扩展ID% a. j2 p  h# B8 ^. X! j+ U
' n, n+ q& g- W' X
T0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。6 r: u7 [8 y- }2 l# M5 f
    0:发送的帧是数据帧& A$ c9 D0 n8 W& x) h
    1:发送到的帧是遥控帧
3 n* l' j4 i* _. f# c0 [1 J9 AT0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。7 i( k  T7 x: j* X0 v; k
T1 MM[7:0](bit31:24):消息掩码,配置Tx buffer的时候由CPU写入。
" d2 |0 H; K. w- b8 E" d) qT1 EFC(bit23):事件FIFO控制
) f4 G) P  t7 I+ m8 [( S, S    0:不存储发送事件。
& ^$ x( o5 J# k7 y    1:存储发送事件。
5 c6 [9 Y8 y* S5 i3 uT1 FDF(bit1):帧格式
) W3 w( k3 F  [1 }7 q    0:标准帧格式
; s9 `. j4 }0 N5 u0 O# g1 n: \    1:FDCAN帧格式。1 I' w1 V# F. a9 M
T1 BRS(bit20):比特率切换
- w( {" M3 e) V" a9 K( m% ^$ A    0:发送的帧没有比特率切换
2 R& d) F7 y# N! e* p+ t! ?2 t4 G9 g1 c( `) H( o9 g
    1:发送的帧带有比特率切换- ~2 ?* D# b; h) R# b, ?- K
T1 DLC[19:16](bit):数据长度。8 r, A- S( ~! g. U! j
    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。4 {. p% n! ?% i: o( \/ K1 U
    9-15:传统CAN,接收帧长度为8字节。% d3 G! s  S- V0 |  q$ m" D
    9-15:CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64字节。3 r, w8 {1 j0 R2 R: O6 T! P  n
T2-Tn:发送的数据。7 m/ f+ p. f- G/ z; C* D
0 A1 L; v/ {" m) W
三、过滤器设置
2 k0 J% V, V* p' O( G5 u$ s; J
) }) G/ ~9 o4 j+ @& l: |        标准帧和扩展帧过滤器的设置分别往SIDFC.FLSSA和 XIDFC.FLESA区域写数据即可,下面以标准帧为例,标准帧过滤器共有3种过滤模式:' y+ y7 T! [9 x* F. k
; u: B. H2 Q. T- d' V
        1、指定范围过滤
( W( ~1 ~5 Q  }$ f2 u        通过SIDFC.FLSSA的SFID1和SFID2来设置需要过滤的ID范围,其中SFID2的值要大于SFID1,这样只有ID值在SFID1~SFID2之内的消息才能被接收到。比如我们现在要设置只接收ID在0X123~0X321范围内的消息,使用标准滤波器n,SIDFC.FLSSAn(n=0~128)的各个位设置如下:) m1 _& K% M  D, B7 k. F3 ?) l

% D6 B; s" d$ ^" F- G
  1. SIDFC.FLSSAn.SFT=0        //范围滤波
    8 x( p0 c+ g5 n' y1 W  H
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到RxFIFO中4 l( Z0 f  I: X5 Z
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    0 P: x* I% j+ L7 A3 r% T4 p
  4. SDIFC.FLSSAn.SFID2=0X321  //ID2
复制代码

. @, R1 ?; B3 a" M  D: b        2、指定ID过滤
1 q( T& T7 W, J" b4 g3 h8 S1 `/ z% n# u5 \4 z" j9 l7 {
        我们也可以设置只接收指定的一个或者两个ID的消息,如果只接收指定的一个ID消息的话SFID1=SFID2。比如我们要设置只接收ID为0X123的消息,设置如下:
3 f5 R( u8 }* Y% H* x6 p  U& y; x
  1. SIDFC.FLSSAn.SFT=1        //指定D过滤
    * i( \0 W" O3 G: r* H
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到Rx FIFO中6 e$ @( t5 U. I0 ]6 x( V
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1* X7 W7 D$ c: }5 u. \3 o& y/ A
  4. SDIFC.FLSSAn.SFID2=0X123  //ID2
复制代码
9 e" T# u+ w, M5 P# v: e% h+ k# e
        3、传统的位过滤. C  A2 i4 Z" }
        第3种过滤模式就是以前STM32的CAN上存在的位过滤模式,在屏蔽位模式下,过滤消息D和过滤掩码一起工作决定接收哪些消息,其中SFID1为过滤的消息ID,SFID2 为过滤掩码。举个简单的例子,我们设置过滤器SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:2 y$ a2 U1 v, O8 ~( e: L* a

1 p9 e* B. c' s" \
  1. SIDFC.FLSSAn.SFT=2          //传统位过滤
    8 z: H( ]8 ?5 @$ U7 t# S
  2. SDIFC.FLSSAn.SFEC=1         //如果滤波匹配成功的话将消息保存到Rx FIFO中" u  r. p4 U: T+ H1 v
  3. SDIFC.FL SSAn.SFID1=0xFF00  //ID1
    , c+ b+ k8 u/ |  n: n
  4. SDIFC.FLSSAn.SFID2=0xF00    //掩码
复制代码

( x$ d8 l) g0 {        其中SFID1是我们期望接收到的消息ID,我们希望最好接收到ID=0xFF00的消息。SFID2的0xF000规定了我们必须关心的ID,也就是接收到的消息ID其位[15:12]必须和SFID1中的位[15:12]完全一样,其他的位不关心。也即是说接收到的消息ID必须是0XxFxx这样的才算正确(x表示不关心)。+ Z/ B; w: n# {, P% s$ q
) W! n  C) t0 {! Z/ d: E/ f
四、CAN的收发过程/ Y, O+ h  ?, |$ ?3 |- z7 R; O" U+ N

% z, L" c$ ^9 E) Q0 M: F        1、CAN接收过程, L" e  U- a- |8 s$ G

9 a7 `+ u6 [$ [% |$ {0 K        CAN接收到消息后会进行过滤,过滤时会从SIDFC.FLSSA或XIDFC.FLESA区域的第0个元素开始匹配,直至符合过滤器中的某个元素的规则,则过滤完成,过滤完成的消息会按照过滤器元素的配置进行处理。比如过滤器元素的SFEC/EFEC位决定过滤后的消息是放入接收FIFO0、接收FIFO1还是专用的接收buffer中。
, X6 n$ l( C/ Y  D+ {# j& l0 X! o  H3 t  A6 g0 ~) n* s
        接收FIFO 0 和接收FIFO 1 最多可分别保存64个元素。两个接收FIFO的配置是通过寄存器RXF0C和RXF1C完成的。, [" [6 H0 z1 g. ^0 W- l( u9 L/ r0 f
! c; m2 p  B1 d. h
20191127114550965.png

; h" z/ |" g" C
1 t5 M# U" ]- \6 m        当IR寄存器的RFnF(n为0或1,代表接收FIFO0或接收FIFO1)指示接收FIFO已满条件时,在至少已读取一条消息且接收FIFO 获取索引递增之前,不会继续向相应的接收 FIFO 写入消息。如果在相应的接收 FIFO 已满时收到消息, 此消息会被丢弃,中断标志IR[RFnL]会置 1。也就是说,接收FIFO满了后会触发RFnF中断,如果继续接收,消息会被丢弃,并触发RFnL中断。
9 Q& Y( g6 {) b+ ^- V5 e2 r0 Z; }1 Y

* d* R( B* a# W; `
20191127111235302.png

9 I5 b! q9 ]0 M: c5 x3 j' i3 t: X3 D( G- J0 l( [
        为了避免接收FIFO溢出,可使用接收FIFO水印。当接收FIFO填充级别达到由RXFnC[FnWM] 配置的接收FIFO水印时,中断标志IR[RFnW]会置 1。比如接收FIFO0大小配置为64,水印值配置为60,当接收了60条消息时会触发水印中断,提前进行处理,这样就避免了FIFO溢出。0 Z* J0 d1 e* n2 H; p; ^
        读取消息就是直接从RXF0C.F0SAn或RXF1C.F1SAn(n为索引号 0~64)中读,消息的组成结构在上面已经说过了,比如HAL库HAL_FDCAN_GetRxMessage函数读数据过程(假定从FIFO0中读):* U5 n/ C: H  z. ]( V/ ]) O
1 b' T/ [6 ~+ g, }7 f7 [$ K
  1. /* Calculate Rx FIFO 0 element address */
    1 Y) ?6 T/ l+ Q: F* }
  2. GetIndex = ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8);
    # k" `- ^! z' \: B
  3. RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4));
复制代码
! ^0 b2 T0 g0 G1 @, D
1)、((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8):作用是获得FIFO0状态寄存器FDCAN_RXF0S的bit[13:8],读这里可以知道接收到的数据保存在FIFO0中的第几个元素中,GetIndex的范围是0-63,刚好对应64个元素。当FIFO接收到一条消息,GetIndex会加一,当从FIFO中取出一条消息,GetIndex会减一。
% I* ?+ J# R9 U. e! w  z9 {2 j4 y* D0 o
2019112119095892.png

* {8 Q; W) X! R+ w! ~
; Y% p( p7 A- _) Y: a2)、hfdcan->msgRam.RxFIFO0SA:是RXF0C.F0SA区域的开始地址。
+ A/ r; w1 J  n6 i" Z+ }+ p" W0 e: H% k
3)、hfdcan->Init.RxFifo0ElmtSize:是接收FIFO0的元素大小,根据数据长度不同而不同& F* j" ]2 ^2 m$ p( z2 a

: W. \6 _( _. C* n3 T

  L; d7 n9 s9 y) c( H( f: j% J% Q% P0 V$ E
如果消息长度是8个字节,那么算上固定的R0、R1,元素大小就是4个字。. K  r2 i: U* D. }, K% L

0 x/ c* D6 M& f+ \* u如果消息长度是64个字节,那么元素大小就是64/4+2=18个字。/ p2 R6 d$ l* N" L4 {! a, e
6 G7 g# d9 K5 x3 n- c0 i% c
        计算出了元素在FIFO0中的地址,直接按数据结构读数据就可以了:
% @  J! G/ h) Y
. U- t5 a4 O) o( U: j- H
  1. pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;7 B! p) x. q+ H! \& a' ]
  2. pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);
    7 e0 v" _0 ]3 h0 }
  3. pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);
    ( v- n: F1 H" @) Q" V8 P
  4. pRxHeader->ErrorStateIndicator = (*RxAddress++ & FDCAN_ELEMENT_MASK_ESI);  //这里地址自加了一次
    2 U# ?; g0 z! S3 Q6 k+ u
  5. pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);
    , W. N' Y  }$ [( E2 W% s8 G
  6. pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);
    ' C3 X# {/ ^! }; u% x
  7. pRxHeader->IsFilterMatchingFrame = ((*RxAddress++ & FDCAN_ELEMENT_MASK_ANMF) >> 31); //这里地址又自加了一次6 ~' J4 ?7 Z  X
  8. ......
    : W/ ?9 s3 e7 i
  9. pData = (uint8_t *)RxAddress;+ D) \/ I& n7 K
  10. for(ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++)2 {" I5 E& q8 U+ J/ o
  11. {
    : {/ Q4 A4 e+ a, I' n
  12.     *pRxData++ = *pData++;
    & y& V  G/ @1 Y  _4 J) N. d
  13. }
复制代码
" J" \* }  j  ^, y5 V. Y3 b
        2、CAN发送流程
1 @( J: c' r& F0 J/ D* p! r
% p9 r8 ^" v- x/ L5 z        在消息RAM中TXBC.TBSA是发送buffer,最多有32个元素。发送buffer可以配置为专用发送buffer和发送FIFO/队列。发送FIFO/队列是指要么是发送FIFO,要么是发送队列,即发送FIFO模式或发送队列模式,由TXBC[TFQM]决定:
* q4 N! u' r& Y5 V" i4 @
  `0 o( {" E- N3 p2 _. V
20191127150042199.png
3 Y% k6 c/ d  _0 w% F* |
& t+ o. M+ M. E& y* V1 l
        因此发送buffer可以有三种组合:全部是专用发送buffer、专用发送buffer加发送FIFO、专用发送buffer加发送队列。, n% A* z2 A2 B4 h8 {
# R6 \: ~# n" |( V9 |2 n; P
        下面来介绍一下专用发送buffer、发送FIFO、发送队列的情况:, Y6 m+ h5 `8 s, Z4 y/ F/ o

# W4 ?* z8 }0 V8 ^( F8 v        1)、专用发送buffer3 O0 p1 t  M2 ~( \# E+ K+ z; x

9 @2 D2 g3 B, C4 j$ x, U         专用发送buffer可完全在CPU的控制下发送消息。每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
+ T) i0 e' I! w, w  j' N9 R        如果数据部分已更新,则会通过添加请求的TXBAR[ARn] 位请求发送。请求的消息在内部会与发送FIFO/队列中的消息进行仲裁,在外部会与CAN总线上的消息进行仲裁, 并会根据其消息ID发送出去。' ]- O) [: i$ G. `" q; I* w- b  Y) n) w
7 g2 o' c0 f9 u# a% h
20191122101555794.png

- Z: \: \' A, ?+ p4 X
5 {! u' W+ N' U1 l, r6 j2 D9 \        专用发送buffer会在消息RAM中分配四个32位字(元素大小为4个字)。因此消息RAM中专用发送buffer的起始地址是:3 f' |2 Y6 d' I8 O8 V9 s* @8 b

5 M& h; p% C1 ~$ P发送buffer索引 (0…31) *4+发送buffer起始地址。
# O' Z( K+ C# M' v. H" I! U% F! y9 l! E! O/ z
, ^5 p4 F# c; D- H: i: g" t- m. {

* L2 s+ D/ d3 ?8 p1 T$ {0 ^, P        2)、发送FIFO1 y' k+ g9 Y# f8 Y5 M

( N5 d/ _& S0 k7 p$ ?( x$ X6 }9 T" J        发送FIFO中存储的消息是先从获取索引TXFQS[TFGI] 引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送FIFO为空。发送FIFO可按消息写入发送FIFO的顺序发送来自不同发送buffer但消息ID相同的消息。FDCAN会计算获取索引和放入索引之差作为发送FIFO空闲级别TXFQS[TFFL],用于指示可用(空闲)的发送 FIFO 元素数。7 J# c5 s: ?. d  c1 S) v
        新的发送消息必须写入以放入索引 TXFQS[TFQPI] 引用的发送buffer开始的发送FIFO中。 添加请求会将放入索引增加到下一空闲发送FIFO元素。放入索引达到获取索引后,会指示发送FIFO已满(TXFQS[TFQF]=“1”)。在这种情况下,下一条消息已发送且获取索引已递增之前,不应继续向发送FIFO写入消息。
3 \8 D; f4 g1 D4 M3 f
" y6 I- I$ y! b4 ^0 h! c/ ?4 D
20191127160804244.png
0 }9 L1 Q0 j; {: o4 U' Q8 ]( L) Q
; \" T" ~# q0 _0 s
        发送FIFO其实就是个环形队列,放入索引是队头,获取索引是队尾,队头和队尾之间保存着消息,相减当然就是待发送消息个数。当从发送FIFO取出数据,获取索引会自加,自加到等于放入索引时,表示发送FIFO为空。当放入数据到发送FIFO,放入索引自加,当绕了一圈自加到等于获取索引时,表示发送FIFO满了。
. X" u' Z' r# E% b7 `5 B4 A4 `  Y+ A' C* E
        如果有一条消息添加到发送FIFO,则会通过向与发送FIFO放入索引引用的发送buffer相关的TXBAR位写入“1”来请求消息的发送。
2 P8 |3 ^5 G$ Z1 L1 o( x3 D* Y3 X        如果有多条 (n条) 消息添加到发送FIFO,则会写入以放入索引开始的n个连续发送buffer中。 随后会通过TXBAR请求发送。放入索引随后会循环递增n。请求的发送buffer数不应超过发送FIFO空闲级别指示的空闲发送buffer数。
% Y* z) A% q( z8 }# S3 f& w        如果获取索引引用的发送buffer的发送请求取消,获取索引会增加到下一个具有挂起发送请求的发送buffer,并会重新计算发送FIFO空闲级别。如果取消对其他任何发送buffer的发送,获取索引和FIFO空闲级别保持不变。
/ C" `4 Q5 e3 |: P; C+ e1 m        发送FIFO元素会在消息RAM中分配4个32位字。因此下一可用(空闲)发送FIFO 缓冲区的起始地址是:
/ q- U: ^( g# e) P  b5 h( K) N9 G) a6 P8 n! {" b4 J4 \  S
放入索引 TXFQS[TFQPI] (0…31)的值*4+发送buffer起始地址。
/ g/ S( j& ^8 w5 }( X" R0 G/ A9 z: Q1 K5 q9 H4 x
        3)、发送队列3 u/ |9 c1 U/ G1 e( `& Y  |7 R4 D
        发送队列中存储的消息是先从消 息ID最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。/ H5 q' v9 k) L8 k9 a- Z% O
        新消息必须写入放入索引 TXFQS[TFQPI] 引用的发送buffer中(放入索引 TXFQS[TFQPI] 只是队列头的数字)。添加请求会将放入索引循环增加到下一空闲发送buffer。如果发送队列已满(TXFQS[TFQF]=“1”),则放入索引无效,并且在至少有一个请求的消息已发出或挂起的发送请求已取消之前,不应继续向发送队列写入消息。
6 E" I1 T0 {* Y        应用可使用寄存器 TXBRP来代替放入索引,并可将消息放入任何没有挂起传输请求的发送缓冲区中。3 f! w+ M  q6 a4 @6 v) g, D
        发送队列缓冲区会在消息 RAM 中分配四个 32 位字。因此下一可用(空闲)发送队列缓冲区 的起始地址是:
  y1 B3 ~0 R, U, n5 ~9 Y" D; X7 j
+ r# v, P0 F: u( U发送队列放入索引 TXFQS[TFQPI] (0…31) 的值*4+发送buffer的起始地址。: n1 }- t" t8 _. m3 K7 @" o4 M4 w
: w! D2 \7 O" ]% \
        因此可以知道专用发送buffer、发送FIFO、发送队列的区别是对放入其中的多条消息的发送顺序不同:8 o1 `5 E( x2 J+ H: j1 a
; R. b3 m$ z; U* m
        1)、发送buffer全部配置为专用发送buffer" t9 H3 \+ ^* a( ]- y
$ P& E: U- G% ^0 l+ i
        每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
8 o/ B2 F) [% P2 z! D. e% ]7 W5 H/ \/ Q3 s- y! q7 C; S+ M4 C
        2)、混合专用发送buffer和发送FIFO/ G+ i: _* [+ |) y
* U. a0 L! X  m8 ~3 a, @
        在这种情况下,消息RAM中的发送buffer部分会被划分为一组专用发送buffer和一个发送FIFO。专用发送buffer的数量是通过 TXBC[NDTB] 配置的。分配给发送FIFO的发送buffer数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送buffer。
6 @( J' e% c: z% u4 k  z. u1 H
0 l3 B) Q2 i3 u$ a* i/ T8 W
20191127162943182.png
6 t6 s7 d  X* z, l& ^

! q9 Z: j, I& T" G( L: o9 u/ Y        发送优先次序:
# M, g# P  Y8 p6 V0 `A、扫描专用发送缓冲区和时间最久的挂起发送FIFO缓冲区(TXFS[TFGI] 引用的缓冲区)
+ w* G- V  ^  R7 v8 NB、消息ID最小的缓冲区优先级最高,下次将发送该缓冲区的数据; U# h4 }4 g! w  \

$ S# c" f8 A. p0 o: B, P5 J        3)、混合专用发送buffer和发送队列
9 T- V# T7 a  v) z% N
7 L( ~) y3 E; n! m# k        在这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队 列。专用发送缓冲区的数量是通过 TXBC[NDTB] 配置的。发送队列缓冲区的数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送缓冲区。
+ x" P1 u) r/ w! n: c/ L) B) t% J  q6 u
20191127163202212.png

0 k; }5 V) i. R4 B: R, O5 }- z
6 V' |2 i" W+ O: T( G: ^        发送优先级设置:' K) z: O: Y6 W/ C8 x) h
A、扫描所有激活了发送请求的发送缓冲区
/ x6 F9 q4 d' Q8 h  Y& l4 a$ r8 KB、消息 ID 最小的发送缓冲区优先级最高,下次将发送该缓冲区的数据$ D* x! F; {0 j- D2 d+ d5 m
! K1 p9 Z" n( N* X1 N+ e& z
        再来介绍一下发送事件FIFO,它并不是发送FIFO,不是用来存储发送消息的,而是用来存储发送消息的状态的。
0 I0 J4 ~; X* ?1 V2 H  q1 `7 D5 s% j: w/ X7 b* f
        FDCAN 在 CAN 总线上发送消息 后,消息 ID 和时间戳会存储在发送事件 FIFO 元素中。为了将发送事件关联到发送事件 FIFO 元素,已发送的发送缓冲区中的消息标志会被复制到发送事件 FIFO 元素中。1 ?8 l/ r! @9 Z3 k
        发送事件 FIFO 最多可配置为 32 个元素。发送 FIFO 中介绍了发送事件 FIFO 元素。根据元素 大小 (TXESC) 的配置,会使用 2 到 16 个 32 位字 (Tn = 3 ..17) 来存储 CAN 消息数据字段。
$ H3 B' {& t0 }# Q8 |        发送事件 FIFO 的用途是将处理发送状态信息与处理发送消息分开,也就是让发送缓冲区仅 保存要发送的消息,而将发送状态单独存储在发送事件 FIFO 中。这样做有很大的优势,尤 其是在处理动态管理的发送队列时,发送缓冲区可在发送成功后立即用于新消息。覆盖发送缓冲区之前,不需要保存该发送缓冲区的发送状态信息。
, L$ ^' d- h9 v6 m4 ^, B8 p8 U/ G8 i0 V9 [4 s
        为了防止发送事件FIFO溢出,发送事件FIFO仍然支持水印功能。, D2 z) \: Q' E2 A# k  D

2 T: [3 c  d+ |6 R        CAN发送消息的代码实现:. U# s6 I  q9 Z2 T
/ z8 A  K4 J  n
        发送流程与接收流程刚好相反,只需要把消息按照TXBC.TBSA格式构建好,然后写入发送buffer,写进去后设置FDCAN_TXBAR寄存器的指定位为1来请求传输即可。如HAL库函数HAL_FDCAN_AddMessageToTxFifoQ:/ H7 B6 D/ ?3 @6 B9 G1 y
) h8 A+ |1 O- t+ r6 H6 }3 ~8 e
  1. PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> 16); //获取元素编号   r  Y( O& b; ]9 o# K( j) y+ J
  2. FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex); //复制消息到Tx buffer 0 D6 c/ U( }, Z  Z
  3. hfdcan->Instance->TXBAR = (1 << PutIndex); //发出传输请求
复制代码

5 d9 G- W6 k4 e1 J, w4 z: Q        发送buffer请求寄存器FDCAN_TXBAR,描述为:
. K; V4 y8 o: F! X) l( Y, |# t8 X" O# x$ o# N$ ~* O

5 h6 l' u- V0 e; O8 _
; L. ?( ^! o) n        此寄存器用来设置FDCAN的哪个发送buffer可以发送数据,FDCAN有32个发送buffer,当把消息复制到这些buffer中后,就需要设置此寄存器来标记此buffer可以发送。
3 |# `5 y1 }7 f0 F0 `. D- Q# B4 Q! T6 ?2 d' s) k9 j

: T, B- c) q3 l, [- d' ]% c  {
/ N9 _5 b3 Z" _" ?. g5 m五、初始化
; r* Q* M) `4 k1 m# x$ L- D% M+ h: l# d5 a1 Q+ W
        初始化可以直接使用HAL库,
, g4 L2 ]7 Y! ]" r
; D8 }! N% }4 p. l
  1. u8 FDCAN1_Mode_Init(void)
    ! O3 s& `* K( v9 p, f3 B
  2. {( |3 Q7 y; ?' k* S5 s# s3 b
  3.     FDCAN_FilterTypeDef FDCAN1_RXFilter;
    . I# x9 P" L5 `2 O
  4. 5 M+ f8 t0 b2 Q" j4 M7 [
  5.     HAL_FDCAN_DeInit(&FDCAN1_Handler);                              //先清除以前的设置
    % N0 P8 L! l+ Q& Q5 }! B: m" M
  6.     FDCAN1_Handler.Instance=FDCAN1;
    4 x- r6 G0 c9 q8 E+ n) Y8 W6 R
  7.     FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC;            //传统模式5 C. }0 c+ b3 l; o& y4 E
  8.     FDCAN1_Handler.Init.Mode=FDCAN_MODE_NORMAL;                     //正常模式
    8 O/ w, q1 `; {
  9.     FDCAN1_Handler.Init.AutoRetransmission=DISABLE;                 //关闭自动重传7 n" X! i& T( Y* b6 R+ z
  10.     FDCAN1_Handler.Init.TransmitPause=DISABLE;                      //关闭传输暂停           
    ( l  r! j8 y4 Y' g
  11.     FDCAN1_Handler.Init.ProtocolException=DISABLE;                  //关闭协议异常处理
    # U- C% q! F6 w; r# t
  12.         ( r- k% e3 K. `8 \  I6 j& q
  13.         //时钟为200M,baudrate=200M/(NominalTimeSeg1+NominalTimeSeg2+1)/NominalPrescaler,这里配置为1M
    9 s4 u" H+ a# u5 |! @
  14.     FDCAN1_Handler.Init.NominalPrescaler=10;                        //分频系数
    + h3 b1 V( m" z+ j8 v
  15.     FDCAN1_Handler.Init.NominalSyncJumpWidth=8;                     //重新同步跳跃宽度0 h/ t5 M7 q1 d$ a( ?/ ^
  16.     FDCAN1_Handler.Init.NominalTimeSeg1=11;                         //tsg1范围:2~256
    " m' ~7 k: ?: I0 F) f. X# W
  17.     FDCAN1_Handler.Init.NominalTimeSeg2=8;                          //tsg2范围:2~1286 x* ^( D. q1 \4 f3 Y
  18.         / Y1 g9 a5 J" t$ d& g) i: z9 x
  19.     FDCAN1_Handler.Init.MessageRAMOffset=0;                         //信息RAM偏移,10KB消息RAM共有2560字,故可以偏移0~25600 O$ q% S  m8 t
  20.         //使用了多少个滤波器就要设置为多少
    7 `( n$ m, }: o8 T
  21.     FDCAN1_Handler.Init.StdFiltersNbr=3;                            //标准帧滤波器个数,0~128
      r9 k2 D/ v2 a) m
  22.     FDCAN1_Handler.Init.ExtFiltersNbr=2;                            //扩展帧滤波器个数,0~64
    % ~5 o2 M0 C' C+ E! {8 \4 J% k
  23.         - C: G& e$ Y) y. }& A: L3 x" E
  24.         //接收FIFO0、FIFO1和buffer配置,此处没有使用FIFO1故个数设置为0" J* ]# b5 H0 j+ _( M3 m% l
  25.     FDCAN1_Handler.Init.RxFifo0ElmtsNbr=64;                         //设置接收FIFO0元素个数,0-64. S9 a/ T; i. g( ?  q5 w
  26.     FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO0元素的数据域大小:8字节        / T. J9 [: t  V
  27.     FDCAN1_Handler.Init.RxFifo1ElmtsNbr=0;                          //设置接收FIFO1元素个数,0-64
    5 e  M; V" s: N  [4 V, H! e
  28.     FDCAN1_Handler.Init.RxFifo1ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO1元素的数据域大小:8字节               
    5 {* _/ H5 x+ @3 }
  29.     FDCAN1_Handler.Init.RxBuffersNbr=64;                            //接收buffer元素个数,0~64
    2 g% u  s- j- X+ L8 F4 ~
  30.         FDCAN1_Handler.Init.RxBufferSize=FDCAN_DATA_BYTES_8;            //接收buffer元素的数据域大小:8字节        
    2 l( V. Q9 }) @8 \* Q. c+ B
  31.         
    % Q5 u* J- ^% B# Y) o7 i* ~2 f
  32.         //没有使用发送事件FIFO功能,故TxEventsNbr设置为0。把发送buffer全部作为专用发送buffer使用,故TxFifoQueueElmtsNbr设为0.
    4 F! F. m" {. i6 A9 G3 x
  33.     FDCAN1_Handler.Init.TxEventsNbr=0;                              //发送事件FIFO元素个数,0~32, \9 q$ ]9 b: |- P
  34.     FDCAN1_Handler.Init.TxBuffersNbr=32;                            //发送buffer元素个数,0~32+ M9 G7 I8 {# _  X1 t: N
  35.     FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=0;                      //发送Buffer被用作发送FIFO/队列的元素个数,0~32% x6 ~! ?$ F. G! v0 u
  36.     FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION;    //发送FIFO模式选择,可以选择FIFO模式或队列模式
    8 {  m, r* v6 a9 I: x
  37.     FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8;              //发送元素的数据域大小:8字节
    * f4 J+ r5 Z4 T5 R5 C4 Q: |
  38.         
    3 z+ N& i  O( N1 q0 A# V
  39.     if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1;          //初始化FDCAN
    9 T9 |2 S% p5 @, h8 {4 c) C

  40. 6 q* P: R4 t8 E$ N
  41.     //配置RX滤波器,标准帧   1 L" h( x" z) y  s* N0 K% V  U
  42.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID, F/ w* `+ w. U6 M) ^/ B
  43.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                   % \8 r  h3 n) G" d
  44.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    1 ?9 A" u5 e0 l4 \- k
  45.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  " K# \* \' T# w- j" y/ ?# B
  46.     FDCAN1_RXFilter.FilterID1=0x112;                                //11位ID
    6 X4 L5 V  v% r" y! g4 D, ]
  47.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码( s2 p% v- m. r9 u4 p
  48.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化/ ^2 L( ], j% V! D* E4 T! p7 Y* ^5 T; U
  49.   l8 i  X9 u5 H5 u4 H) O
  50.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID% q" M1 F) O4 m: M  U6 i
  51.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                   & x- f: ^  C; K
  52.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型# ~" f$ [. ]3 n, u$ w* u
  53.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    / ]1 m: F: @1 R( k9 k
  54.     FDCAN1_RXFilter.FilterID1=0x113;                                //11位ID/ Z, @- C* X  _4 ?1 ~) G! E
  55.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    7 U5 I. C2 u3 T9 x+ t9 n% a
  56.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    7 _2 l! I4 |, \% T2 P7 A
  57.         ( P7 ^; V5 ]  C! q$ D
  58.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID; ~; X" E5 c- M
  59.     FDCAN1_RXFilter.FilterIndex=2;                                  //滤波器索引                  
    5 N" Q( @: W$ ?) N9 `2 Z
  60.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    % e6 y3 `% W4 _) |: w3 I; j  r
  61.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  3 `( U3 \$ _8 J: K! u, c( @
  62.     FDCAN1_RXFilter.FilterID1=0x114;                                //11位ID
    1 K( J1 H4 x7 f: v7 P
  63.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    * B- A0 C' V# A4 R! r
  64.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    6 S% k1 ~- Y1 O9 h8 q
  65.         
    9 K% u% r9 U5 _4 W2 n( T
  66.         //配置RX滤波器,扩展帧。标准帧和扩展帧的滤波器索引是分开的   
    & X( `9 ]" D" z+ f% `" ]" d; W
  67.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
    * l) p7 H. j( y* ?4 e1 D2 s% E5 h
  68.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    # V- r- N! F7 f/ o* V8 e* X# a
  69.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    9 `, [+ c  x4 {. t
  70.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    ' Z) z3 |6 V; p) |
  71.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(2 << 12);                  //32位ID. j- I: C' c. u8 c  n' j) h5 U
  72.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码6 m4 [# n5 [8 z. w
  73.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    3 f2 C6 Z0 ?/ D+ v; V
  74. 6 n& s6 ~! r' I6 y4 c  _9 f
  75.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID2 y8 g/ E6 _3 y, s6 h: Y/ ~  A
  76.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                   $ k: t9 F8 ~! `# v; X5 m2 P/ V
  77.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    * u. @8 M8 @$ r5 Q
  78.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    # u7 A8 }" W! B& a) d  u
  79.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(3 << 12);                  //32位ID7 D( n* i5 |5 u) {1 _
  80.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码
    . v- o3 q( ?9 C) v9 j% [
  81.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;    //滤波器初始化7 P! ~2 n" J0 a
  82.         9 L* E8 S7 i+ d) Q4 b5 V: j( f( y
  83.         //滤除的消息直接丢弃
    0 u. U* |! b& P
  84.         HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);  //设置被滤除掉的消息的处理方式
    9 g7 [' |$ _9 v! S$ u* ?
  85.         
    % M+ K) l. `; z
  86.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);   //使能新消息接收中断
    % @- O6 [, Z2 R8 I3 f7 c: n) _
  87.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_TX_COMPLETE,0xffffffff);   //使能消息发送中断,0xffffffff表示所有的发送buffer都触发中断        2 N# A; V6 G) w9 ~4 {
  88.         0 x0 `7 O4 l1 Q# h" f2 X) J
  89.     HAL_FDCAN_Start(&FDCAN1_Handler);                               //开启FDCAN
    9 O4 O, J/ Z9 u" T
  90.     return 0;
    * j, V! y7 M0 Q1 z. j* J, K1 L  L
  91. }
复制代码

( D0 @& w: P# I% @5 t
" e$ a% n2 C; R, B6 I" g六、CAN发送示例(来自正点原子)
2 Q& Y* k9 L1 r2 r
/ ^, s% G! w; R2 ]! V) y# Q" w
  1. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)        
    6 C' J- T6 G) m  V  `
  2. //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8                                    
    * r7 i2 A( w7 g6 o' T% X. Y
  3. //msg:数据指针,最大为8个字节.+ k' m) y0 M% u) P
  4. //返回值:0,成功;
    4 z7 \" r2 H, c) [3 h- j) K3 ]
  5. //                 其他,失败;
    " s0 j) D6 L6 \' H) d- A! t# Y# r
  6. u8 FDCAN1_Send_Msg(u8* msg,u32 len)
    + m" t' |1 H' v: g6 u
  7. {        0 K$ @* q9 a& o# ]+ z- h$ Q5 r
  8.     FDCAN1_TxHeader.Identifier=0x12;                           //32位ID+ ^" z5 H( a$ u$ Z, U& o+ c
  9.     FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID2 H/ d/ B: O3 \, o- P, K4 I
  10.     FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧( J: M9 j; m2 d$ v  Y( P
  11.     FDCAN1_TxHeader.DataLength=len;                            //数据长度2 ]( S* d; e; T1 h/ W
  12.     FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;            + \7 f( I  Q6 Q
  13.     FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换2 i1 O4 @: k$ }! r6 @0 B
  14.     FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式' ~6 B, t' s# F! F* e
  15.     FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    / |1 T6 m. }0 i( O5 X! x
  16.     FDCAN1_TxHeader.MessageMarker=0;                           1 ]* |9 k. x! C  x
  17. ! g8 A. R: x9 Q! t; t/ _
  18.     if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//发送; _0 ?5 e% G7 R3 p- }
  19.     return 0;        ) R+ f' d+ [5 I5 D+ r+ t
  20. }
复制代码
/ E& X; Q: v6 ^0 r& f4 L# r2 k
七、CAN接收示例(来自正点原子,因为滤波器被关联到FIFO0,因此消息只会放入到FIFO0)
1 J' ?- R( z" a/ j' }- S7 F! q! Q" K5 ]5 C% _
  1. //can口接收数据查询
    , m# \* n$ F; Q/ s
  2. //buf:数据缓存区;         ( U  l5 e- N7 `
  3. //返回值:0,无数据被收到;
    $ _! h$ S' w& C, h
  4. //                 其他,接收的数据长度;
    . x, W, n+ A' i
  5. u8 FDCAN1_Receive_Msg(u8 *buf)" N- z9 U' h: T7 j6 r
  6. {        
    3 r3 A& T& Y- A# t7 n1 ?0 A
  7.     if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收数据
    4 Q5 b2 q: q6 [6 ^, _, L
  8.         return FDCAN1_RxHeader.DataLength>>16;        # `' ]3 k9 \7 K3 y% M. L' X
  9. }
复制代码
3 a* q  ?/ k! @. y7 q2 {) l
参考:《正点原子》  STM32H7开发指南-HAL库版本_V1.0 (文档中有很多错误的地方,笔者被误导了好久,阅读的时候还是要以H7官方手册为准)
! B( x* o$ ?: b% z/ L+ R, S. l! d6 U. }( Y

) o* m7 r! ~' V$ x& h: v6 {
收藏 评论0 发布时间:2021-12-22 14:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版