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

【经验分享】STM32H7的FDCAN

[复制链接]
STMCU小助手 发布时间:2021-12-22 14:00
一、介绍
, ~* V5 ?' N' R, m2 [3 ]2 I; w
( T" t. H! C& Y( c) ~0 y6 J        FDCAN(Flexible Data-Rate CAN)是CAN的升级版。特点包括:
6 P/ M& u0 Y# I1 C/ p* J4 U3 ]7 g7 F4 m/ i6 C# a
       1、每帧数据段最大长度由8字节上升到64字节。3 K) y# E$ U6 r: `) [0 o$ j

! Q4 I1 }3 f; `) w. _: @+ z        2、速度由1Mbps上升到5Mbps,甚至还可以更高。在一个数据帧中仲裁段(ID和ACK)的速率和CAN一样最高1Mbps,这样可以保证总线的健壮可靠,但是数据段可以5Mbps甚至更高,一个数据帧中使用不同的波特率,这就是FD(Flexible Data-Rate)的由来。
! C( m! e1 Q2 z% }
' _" w; q- Y: P! ^; m. C9 E6 B        3、向下兼容CAN。
1 X/ l0 I, J4 w$ l) R( j  E& B! F; X1 _
. h: ?) W2 `# i% o3 A9 u0 b        H7的FDCAN包含2个可配置接收FIFO。多达64个专用接收buffer,多达32个专用发送buffer。可配置发送FIFO/队列,可配置发送事件FIFO。$ T2 a' \! {# z9 _
' y' H2 ~7 m# B* K+ S% {3 G: o
二、结构3 Y4 v! i7 ?% |) j* h9 C+ B4 f% {& A

0 Z0 `! u' Q: a& K/ Q4 X; G        先看结构框图:
+ |1 I% l# `7 y4 w" r* N4 H5 e
% g- X' @. d5 E( I+ c7 N. e& J; K
20191121162856859.png

, S/ ]1 M, {2 x, f
( ~5 }- ]- l1 f  x! q( j2 C1、两条中断线:fdcan_intr0_it和fdcan_intr1_it。可以通过FDCAN_ILE寄存器的 EINT0和 EINT1这两个位来使能或者关闭。
! m7 m  J. Q  ^; s* K, n: H0 q) m2 g; r+ _1 J  }$ i" v
20191127102816991.png
' ?- Y" f. }/ X

! O0 C% I  C& b! _; P+ X1 a        可以通过FDCAN_ILS寄存器来选择FDCAN的中断是在fdcan_intr0_it上触发,还是在fdcan_intr1_it上触发,默认所有中断都在fdcan_intr0_it上触发,没有特殊的要求,只需要用一条中断线就可以了。
1 \# l) `7 s  a1 U1 m
! y3 D% C5 J) V; c  M& c" T2、TX Handler:负责将消息RAM中的数据发送到CAN内核,最多可配置32个发送buffer进行发送。发送buffer可用作专用发送buffer、发送FIFO(发送队列的组成部分)或二者的组合。发送事件FIFO会将发送时间戳与相应的消息ID存储在一起,另外还支持取消发送。+ w$ W7 l# U% Q, [2 b" _

7 l! j( J+ w% g/ {, ^4 k. V" Z7 H3、RX Handler:负责将CAN内核的数据传输到消息RAM,支持两个接收FIFO(每个FIFO的大小均可配置)以及最多64个专用接收buffer(用于存储所有通过验收过滤的消息)。专用接收buffer仅用于存储具有特定标识符的消息,与接收FIFO有所不同。每条消息均与其接收时间戳存储在一起。
% x0 z. J, S) d5 ~- j; }" _: v& R/ t- u8 P, |2 C
4、CAN core:CAN内核,读RX引脚数据处理后给RX Handler,接收TX Handler处理后控制TX引脚。
7 g  D# ~9 D% n& C8 C& ?8 `
- I4 q2 O7 T1 d* a. U& y5、Message RAM interface:消息RAM接口,外面连接着消息RAM。消息RAM是FDCAN的核心,本质是一段最大10KB的内存,把这段内存分成不同的区域,每个区域的作用不同,可以实现:过滤器、接收FIFO、接收buffer、发送事件FIFO、发送buffer。内存分配如下:
9 d8 G) b0 e4 i/ l9 j1 u# ?/ F1 V2 i9 i! ?' A2 @( o: W, i
20191121164211703.png

$ A: t3 c7 C' q6 N  N4 D5 T% Z
4 [5 x+ Q& r0 B        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字。
2 F5 Y% X% [) `; Z
' \' d6 ~- ]& {( @        1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,最多可以有128个元素。
) ^; b9 t; I' c" {0 u
1 K6 P1 k, B8 I* J+ a, p' u        2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,最多可以有64个元素。(F1配置寄存器来设置过滤ID,H7直接划了个内存区来设置过滤ID)  O5 v$ Y* X2 I/ ?0 R/ T

6 T; l- K. e& ?5 Q, W# q, u. j3 c; j        3)、RXF0C.F0SA:接收FIFO0,最多可以有64个元素,可以接收64条消息。
* T  x7 @# F3 J4 A* ]) ^% x+ ?: x7 ]3 [; X% W
        4)、RXF1C.F1SA:接收FIFO1,最多可以有64个元素,可以接收64条消息。
6 u3 r/ u" z0 P0 m' p
5 s% S1 a  Y7 T1 @6 `        5)、RXBC.RBSA:接收buffer,最多可以有64个元素。
$ \, n+ Z' G8 N6 r6 ]' J9 ]. d# X) }( H
        6)、TXEFC.EFSA:发送事件FIFO,最多可以有32个元素。(不是发送FIFO)
  K* b, B6 u) g8 |% e2 Z5 q! L* g$ @; o& l7 n
        7)、TXBC.TBSA:发送buffer,最多可以有32个元素。3 l% T) b% ?; k0 V. |8 q
& a. k$ n+ |4 C+ R( f1 {  @- M  S1 Z
        8)、TMC.TMSA:触发存储器,最多可以有64个元素。! w$ Z2 E* g0 ?, N* T5 O

8 O# @9 T  T" S% e《注:这8个区域的元素个数和元素大小都是可以配置的,但是这8个区域的地址又是连续的。因此在初始化的时候,会根据每个区域的元素个数和大小来计算下一个区域的起始地址,并保存到相应的寄存器中》- k" y+ T# Z8 n, B
% R4 V. Y" R) L
        下面来详细介绍这几个功能区域:" H/ X' v" ?* I$ X
! E! O" c: Q2 U$ m6 ~
1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,有128个元素,每个元素占一个字,定义为:
* s8 O$ C' ]! l4 S% v) C) B4 ?& J: h1 W: b! b" K4 y
20191121170625565.png
  ~! ?8 h5 y% ?% B8 W% Z0 p# i$ r3 Z

' J% _2 O, ]& E& ^SFT[1:0](bit31:30):这两位用来表示过滤类型,一共有四种:- L, E: A4 r& R- }0 z2 D# O
    00:范围过滤,过滤到SFID1到SFID2中的所有信息。- r5 n7 K( J7 K) w
    01:双过滤,过滤到SFID1和SFID2中的信息。; e: u3 t+ S5 w* L
    10:传统位过滤,SFID1 是过滤值,SFID2 是掩码。! B, ^: E5 N# k
    11:禁止过滤器元素
6 C: b9 m, Z3 b# @& B2 J8 tSFEC[2:0](bit29:27):标准过滤配置
, z! J9 R) r7 b' u7 C" p    000:禁止过滤器元素
4 n' F5 u# |$ x/ G, E! R+ X4 z9 E: n    001:当过滤匹配以后存储在Rx FIFO0中。
. t# ?6 a  S4 e4 C# r) V    010:当过滤匹配以后存储在Rx FIFO1中。: G0 G( Z0 p: t+ Q1 S
    011:当过滤匹配以后丢弃。0 b0 A. u5 @) X: p
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。+ a* ~' B, k1 S7 f( F0 f' x' b% O* H
    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。) H  G$ V. S- b& S, B6 l. n5 P
    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。3 U4 ^' V4 m  q3 t9 U4 x
    111:存储到Rx buffer中或者作为debug消息,FDCAN SFT[1:0]忽略。3 b" s( @7 @, d: R$ F
SFID1[10:0](bit26:16):标准过滤ID1,第一个要过滤的ID。
" U- V0 X; _6 M& Z! @* SSFID2[15:10](bit15:10):标准过滤ID2,此位根据SFEC的配置不同而不同,当SFEC=001~110的时候此位域表示标准过滤ID。当SFEC=111的时候此位域表示Rx buffer或者debug消息。$ h$ M1 n5 v, ^
; ^  N. ^# ?/ ?
SFID2[10:9](bit10:9):设置接收到的消息是存放在Rxbuffer中还是处理为debug消息的消息A、B或C。) j* z2 e$ r. f: [1 @; l
    00:将消息存储在Rx Buffer中。
6 g" _9 z- j: H0 Q) u% N
9 c9 R6 s& k- o) l$ ]6 W" {" E    01:debug消息A。    + d) W5 z' b5 N4 F2 t/ r5 M3 S
" j3 j$ O/ M4 q( _3 U/ f' H  b4 {
    10:debug消息B。3 W( ?: j% U+ [
9 F" b1 M6 |/ @% u* Y5 [  y
    11:debug消息C。* @3 w% }$ [& X+ u, V4 Y
3 r2 D6 h1 V3 G8 f: ~, Z! {' ]2 r
SFID2[8:6](bit8:6):确定是否将滤波器事件引脚作为外部接口。
9 N$ ~5 N, |4 S3 k
/ C. w1 C' c3 k4 s( XSFID2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer 的开始地址RXBC.RBSA的偏移。
7 x. _3 X! K; @+ P
" [5 K. B9 G: |4 i* V% b# c2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,有64个元素,每个元素占2个字,定义为:2 B4 G4 u: M9 @7 o# M! q

, Q) Z) p8 D; Y7 F% u
20191121171836710.png

4 N8 b% x. g7 z: ?4 e& n, o; f. k. ^
F0 EFEC[2:0](bit31:29):扩展过滤配置, Z( K' F7 z( b/ E& @* H
    000:禁止过滤器元素. [3 h9 _: ?6 ~( J4 I" `
    001:当过滤匹配以后存储在Rx FIFO0中。
  x+ @' L- C8 ?2 }    010:当过滤匹配以后存储在Rx FIFO1中
( t6 |) {+ W$ p# o3 f! L$ W9 e    011:当过滤匹配以后丢弃。* p: K& ]* V4 W  S9 r# d
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。* L4 P4 l( H* Q
    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。! ?  W) o" t) S/ M( [: i- _
    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。+ |, Q2 f, C& u1 f* z2 |
    111:存储到Rx buffer中,EFT[1:0]忽略。
2 d! s( z) _: ?: ]/ c: s4 e2 `( xF0 EFID1[28:0](bit28:0):扩展过滤ID1。
# A+ O1 G$ j) q' V% [4 B* rF1 EFTI[1:0](bit31:30):扩展过滤类型: D3 }# s$ @4 M1 z$ d' g/ I
    00:范围过滤,过滤到EF1ID到EF2ID中的所有信息。
3 I/ k. m8 ]8 N# |2 o2 Y3 k& X% C    01:双过滤,过滤到EF1ID和EF2ID中的信息。
9 m5 U0 _2 g* q- `    10:传统位过滤,EF1ID 是过滤值,EF2ID 是掩码。
# Y' w7 C5 v! a) [1 s    11:范围过滤,过滤到ED1ID到ED2ID中的所有信息,没有使用FDCAN XIDAM的掩码1 L1 Z' X; m- `  Y/ a
F1 EFID2[10:9](bit10:9):设置接收到的消息是存放在Rx buffer中还是处理为debug消息的消息A、B或C。0 r. ?  u4 e) o7 A& M- B
    00将消息存储在Rx Buffer中。/ G( @3 X& }0 D  H( J" }' v" E
    01:debug消息A。
' T3 \7 X1 F  h1 t' Y6 C    10:debug消息B。' g  n' q3 K/ K' V% j3 q& Y
    11:debug消息C.' o  S. }  T& ?. |* S
F1 EFD2[8:6]bit8:6):确定是否将滤波器事件引脚作为外部接口。
2 g% ]; i9 e' l$ rF1EDIF2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer的开始地址RXBC.RBSA的偏移。
: z" j4 S; L/ I  ]+ Z. [5 v' g% c' _6 H7 n/ o6 w% U) G
3)、RXF0C.F0SA、RXF1C.F1SA和 RXBC.RBSA分别为Rx FIFO0、Rx FIFO1、Rx buffer,它们都有64个元素,元素的大小根据数据长度不同而不同,范围为4-18字,它们的位定义相同:$ H/ j+ G" j8 m" `- E+ G( k
, N( A2 u% W. u* T- w$ i! ?
20191121172451477.png

7 Y# m% Q1 {2 q% z! P3 a0 s$ c& h- D. Q
R0 ESI(bit31):错误状态标志
; `, _' k5 [- u* D6 w& X$ l    0:传输节点显性错误。# z8 z1 Y; d- o9 q
    1:传输节点隐形错误& ^- F; u" Y) Z$ ]) A" d
R0 XTD(bit30):标记是标准ID还是扩展ID/ K; d, g/ }+ V% \( J0 u' B' z
    0:11位标准ID8 ]" {- o, {3 |/ D+ J

1 j2 b9 G$ ~1 ~5 f    1:29位扩展ID
$ `. c6 r8 c7 g) c1 a* H4 V' ?" I! K2 s# h' e. B% k- k
R0 RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。# ^+ [0 _- o5 ~
    0:接收到的帧是数据帧8 H$ l. c/ @& u$ z+ F) M

" ]$ `* y9 V- g/ L' E8 L& \    1:接收到的帧是遥控帧
+ I. @' `$ M3 @R0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。5 t+ ]/ J4 R( l% c' D% T
R1 ANMF(bit31):, ?9 b  Q6 N5 Y& u

8 m& l2 R2 n7 c  a: i    0:接收到的帧和FIDX中的过滤帧匹配
1 F% t1 u9 _& O4 W* A7 V  c/ K4 B& Z; B' E6 C* d' w
    1:接收到的帧和Rx滤波器中的任何元素都不匹配' N% k6 C5 m  K3 N! b$ r
R1 FIDX[6:0]bit30:24):过滤器索引,0~127,表示和Rx滤波器中的哪个元素匹配。* {: ]' V5 g9 `7 j" Y
R1 FDF(bit21):帧格式9 ^1 U. J$ J" t
    0:标准帧格式4 x" _& d8 H7 v' \, @. y: d
    1:FDCAN帧格式。- U0 w2 E" n7 }' h2 T0 d1 Z
R1 BRS(bit20):比特率切换
& K( c- Z$ P. E    0:接收到的帧没有比特率切换
/ a) e; o6 r1 N6 r9 W0 j* t
' N) Y' K/ K4 I% ~    1:接收到的帧带有比特率切换
! c5 _% |' [$ Y+ ZR1 DLC[3:0](bit):数据长度。, H* t! [" M/ ?' P- c8 o8 P, w& S
    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
2 I6 x$ c) M; f$ G7 p* x    9-15:如果是传统CAN,接收帧长度为8字节。
/ `% q( i% f2 k    9-15:如果是 CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64 字节。
6 o1 f% ~4 I7 GR1 RXTS[15:0](bit15:0):接收时间戳。( @: \0 r' C, F2 h
R2-Rn:接收到的数据。& r( Z1 b0 h3 B$ M5 X1 ^- V7 j9 b

. y6 W- Q" |( I1 y4)、TXEFC.EFSA:发送事件FIFO,有32个元素,每个元素两个字。6 s- R2 A% o6 V
2 P- O. ]3 E- ]/ P2 h# \$ X" N* |
20191121174147402.png
( i8 q* _; y5 d3 H2 s9 J4 I# l( R
/ ?( Z2 V! k4 {! D$ k
E0 ESI (bit31): 错误状态标志' v: o7 F7 j- f$ u) H9 V1 G, F

6 ], q% C' T- }. Q, r/ v    0:传输节点显性错误& j1 |4 o% t- v' A* U
    1:传输节点隐形错误。
- U- q8 C" P5 M! R: t1 F% p/ \E0 XTD(bit30):标记是标准D还是扩展ID) X0 {! M! v* h( [  ^7 c1 G
    0:11位标准ID.% R; J5 V7 [& B& y( m
    1:29位扩展ID
9 o' P; \  P6 E3 D1 @$ {2 B$ }
' ]- c1 M) Y0 Z( zE0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。6 I5 G/ z7 S/ Q2 V
    0:发送的帧是数据帧' R' M  C+ y9 r; r/ [" S
    1:发送到的帧是遥控帧
) s9 u( f0 j# w$ F/ n* P# B9 pE0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11 位ID还是29位ID。
( w6 p* R4 k* A$ k8 YE1 MM[7:0](bit31:24):消息掩码,从Tx buffer拷贝到Tx Event FIFO中。" V; P* W5 E2 v7 F$ X' Y! y5 n
E1 EFC(bit23:22):事件类型$ m& }, c* Q4 J. v7 w' h9 B
    00:保留。
7 g. R6 W3 U( h) o( X2 I/ A    01:发送事件。
- x3 O8 y$ g" Z" {    10:发送取消。: ^" ~! Y( G5 @3 J, v6 l2 K' o8 N
    11 :保留。- D1 |; x' ]; X+ R1 ^
E1 EDL(bit21):扩展数据长度  [. q# `2 O' \/ A' E/ R
    0:标准帧格式, C4 \+ c5 j0 k
    1:FDCAN帧格式。# k0 A: o0 w2 f- Q( _
E1 BRS(bit20):比特率切换
/ n& v  J8 l- t, W6 a    0:发送的帧没有比特率切换# r% b* C& I( w' U. B. J
; P2 X# V* o1 q( [# `6 f
    1:发送的帧带有比特率切换+ c+ |# E" ?+ w* y. ~/ ^
E1 DLC[19:16](bit):数据长度。- h; P! f9 u! Z
    0-8:传统CAN+CANFD,长度为0~8字节。( y' s3 w" s9 L- A0 D. }6 |1 {9 y
    9-15:长度为8字节。9 X9 p1 }3 P1 a- F: C' A; o
E1 TXTS[15:0]bit15:0):时间戳。
6 [# r+ {8 Y5 p: P" k
( O  N$ P4 t% R) b4 y5)、TXBC.TBSA:发送buffer,有32个元素。
" Z# Z. m, k8 p  w% |7 r
' i2 g' y1 }" \' r2 c& m
20191121175121493.png

" \9 {4 T& d9 \. X
. G1 k+ Y( B; L( k: ~T0 ESI(bit31):错误状态标志  \" g8 i8 O& B0 p. N
    0:CANFD帧中取决于被动错误标志。4 b1 J7 ?+ }6 m8 R2 p
    1:CANFD帧中隐形错误。- ~' S: }% P: o# |
T0 XTD(bit30):标记是标准ID还是扩展ID
3 d0 E' _+ w+ ~2 Y# N7 ]( }/ \5 f4 l    0:11位标准ID
2 Y2 k; o$ d8 X/ Y" l
* E0 h- `+ H& e6 {5 |    1:29位扩展ID8 {' k% s9 N, j, g

  u, K- `: L2 \+ l  yT0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。3 V1 P( P' s+ J5 k/ U# g
    0:发送的帧是数据帧3 m$ i7 X: ^+ K3 V6 ]( k& X) v
    1:发送到的帧是遥控帧
* Z/ O2 _3 @; y: M- ^, YT0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。9 R# N* z3 `: ?# b$ f( C# o  @
T1 MM[7:0](bit31:24):消息掩码,配置Tx buffer的时候由CPU写入。
1 H' x, D; g7 rT1 EFC(bit23):事件FIFO控制# ]' ^/ |  e, G4 [& I# [7 F2 k
    0:不存储发送事件。% F6 f' G4 \% k: [7 X4 [# o, q
    1:存储发送事件。) G0 B$ \0 [% L" ?
T1 FDF(bit1):帧格式$ ?6 r6 C0 R( u+ c
    0:标准帧格式# F. I+ r: T' X/ w: _- P
    1:FDCAN帧格式。2 g4 `; W/ |: h
T1 BRS(bit20):比特率切换
9 U& f" ^7 f* W% z% v( C, B    0:发送的帧没有比特率切换
& L& X1 T; J7 H4 z" S( v# D' B5 j. w' z' o" z3 {7 b
    1:发送的帧带有比特率切换
1 H" R/ X- P* F+ L$ ?" }3 _: r+ aT1 DLC[19:16](bit):数据长度。1 I. f# {1 e8 x
    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
# b" K  u9 |/ D' k    9-15:传统CAN,接收帧长度为8字节。
( Q( V* J( U8 X+ u    9-15:CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64字节。
; \5 y' @& [9 I# d" o8 lT2-Tn:发送的数据。
/ m) C/ n' R6 i* X1 k- M2 [( `& J/ r" ], ?
三、过滤器设置
: S+ E' m' F' l# ~% k% j/ m+ y0 N! S
        标准帧和扩展帧过滤器的设置分别往SIDFC.FLSSA和 XIDFC.FLESA区域写数据即可,下面以标准帧为例,标准帧过滤器共有3种过滤模式:5 g0 H% Y. i+ K; r+ I8 m) Z
) ]: F- c- m. `0 g/ A
        1、指定范围过滤2 u( S2 @% I6 R8 B+ n# k7 R/ K7 y
        通过SIDFC.FLSSA的SFID1和SFID2来设置需要过滤的ID范围,其中SFID2的值要大于SFID1,这样只有ID值在SFID1~SFID2之内的消息才能被接收到。比如我们现在要设置只接收ID在0X123~0X321范围内的消息,使用标准滤波器n,SIDFC.FLSSAn(n=0~128)的各个位设置如下:8 W" K7 s5 G3 p) ^  {

% z. N0 P+ T& @* G0 A/ `; k
  1. SIDFC.FLSSAn.SFT=0        //范围滤波2 A$ R$ b8 d* s; W
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到RxFIFO中& E( I+ P' j6 j) _
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    8 z' O( c7 T& e- ?: ^/ }
  4. SDIFC.FLSSAn.SFID2=0X321  //ID2
复制代码

4 l- V) m, \* k9 {6 |% H  m        2、指定ID过滤
8 x* Z3 e( o0 S% s& ^4 Z
  X) o+ _5 y, O) H3 [8 T$ v" C        我们也可以设置只接收指定的一个或者两个ID的消息,如果只接收指定的一个ID消息的话SFID1=SFID2。比如我们要设置只接收ID为0X123的消息,设置如下:, V4 u& x7 i# n  u1 ?4 N
4 Y; D5 g5 @0 W9 f  G" i+ M. J+ f
  1. SIDFC.FLSSAn.SFT=1        //指定D过滤
    6 A" [1 T6 Z7 D; g; e
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到Rx FIFO中" K! g/ Y/ h" `. A( |+ u! i
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    4 ~2 u2 M" o* z3 t' S
  4. SDIFC.FLSSAn.SFID2=0X123  //ID2
复制代码
9 U/ M& n( a/ |6 s- O; Q; _2 i* V! T
        3、传统的位过滤! X0 d6 [4 Q6 x- ?) a; A
        第3种过滤模式就是以前STM32的CAN上存在的位过滤模式,在屏蔽位模式下,过滤消息D和过滤掩码一起工作决定接收哪些消息,其中SFID1为过滤的消息ID,SFID2 为过滤掩码。举个简单的例子,我们设置过滤器SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:
$ v% N5 f3 I+ l0 j/ P' d; T& P0 w* y; o0 `3 u  T
  1. SIDFC.FLSSAn.SFT=2          //传统位过滤
    1 J6 a6 a/ L- ?' D
  2. SDIFC.FLSSAn.SFEC=1         //如果滤波匹配成功的话将消息保存到Rx FIFO中
    ! |9 O0 I5 ]% F$ a9 l( P
  3. SDIFC.FL SSAn.SFID1=0xFF00  //ID1
    ! s- K4 M: f( ]3 A
  4. SDIFC.FLSSAn.SFID2=0xF00    //掩码
复制代码
0 i0 s9 g: n4 j, ]* @
        其中SFID1是我们期望接收到的消息ID,我们希望最好接收到ID=0xFF00的消息。SFID2的0xF000规定了我们必须关心的ID,也就是接收到的消息ID其位[15:12]必须和SFID1中的位[15:12]完全一样,其他的位不关心。也即是说接收到的消息ID必须是0XxFxx这样的才算正确(x表示不关心)。' B+ c" ?2 t$ s2 x

6 I" C9 L/ }6 \" g四、CAN的收发过程
# O0 A6 s4 }* @. w- B' q% ]
# y$ H- T, E! f3 ^6 d/ G& i/ e$ z        1、CAN接收过程
" {: k) Z% u4 O! ^+ G. h5 z4 I& v2 k' w9 ^7 E% C2 l
        CAN接收到消息后会进行过滤,过滤时会从SIDFC.FLSSA或XIDFC.FLESA区域的第0个元素开始匹配,直至符合过滤器中的某个元素的规则,则过滤完成,过滤完成的消息会按照过滤器元素的配置进行处理。比如过滤器元素的SFEC/EFEC位决定过滤后的消息是放入接收FIFO0、接收FIFO1还是专用的接收buffer中。
2 M9 ]% ^. O& h$ D  u* ?2 ?
6 p* [/ c# T2 }: d6 q: X4 O$ D        接收FIFO 0 和接收FIFO 1 最多可分别保存64个元素。两个接收FIFO的配置是通过寄存器RXF0C和RXF1C完成的。
; j+ y, \% o9 Z0 V- g
( W* ]; X6 p& ~& A- g) I
20191127114550965.png

* y# g4 x3 L1 e+ b* @. U: I/ d; b+ _* F$ q2 Q) K6 X0 b5 b
        当IR寄存器的RFnF(n为0或1,代表接收FIFO0或接收FIFO1)指示接收FIFO已满条件时,在至少已读取一条消息且接收FIFO 获取索引递增之前,不会继续向相应的接收 FIFO 写入消息。如果在相应的接收 FIFO 已满时收到消息, 此消息会被丢弃,中断标志IR[RFnL]会置 1。也就是说,接收FIFO满了后会触发RFnF中断,如果继续接收,消息会被丢弃,并触发RFnL中断。$ f. R' U* b& a# B/ D  j
# T' e0 i( z& w" y" x

0 d5 w8 \6 y1 x. j3 u4 `3 ~
20191127111235302.png

4 E, g% B! e5 v4 X+ `& K8 z, K
, ~& B# _- ]4 H% m& `        为了避免接收FIFO溢出,可使用接收FIFO水印。当接收FIFO填充级别达到由RXFnC[FnWM] 配置的接收FIFO水印时,中断标志IR[RFnW]会置 1。比如接收FIFO0大小配置为64,水印值配置为60,当接收了60条消息时会触发水印中断,提前进行处理,这样就避免了FIFO溢出。3 \" ~; w4 G% f' U  i
        读取消息就是直接从RXF0C.F0SAn或RXF1C.F1SAn(n为索引号 0~64)中读,消息的组成结构在上面已经说过了,比如HAL库HAL_FDCAN_GetRxMessage函数读数据过程(假定从FIFO0中读):
0 {/ C/ k& ]) N( @
  b/ |* x: r  F( l% _/ L& o1 I6 \1 D- @
  1. /* Calculate Rx FIFO 0 element address */' s2 Q) i( G2 P! G
  2. GetIndex = ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8);
    0 b7 {9 W) U6 M
  3. RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4));
复制代码
9 b1 D& N1 o6 Z7 \9 M3 }
1)、((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8):作用是获得FIFO0状态寄存器FDCAN_RXF0S的bit[13:8],读这里可以知道接收到的数据保存在FIFO0中的第几个元素中,GetIndex的范围是0-63,刚好对应64个元素。当FIFO接收到一条消息,GetIndex会加一,当从FIFO中取出一条消息,GetIndex会减一。/ ~  t4 j' Y. L. x/ i0 M

. S4 s" e- S7 _* y1 M
2019112119095892.png

% `: @6 \& j, v5 V; X3 S% v& t  v1 @9 N
2)、hfdcan->msgRam.RxFIFO0SA:是RXF0C.F0SA区域的开始地址。
( B  t% G7 l" y4 B6 N! L
7 K' |; K4 H0 z3)、hfdcan->Init.RxFifo0ElmtSize:是接收FIFO0的元素大小,根据数据长度不同而不同
6 [- P" L" Y7 R' A/ c2 r: P9 s) V8 h7 T, E# W% Z: z

# k# a6 v: `- J& ]" E( s
& H* G# y! y; z如果消息长度是8个字节,那么算上固定的R0、R1,元素大小就是4个字。6 F1 }$ W# d# W2 l% d8 i  o$ s
# ^+ x9 @$ Y0 h- i7 c
如果消息长度是64个字节,那么元素大小就是64/4+2=18个字。3 d$ ^5 g* p, ]& E7 S' E& T; X

9 ~0 [% F: t- |        计算出了元素在FIFO0中的地址,直接按数据结构读数据就可以了:
; C% v) C* T9 N4 ~, t4 o4 k- ]6 a7 K1 V0 J
  1. pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;
    : f6 `7 Q) {2 t: X5 L
  2. pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);0 n9 [. K4 q, I
  3. pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);
    9 f2 Z7 W$ N4 d9 c" \
  4. pRxHeader->ErrorStateIndicator = (*RxAddress++ & FDCAN_ELEMENT_MASK_ESI);  //这里地址自加了一次  ~5 F4 B/ j+ i! ]3 v0 z3 W
  5. pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);7 q' _$ y5 b7 U% h- h. o2 `
  6. pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);
    * U- d, s& w  D
  7. pRxHeader->IsFilterMatchingFrame = ((*RxAddress++ & FDCAN_ELEMENT_MASK_ANMF) >> 31); //这里地址又自加了一次' m5 d' S8 s$ t; \6 z: z
  8. ......
    . F1 N) I; z2 G" A% x
  9. pData = (uint8_t *)RxAddress;2 H$ W' @1 B- a4 l* Z/ p
  10. for(ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++)
    , {: M# c5 o" b; r4 p* X
  11. {
    9 P7 l  l: [# q! K% b4 N
  12.     *pRxData++ = *pData++;5 _! d% n& s5 \1 t9 A0 b1 P
  13. }
复制代码

3 o0 }5 |8 [1 l        2、CAN发送流程) T' N) T$ U8 c1 f! G2 F
( P1 G$ @  }, s! _
        在消息RAM中TXBC.TBSA是发送buffer,最多有32个元素。发送buffer可以配置为专用发送buffer和发送FIFO/队列。发送FIFO/队列是指要么是发送FIFO,要么是发送队列,即发送FIFO模式或发送队列模式,由TXBC[TFQM]决定:' n, r- x/ i' E( s" o$ T, X
* Q5 A7 J0 t" Y  S& N0 P) g
20191127150042199.png

) U: U, f/ E) J( b% r6 M
1 }) A9 O, q1 A) h        因此发送buffer可以有三种组合:全部是专用发送buffer、专用发送buffer加发送FIFO、专用发送buffer加发送队列。
) y/ d% T' @2 g' w( P2 k5 x, E. C4 {# I+ {( ~' R2 I2 B5 W4 a4 O
        下面来介绍一下专用发送buffer、发送FIFO、发送队列的情况:, ?& v7 @9 e8 m7 C( P* N3 }

# `4 P' v) e2 A' h- t        1)、专用发送buffer9 ^- T' q- s: v( u

5 t) z( V+ K# D, o. T2 R8 R         专用发送buffer可完全在CPU的控制下发送消息。每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。/ [1 ]; I0 @2 o' V8 b4 H  `
        如果数据部分已更新,则会通过添加请求的TXBAR[ARn] 位请求发送。请求的消息在内部会与发送FIFO/队列中的消息进行仲裁,在外部会与CAN总线上的消息进行仲裁, 并会根据其消息ID发送出去。
0 q4 J2 X3 O  S: H0 z( ^) _# D: t7 P
20191122101555794.png
* |/ N" N1 P$ j, e* S
1 h0 H, H6 [5 M* E1 C6 `5 C  O: \6 Y
        专用发送buffer会在消息RAM中分配四个32位字(元素大小为4个字)。因此消息RAM中专用发送buffer的起始地址是:
  @0 t) P$ j  x% P1 ?8 ]: [- B( H; v# o
发送buffer索引 (0…31) *4+发送buffer起始地址。9 }6 H5 F6 ~! k, l7 ^7 j
, D, Q$ X2 B4 m( A& Q' t

3 S# E* M. O, q; d+ [# i2 L# P9 H# ^1 I4 v0 \, s4 ]
        2)、发送FIFO4 N+ }# L4 E2 e+ c5 P# W

3 {4 @# j% \- ~7 q        发送FIFO中存储的消息是先从获取索引TXFQS[TFGI] 引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送FIFO为空。发送FIFO可按消息写入发送FIFO的顺序发送来自不同发送buffer但消息ID相同的消息。FDCAN会计算获取索引和放入索引之差作为发送FIFO空闲级别TXFQS[TFFL],用于指示可用(空闲)的发送 FIFO 元素数。( p0 f; ^$ |/ ~! B) }3 m
        新的发送消息必须写入以放入索引 TXFQS[TFQPI] 引用的发送buffer开始的发送FIFO中。 添加请求会将放入索引增加到下一空闲发送FIFO元素。放入索引达到获取索引后,会指示发送FIFO已满(TXFQS[TFQF]=“1”)。在这种情况下,下一条消息已发送且获取索引已递增之前,不应继续向发送FIFO写入消息。" b5 q2 Y$ j- H% t3 V+ d' a
, K3 [, ~% Z2 ?  C3 b* y" V4 M, v
20191127160804244.png
: j, T1 [' k" F7 t

7 ?  v7 x. w: j$ [, K! e" Q        发送FIFO其实就是个环形队列,放入索引是队头,获取索引是队尾,队头和队尾之间保存着消息,相减当然就是待发送消息个数。当从发送FIFO取出数据,获取索引会自加,自加到等于放入索引时,表示发送FIFO为空。当放入数据到发送FIFO,放入索引自加,当绕了一圈自加到等于获取索引时,表示发送FIFO满了。
" z5 c' y; K) r
. S0 f' e% \. Z; D1 ^        如果有一条消息添加到发送FIFO,则会通过向与发送FIFO放入索引引用的发送buffer相关的TXBAR位写入“1”来请求消息的发送。
, P% Z# u( u: a8 t0 U        如果有多条 (n条) 消息添加到发送FIFO,则会写入以放入索引开始的n个连续发送buffer中。 随后会通过TXBAR请求发送。放入索引随后会循环递增n。请求的发送buffer数不应超过发送FIFO空闲级别指示的空闲发送buffer数。
$ o# {. t0 X/ N% _% z        如果获取索引引用的发送buffer的发送请求取消,获取索引会增加到下一个具有挂起发送请求的发送buffer,并会重新计算发送FIFO空闲级别。如果取消对其他任何发送buffer的发送,获取索引和FIFO空闲级别保持不变。3 _$ t; ]  a2 @  C; @
        发送FIFO元素会在消息RAM中分配4个32位字。因此下一可用(空闲)发送FIFO 缓冲区的起始地址是:7 e. A6 ^5 e% h) h; l& n9 D

2 P8 v1 p6 u. j4 {/ e放入索引 TXFQS[TFQPI] (0…31)的值*4+发送buffer起始地址。
5 Q4 ~8 O$ O3 s: H, x: V% [, u$ q- g0 _& C1 e. o
        3)、发送队列
& B- U( a* s/ G* j$ T  T$ j- A3 O) J8 G        发送队列中存储的消息是先从消 息ID最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。
- _& T2 t7 Y% \% C; }" g5 t4 M        新消息必须写入放入索引 TXFQS[TFQPI] 引用的发送buffer中(放入索引 TXFQS[TFQPI] 只是队列头的数字)。添加请求会将放入索引循环增加到下一空闲发送buffer。如果发送队列已满(TXFQS[TFQF]=“1”),则放入索引无效,并且在至少有一个请求的消息已发出或挂起的发送请求已取消之前,不应继续向发送队列写入消息。
( c$ W: ?4 @: g9 A) C$ A9 ?& l        应用可使用寄存器 TXBRP来代替放入索引,并可将消息放入任何没有挂起传输请求的发送缓冲区中。7 {6 `1 R5 h6 x; J6 Y4 y) S' U+ l
        发送队列缓冲区会在消息 RAM 中分配四个 32 位字。因此下一可用(空闲)发送队列缓冲区 的起始地址是:
/ ?8 I) X2 \  ]2 n/ @- \6 N' m( l; Y
, i' O4 V' J0 p3 o发送队列放入索引 TXFQS[TFQPI] (0…31) 的值*4+发送buffer的起始地址。+ D  h5 Q0 @" ?% O, M. ?) ~! j

) [5 U$ k- M" }' Z+ U3 U- c3 R        因此可以知道专用发送buffer、发送FIFO、发送队列的区别是对放入其中的多条消息的发送顺序不同:8 V7 ]0 \# B* `

4 p9 y6 R  T/ Z0 D9 @8 A% ^# S' j; |        1)、发送buffer全部配置为专用发送buffer, |9 C' C: o5 i7 s( m5 D
1 p# r. [  U) s" Y! j5 O# l: E" q
        每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。2 x; O" Y3 G7 e/ C1 y9 _7 Q% |

9 r8 d, Y' V3 Y/ B2 [# `' X1 j, @5 w        2)、混合专用发送buffer和发送FIFO
3 a& _, m; T/ Z' t% J
2 r7 ?# p* U( }+ P) w2 p# g        在这种情况下,消息RAM中的发送buffer部分会被划分为一组专用发送buffer和一个发送FIFO。专用发送buffer的数量是通过 TXBC[NDTB] 配置的。分配给发送FIFO的发送buffer数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送buffer。: B0 k3 w8 v1 d1 Z( O
/ ]' u, T7 l- P1 Z2 x+ G! @! z
20191127162943182.png

: S9 t8 D' D! U, A
& l8 Z- s4 [: ]        发送优先次序:. W* H: H/ U2 E9 q( l
A、扫描专用发送缓冲区和时间最久的挂起发送FIFO缓冲区(TXFS[TFGI] 引用的缓冲区)
9 s( {* f6 o# XB、消息ID最小的缓冲区优先级最高,下次将发送该缓冲区的数据, x' u' d6 o% o

/ B: [: F; b8 H% s. S        3)、混合专用发送buffer和发送队列
9 @, M. _) W! E6 u+ K# m7 @6 t. N5 G- L7 `" `2 h2 u
        在这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队 列。专用发送缓冲区的数量是通过 TXBC[NDTB] 配置的。发送队列缓冲区的数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送缓冲区。
/ c$ J. @* }/ ]1 Y3 b; ~$ g0 k
4 |" s1 F5 \" [1 T( y7 G
20191127163202212.png

3 U: r, \$ U1 s  j3 K5 k8 E& {# U9 Q+ t% Z( I
        发送优先级设置:
9 s8 C; k, @+ O' N/ @& k7 U& DA、扫描所有激活了发送请求的发送缓冲区2 c6 E! u. k" k3 ~% q; g* A
B、消息 ID 最小的发送缓冲区优先级最高,下次将发送该缓冲区的数据6 V" d- h7 L" F

# P0 [! t& b+ c2 c5 U3 E        再来介绍一下发送事件FIFO,它并不是发送FIFO,不是用来存储发送消息的,而是用来存储发送消息的状态的。
0 \& q) {- W  r' ~  ]  l* g* M& z/ i8 `, F: {/ v
        FDCAN 在 CAN 总线上发送消息 后,消息 ID 和时间戳会存储在发送事件 FIFO 元素中。为了将发送事件关联到发送事件 FIFO 元素,已发送的发送缓冲区中的消息标志会被复制到发送事件 FIFO 元素中。
; i* [! [5 O2 L! A% j+ Q( `        发送事件 FIFO 最多可配置为 32 个元素。发送 FIFO 中介绍了发送事件 FIFO 元素。根据元素 大小 (TXESC) 的配置,会使用 2 到 16 个 32 位字 (Tn = 3 ..17) 来存储 CAN 消息数据字段。
& A* \2 {# N: o7 j& ?, N: B        发送事件 FIFO 的用途是将处理发送状态信息与处理发送消息分开,也就是让发送缓冲区仅 保存要发送的消息,而将发送状态单独存储在发送事件 FIFO 中。这样做有很大的优势,尤 其是在处理动态管理的发送队列时,发送缓冲区可在发送成功后立即用于新消息。覆盖发送缓冲区之前,不需要保存该发送缓冲区的发送状态信息。
3 L+ Y1 r- k. A0 O
. f; p! T, d* H- F7 |; x        为了防止发送事件FIFO溢出,发送事件FIFO仍然支持水印功能。  F3 y6 m) m, c+ A1 t! j# ^

: N7 |( _/ k6 `  k8 e$ q/ X: n1 Y        CAN发送消息的代码实现:
2 q# d$ }3 w. i5 Y, S) b0 |- P
- S3 P: e4 K* Z/ t$ g% ]4 P" L( K        发送流程与接收流程刚好相反,只需要把消息按照TXBC.TBSA格式构建好,然后写入发送buffer,写进去后设置FDCAN_TXBAR寄存器的指定位为1来请求传输即可。如HAL库函数HAL_FDCAN_AddMessageToTxFifoQ:+ v7 E7 u4 M9 h
: |$ X" o1 {# X, y
  1. PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> 16); //获取元素编号 % n4 r5 @( |" ]0 W5 t  Y: O5 E
  2. FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex); //复制消息到Tx buffer
    ; f8 c5 x" E& M! |& W
  3. hfdcan->Instance->TXBAR = (1 << PutIndex); //发出传输请求
复制代码
# S. ~; s8 [7 n- U6 D5 R; w" K: A
        发送buffer请求寄存器FDCAN_TXBAR,描述为:
0 ^1 i* B0 v6 {2 p& X; d3 f- }/ U' _( K

+ e" e' _* d- N6 ^$ ]/ k% \
2 W# W6 t5 q. v9 H/ @        此寄存器用来设置FDCAN的哪个发送buffer可以发送数据,FDCAN有32个发送buffer,当把消息复制到这些buffer中后,就需要设置此寄存器来标记此buffer可以发送。. v. V* G6 O1 b4 ]' R

6 @0 S, q- z0 y) b; d* d, Z: A  W$ h# I( }  n3 d# q* N1 w% k; o
( S8 h( }9 s$ s; h
五、初始化
4 ^: ^' J- c) n+ j5 u& w" }7 J0 T1 Q! c+ H+ ]" z+ S& s
        初始化可以直接使用HAL库,
% M3 ^3 ^/ _6 ^3 [2 c, I' [! N
4 a. R% a9 U9 _0 j- |, f  ^
  1. u8 FDCAN1_Mode_Init(void)
    1 {! u% D, M) t# ^+ b6 r% U
  2. {, x' T+ [3 K/ p. w9 @% I
  3.     FDCAN_FilterTypeDef FDCAN1_RXFilter;
    ) q/ z9 A7 \* o  }8 P- r7 @
  4. - j* X. d% [# T8 U. O0 ^5 @
  5.     HAL_FDCAN_DeInit(&FDCAN1_Handler);                              //先清除以前的设置
    7 a) h! `# a* O+ r. \
  6.     FDCAN1_Handler.Instance=FDCAN1;
    5 g1 W( N/ ~8 Z' f% G
  7.     FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC;            //传统模式' l8 P4 ~' d0 _- I
  8.     FDCAN1_Handler.Init.Mode=FDCAN_MODE_NORMAL;                     //正常模式" e/ c+ r* x, a3 ?- y
  9.     FDCAN1_Handler.Init.AutoRetransmission=DISABLE;                 //关闭自动重传
    / c: {" @# F4 b, g, K
  10.     FDCAN1_Handler.Init.TransmitPause=DISABLE;                      //关闭传输暂停           
    ) l* r; V- G; g* j4 u+ i
  11.     FDCAN1_Handler.Init.ProtocolException=DISABLE;                  //关闭协议异常处理
    / k( s" k2 Q1 p8 K0 Y* |
  12.         . ?6 M8 y1 E+ }/ W3 e3 e+ H4 X" W
  13.         //时钟为200M,baudrate=200M/(NominalTimeSeg1+NominalTimeSeg2+1)/NominalPrescaler,这里配置为1M4 o8 m) u! c( |+ g8 X
  14.     FDCAN1_Handler.Init.NominalPrescaler=10;                        //分频系数
    # S$ A( P3 C& V$ `* `0 t
  15.     FDCAN1_Handler.Init.NominalSyncJumpWidth=8;                     //重新同步跳跃宽度
    : C1 k" }! E( U: G4 |8 K
  16.     FDCAN1_Handler.Init.NominalTimeSeg1=11;                         //tsg1范围:2~256
    $ @9 G4 {* ~% ~5 _6 u3 W
  17.     FDCAN1_Handler.Init.NominalTimeSeg2=8;                          //tsg2范围:2~128$ {$ B7 p" v9 y' B$ L
  18.         4 f  r8 H4 W0 V0 g; T
  19.     FDCAN1_Handler.Init.MessageRAMOffset=0;                         //信息RAM偏移,10KB消息RAM共有2560字,故可以偏移0~2560
    ( J& k* K: q- U
  20.         //使用了多少个滤波器就要设置为多少; _/ h4 a1 G: |) E: ~2 o+ o! V
  21.     FDCAN1_Handler.Init.StdFiltersNbr=3;                            //标准帧滤波器个数,0~128
    - A+ N& Q3 x% m
  22.     FDCAN1_Handler.Init.ExtFiltersNbr=2;                            //扩展帧滤波器个数,0~64% O6 u; T7 C* s$ }# L* D( v7 v! q
  23.         
      _- W0 m/ C" n9 H, N' |! `( v
  24.         //接收FIFO0、FIFO1和buffer配置,此处没有使用FIFO1故个数设置为0
    # z1 l! D: ~5 \( X# w  ]
  25.     FDCAN1_Handler.Init.RxFifo0ElmtsNbr=64;                         //设置接收FIFO0元素个数,0-64
    9 r7 |' ?( a2 T! ~2 S
  26.     FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO0元素的数据域大小:8字节        
    / O# M/ p) l* M( x; V
  27.     FDCAN1_Handler.Init.RxFifo1ElmtsNbr=0;                          //设置接收FIFO1元素个数,0-64
    2 U. n* P; V( g* }; f, d7 y
  28.     FDCAN1_Handler.Init.RxFifo1ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO1元素的数据域大小:8字节               
    ' s. Q. b8 y1 `7 Q2 G
  29.     FDCAN1_Handler.Init.RxBuffersNbr=64;                            //接收buffer元素个数,0~643 l4 s" ~# P& Q
  30.         FDCAN1_Handler.Init.RxBufferSize=FDCAN_DATA_BYTES_8;            //接收buffer元素的数据域大小:8字节        , k7 v, _: b7 ], n
  31.         
    + b& a) A( H* k/ ]% Y
  32.         //没有使用发送事件FIFO功能,故TxEventsNbr设置为0。把发送buffer全部作为专用发送buffer使用,故TxFifoQueueElmtsNbr设为0.
    ( S9 B( P+ L2 ~, X9 k
  33.     FDCAN1_Handler.Init.TxEventsNbr=0;                              //发送事件FIFO元素个数,0~32$ q0 G2 }7 o! l4 m( @' f, E  c
  34.     FDCAN1_Handler.Init.TxBuffersNbr=32;                            //发送buffer元素个数,0~32. ^9 ^! c9 Z( l0 u8 o- f. P* k
  35.     FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=0;                      //发送Buffer被用作发送FIFO/队列的元素个数,0~32
    / I0 d+ L  |' g% d
  36.     FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION;    //发送FIFO模式选择,可以选择FIFO模式或队列模式
    - a2 b8 {% o" B5 z) Y2 O
  37.     FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8;              //发送元素的数据域大小:8字节4 O  J" \6 i9 u1 J# w
  38.         
    $ C" W! i8 I- Q& h1 Z6 p
  39.     if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1;          //初始化FDCAN+ w1 m8 o" m% t2 |# q) \
  40. $ R$ V4 s4 y: e
  41.     //配置RX滤波器,标准帧   
    8 Q0 ^& }( T# t+ @
  42.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    % X8 a. `! b) b# Q! M$ ?
  43.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    & L9 f+ P0 V- X' z
  44.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型2 p! I& c. ?4 K5 W8 R6 @9 }# i
  45.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    2 }7 `2 T, x' r' b
  46.     FDCAN1_RXFilter.FilterID1=0x112;                                //11位ID6 [- e. T& I/ Z1 }
  47.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码+ }4 ]! a  O" @8 d0 `
  48.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    8 `3 Z+ A; T& v, D! c4 H
  49. : \0 q& |* d( P: o! o+ t
  50.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID+ g) A4 h: k) m  d0 P+ _
  51.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                  
    ! r7 n( N; i; {: q$ S4 s! P8 B) s
  52.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型6 T' `+ U$ T& `" h0 m- S3 c
  53.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    ! A" o9 n5 a/ E% O
  54.     FDCAN1_RXFilter.FilterID1=0x113;                                //11位ID
    , F) W+ _/ J: b5 P3 l5 v
  55.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码* D3 i  |  g, G1 T4 r' T
  56.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化0 U9 q, V; F/ v6 I  q+ h, G4 n
  57.         , \2 D% H1 I+ ~
  58.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID+ x: Z5 b* ^3 U# }1 {/ ~
  59.     FDCAN1_RXFilter.FilterIndex=2;                                  //滤波器索引                   6 \$ Y4 P' p- W  ^7 c" p* O) r
  60.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    ( D; ^! c$ x& o7 ~3 u# O( z1 H
  61.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  ! w5 |! @6 \5 b3 q$ P  x
  62.     FDCAN1_RXFilter.FilterID1=0x114;                                //11位ID/ R2 D8 f# b& M+ D) ?' a3 Y8 F0 r
  63.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码% I- K  E$ V3 [# S5 j$ M
  64.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    6 C- w6 x* o" C3 S. Y$ k2 t4 @
  65.         
    % o# o  e" F; h, Y5 a7 k" s
  66.         //配置RX滤波器,扩展帧。标准帧和扩展帧的滤波器索引是分开的   
    . z" t+ S' g  n9 Y1 [
  67.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID! Z1 [) ^: y/ D: @) C
  68.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    0 L7 O5 Y! O2 u8 W# Z# g
  69.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型3 T8 r+ M$ L. f+ y
  70.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  3 P, h  Z6 l! |0 r$ ?6 p8 x
  71.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(2 << 12);                  //32位ID
    6 W3 }$ C( s: S4 h5 f+ q
  72.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码
    9 F) D, [6 Q. Q
  73.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    " w# @9 T$ N5 h& u* V

  74. # |0 Y$ m# T/ L
  75.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
    ! z7 T4 o% k! n
  76.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                  
    3 k9 i7 u& [: ^% Z- z
  77.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    & [0 w3 O" }# o
  78.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  % ?. g1 S8 p# }* D3 @
  79.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(3 << 12);                  //32位ID
    0 T8 S/ c2 X6 W- c4 a8 q) k8 U" a9 j
  80.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码
      b: n# P' \. _4 F3 U; r. q+ G
  81.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;    //滤波器初始化* v  G) O  ~, y3 I& J
  82.         * S1 l+ I  p4 O: a. z: U
  83.         //滤除的消息直接丢弃1 u$ `' J* a9 \4 q( [+ p8 z
  84.         HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);  //设置被滤除掉的消息的处理方式$ K$ @7 t0 g0 J: C
  85.         - `. @* K, W) S. K! C+ G& A/ R+ M1 @
  86.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);   //使能新消息接收中断
    ( H! n' o1 x  p! x
  87.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_TX_COMPLETE,0xffffffff);   //使能消息发送中断,0xffffffff表示所有的发送buffer都触发中断        
    8 e; m+ W& G9 o% c
  88.         $ V1 i2 g  Q' a2 O0 T( L
  89.     HAL_FDCAN_Start(&FDCAN1_Handler);                               //开启FDCAN5 X! E2 `, [" p* b( ~
  90.     return 0;$ c8 B5 w' U2 |' `7 p
  91. }
复制代码
" M: t; c; ]% ]" e5 u& F

% K- s4 E( J) ^- k6 Q六、CAN发送示例(来自正点原子)5 v0 U! q% U; g9 O2 Y9 E+ e$ A
2 U3 i2 f: K! ?4 K( [. Q& G: I
  1. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)        2 `  a, }2 m) Q
  2. //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8                                     ! w* ^5 h' s/ s# a7 P
  3. //msg:数据指针,最大为8个字节.9 m% u! z* K0 p! ~! n
  4. //返回值:0,成功;
    . V. p8 {) k% y  e* Q" k; A. ]
  5. //                 其他,失败;
    + A  \# x3 D! I8 z1 i; l4 G9 ~- F
  6. u8 FDCAN1_Send_Msg(u8* msg,u32 len)- t3 r  i6 m9 O' h+ c
  7. {        
    4 y: X! T! d) H% P1 O4 Q
  8.     FDCAN1_TxHeader.Identifier=0x12;                           //32位ID4 G6 J+ n4 m; ]# {
  9.     FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID
    . M6 ?/ c0 k. o9 I
  10.     FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧1 K1 {7 }# ^  ]. H
  11.     FDCAN1_TxHeader.DataLength=len;                            //数据长度
      a% |' X; |* `; v; P# o
  12.     FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;            # X( @! \# f7 m5 g( V- G/ k" o
  13.     FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换
      q! k" w% L2 ?% E2 f8 ?
  14.     FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式0 G& q, I- h; |! z* l* v9 \2 H
  15.     FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    % H& `. Y5 l' A! V1 t  ^
  16.     FDCAN1_TxHeader.MessageMarker=0;                           
    ( \! w5 {; k- R& T" J- \

  17. ( u8 }1 d) k7 o4 @* e$ z
  18.     if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//发送1 U# C5 |4 Y0 `- h
  19.     return 0;        
    , ?& k" S0 }  ?- I4 m
  20. }
复制代码
  t$ I/ T' w4 D6 N- R3 _
七、CAN接收示例(来自正点原子,因为滤波器被关联到FIFO0,因此消息只会放入到FIFO0)
: ^/ n6 j4 D: S4 N1 A) }
# C/ ~+ n; X9 J$ }
  1. //can口接收数据查询1 s2 k8 q2 h! A! j/ d8 P
  2. //buf:数据缓存区;         
    5 s/ J  C7 T- o' \
  3. //返回值:0,无数据被收到;
    - z. R* C3 ], r6 o  Z
  4. //                 其他,接收的数据长度;1 ]! [) A" g+ m. W& k- [
  5. u8 FDCAN1_Receive_Msg(u8 *buf)
    * @2 D# ^9 x1 x& z" y5 ]; b3 [
  6. {        
    ! s0 @3 z9 p1 K) ]+ e2 Y
  7.     if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收数据' W# `- G( U8 D- l) P( R/ @
  8.         return FDCAN1_RxHeader.DataLength>>16;        0 w0 I; t1 x& \: c
  9. }
复制代码

( K% Z0 n% ~; O3 `1 i, T参考:《正点原子》  STM32H7开发指南-HAL库版本_V1.0 (文档中有很多错误的地方,笔者被误导了好久,阅读的时候还是要以H7官方手册为准)
6 x. v2 |5 s# {5 ]
3 Q# K  ~  ?" }: K# {8 Z+ W- G1 n% Y; r* {7 I
收藏 评论0 发布时间:2021-12-22 14:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版