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

【经验分享】STM32H7的FDCAN

[复制链接]
STMCU小助手 发布时间:2021-12-22 14:00
一、介绍
, l8 i$ a. R; \  O4 ^/ B$ M* k/ o1 t5 o9 M! o( m7 Z
        FDCAN(Flexible Data-Rate CAN)是CAN的升级版。特点包括:
$ H  ^6 ]# c4 ~
( U1 {8 N$ T$ K9 T* |4 R       1、每帧数据段最大长度由8字节上升到64字节。
/ i/ d% f  Z& y: B: U
- e0 O1 o  w4 _+ I. R/ F        2、速度由1Mbps上升到5Mbps,甚至还可以更高。在一个数据帧中仲裁段(ID和ACK)的速率和CAN一样最高1Mbps,这样可以保证总线的健壮可靠,但是数据段可以5Mbps甚至更高,一个数据帧中使用不同的波特率,这就是FD(Flexible Data-Rate)的由来。7 D% p6 ~. a4 h0 f
9 ?1 g- |7 ?3 I& u% B" C: H6 Z
        3、向下兼容CAN。: T7 y  g" {- M9 R, x6 y7 c6 O

+ N) k3 B/ V* X# \8 |9 R7 }  t        H7的FDCAN包含2个可配置接收FIFO。多达64个专用接收buffer,多达32个专用发送buffer。可配置发送FIFO/队列,可配置发送事件FIFO。
1 R/ C- O- z' q! Q. I) `+ k, k) L8 m
- a7 x+ ^, z0 d, S5 ]# M二、结构! Y$ a5 v+ t% i/ Q$ V' s) l/ e! U: Z

: B- ?  G% f, \, F5 G' C" f- }/ l; _& s        先看结构框图:
* u$ ^' a9 D/ ?- Q2 m1 p- h4 A( `" y4 K7 m
20191121162856859.png

% I6 w6 s) F6 k; I$ W; V" ?& V: @, y3 Y6 d# h0 Q
1、两条中断线:fdcan_intr0_it和fdcan_intr1_it。可以通过FDCAN_ILE寄存器的 EINT0和 EINT1这两个位来使能或者关闭。# A1 b. A, N9 [' |( S# L2 ]  [: J
$ A+ _* Q% z+ M% g: [  b  ]
20191127102816991.png
6 H. Q6 a* K, s& L1 ]9 o% L- H* X
  ^  T! i8 D6 g: Z8 x
        可以通过FDCAN_ILS寄存器来选择FDCAN的中断是在fdcan_intr0_it上触发,还是在fdcan_intr1_it上触发,默认所有中断都在fdcan_intr0_it上触发,没有特殊的要求,只需要用一条中断线就可以了。
/ ^! g% ~3 ~7 E5 {; D, l
9 T! G4 S8 T( _' o2、TX Handler:负责将消息RAM中的数据发送到CAN内核,最多可配置32个发送buffer进行发送。发送buffer可用作专用发送buffer、发送FIFO(发送队列的组成部分)或二者的组合。发送事件FIFO会将发送时间戳与相应的消息ID存储在一起,另外还支持取消发送。
6 z$ f- j7 T0 L2 v  P" N( p  I# u: c, w
3、RX Handler:负责将CAN内核的数据传输到消息RAM,支持两个接收FIFO(每个FIFO的大小均可配置)以及最多64个专用接收buffer(用于存储所有通过验收过滤的消息)。专用接收buffer仅用于存储具有特定标识符的消息,与接收FIFO有所不同。每条消息均与其接收时间戳存储在一起。8 H& k! ?( A- a. H  Y) l

2 j, {# D% G3 F5 s4、CAN core:CAN内核,读RX引脚数据处理后给RX Handler,接收TX Handler处理后控制TX引脚。. @+ j9 l# u7 Y# [3 W, u
. }) U/ H* j- i) S! B  N% t
5、Message RAM interface:消息RAM接口,外面连接着消息RAM。消息RAM是FDCAN的核心,本质是一段最大10KB的内存,把这段内存分成不同的区域,每个区域的作用不同,可以实现:过滤器、接收FIFO、接收buffer、发送事件FIFO、发送buffer。内存分配如下:7 w( R% }* K$ U2 Q
! q' ?" S& |: `- a' Y8 I
20191121164211703.png

* S8 W9 ?# ]1 }9 d% l2 h: ]9 L/ b  i* D* k3 o5 }
        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字。& G4 R4 W/ f, I* E- U0 }! a
+ j/ Y8 j2 u" w# D; [( k: M5 w
        1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,最多可以有128个元素。% G% S! {' d3 S/ l& B
- {& q) Y% C  Z! Q1 `
        2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,最多可以有64个元素。(F1配置寄存器来设置过滤ID,H7直接划了个内存区来设置过滤ID)8 ~6 ?9 P6 m9 q+ ?+ A# |0 Q
$ J9 @/ K9 g: V0 o% Y
        3)、RXF0C.F0SA:接收FIFO0,最多可以有64个元素,可以接收64条消息。
4 m, D( v1 m$ P8 n4 L5 w6 X# j( g8 I
        4)、RXF1C.F1SA:接收FIFO1,最多可以有64个元素,可以接收64条消息。
% ]1 _7 Y  F/ N# N1 Z0 A
0 n" ?# m" A1 O4 s, g2 S1 o" T8 `        5)、RXBC.RBSA:接收buffer,最多可以有64个元素。
4 r+ o5 ]* u+ l; _3 e
' c! B$ v1 ?( ]) f1 {; L2 ?  t: \        6)、TXEFC.EFSA:发送事件FIFO,最多可以有32个元素。(不是发送FIFO)
" o+ m4 T/ Q' D6 H
+ _0 X' ?8 X% D, @1 [% F7 q        7)、TXBC.TBSA:发送buffer,最多可以有32个元素。
0 m; M; n, n4 @/ U
6 w' u. w( U# L" h        8)、TMC.TMSA:触发存储器,最多可以有64个元素。
7 y6 l5 P' h. o' l' R0 `$ a6 L7 G( ?
《注:这8个区域的元素个数和元素大小都是可以配置的,但是这8个区域的地址又是连续的。因此在初始化的时候,会根据每个区域的元素个数和大小来计算下一个区域的起始地址,并保存到相应的寄存器中》2 i' y4 R% K' {. ?. g8 r0 a3 [
8 N; Y+ W" k1 T
        下面来详细介绍这几个功能区域:
+ D1 q, t; S$ i( h$ q3 o  ~
! U# @  _% ~* [! }0 I9 @+ X$ n1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,有128个元素,每个元素占一个字,定义为:
1 J- _- k6 ~& W( Q" U( w& x  Z# Y# s; ~; L
20191121170625565.png

. {! @; w* c4 [
7 ^- t. z5 ~3 P# wSFT[1:0](bit31:30):这两位用来表示过滤类型,一共有四种:" p+ r* g' ~# D3 h" E7 u
    00:范围过滤,过滤到SFID1到SFID2中的所有信息。
' M2 N( w% U# q* E8 q    01:双过滤,过滤到SFID1和SFID2中的信息。) B4 Q; X0 ^, `8 V
    10:传统位过滤,SFID1 是过滤值,SFID2 是掩码。9 u; I" t+ k/ ?
    11:禁止过滤器元素3 K. V# [1 U$ J9 t2 \8 _
SFEC[2:0](bit29:27):标准过滤配置
$ C5 ?) `. H2 T! z* F4 v7 `7 ~    000:禁止过滤器元素
# Y5 l2 i. L  W  x: T    001:当过滤匹配以后存储在Rx FIFO0中。
" ^0 V6 R$ V" K    010:当过滤匹配以后存储在Rx FIFO1中。
+ L5 O& @  ?( V& D3 ?    011:当过滤匹配以后丢弃。
5 _: C4 a5 U  K: \- v    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。( [, n4 J" D* M1 _
    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。' m; ]$ k/ i1 U
    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。
' I" O( S3 t1 ^# L6 T$ I    111:存储到Rx buffer中或者作为debug消息,FDCAN SFT[1:0]忽略。" I5 L0 y5 R- }( S, S) _. M0 j
SFID1[10:0](bit26:16):标准过滤ID1,第一个要过滤的ID。- S" E: `0 |& B, o/ H  m
SFID2[15:10](bit15:10):标准过滤ID2,此位根据SFEC的配置不同而不同,当SFEC=001~110的时候此位域表示标准过滤ID。当SFEC=111的时候此位域表示Rx buffer或者debug消息。9 h: w/ }" z& I# B
3 Q2 @9 w) |- C! K. @2 J7 z! U. j2 ~2 {
SFID2[10:9](bit10:9):设置接收到的消息是存放在Rxbuffer中还是处理为debug消息的消息A、B或C。
4 J( \) q  Y/ m- j) x; j8 n7 S    00:将消息存储在Rx Buffer中。- G0 T( U$ B1 Y8 b
% W: x$ d3 G# N' d
    01:debug消息A。   
+ m! Y" L6 h4 V. W& F: b6 r
$ c3 N- @; [7 c' A2 a0 z( {% k! I$ A    10:debug消息B。) ~0 J4 [7 e6 G% V4 o. Q
( r. e4 G+ K2 j8 q( t3 R
    11:debug消息C。
9 B& R% x! W, |! Z  J1 C. E/ O, |# ]* Z2 g# F# J
SFID2[8:6](bit8:6):确定是否将滤波器事件引脚作为外部接口。
& U! Y! R% T! ~$ I$ a% J1 l0 T: I, l
SFID2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer 的开始地址RXBC.RBSA的偏移。
: M% \& p  C0 K6 B: S( a* G+ n1 |6 T
2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,有64个元素,每个元素占2个字,定义为:6 {4 Y4 u# F7 v0 T2 i7 G

% M9 d( F! B. T
20191121171836710.png

9 J+ B. w& d0 B; S- B7 Y7 X+ s) v8 I9 p2 d" r
F0 EFEC[2:0](bit31:29):扩展过滤配置
( h& V- @9 K! z$ Q: b    000:禁止过滤器元素
% l7 f9 T5 _2 h    001:当过滤匹配以后存储在Rx FIFO0中。
1 o- w$ i" _; e1 G, E    010:当过滤匹配以后存储在Rx FIFO1中
) `7 B$ W! I1 |9 \    011:当过滤匹配以后丢弃。
' Y- l0 f1 S) }* R* N    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。9 c2 n2 e' Y! t1 |. g  L/ j/ k
    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。
+ m  E) _! I% M    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。! n& N1 C5 y# v0 V; [1 k  g! L( Z
    111:存储到Rx buffer中,EFT[1:0]忽略。  X6 X& T3 R3 A& l: P, Y* [1 y
F0 EFID1[28:0](bit28:0):扩展过滤ID1。
- ]& G! q8 ?5 n5 H8 f7 bF1 EFTI[1:0](bit31:30):扩展过滤类型$ ^; p) P+ D# _
    00:范围过滤,过滤到EF1ID到EF2ID中的所有信息。
( i1 k- y9 |9 ]    01:双过滤,过滤到EF1ID和EF2ID中的信息。7 P& v# b/ Z/ l) L9 P
    10:传统位过滤,EF1ID 是过滤值,EF2ID 是掩码。
0 k( O' {' K. d4 O8 ]8 G, l, l6 u  S    11:范围过滤,过滤到ED1ID到ED2ID中的所有信息,没有使用FDCAN XIDAM的掩码5 g- B- F% q  i1 G* C/ ]
F1 EFID2[10:9](bit10:9):设置接收到的消息是存放在Rx buffer中还是处理为debug消息的消息A、B或C。
7 M7 N# w7 j% L. B5 }    00将消息存储在Rx Buffer中。- w2 e  F: _* T+ ^+ O* ^& N
    01:debug消息A。
$ j, v8 Z7 v& l# ]; q2 i; j    10:debug消息B。' u7 B: A( ~  I6 ^* S; M9 W' Q
    11:debug消息C.2 n3 s1 R  G7 j" P8 k
F1 EFD2[8:6]bit8:6):确定是否将滤波器事件引脚作为外部接口。( ?- Q% a" ?, r9 G8 K+ R
F1EDIF2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer的开始地址RXBC.RBSA的偏移。) S7 T( J' e& S* W
' @& G# R$ T& R; X. B
3)、RXF0C.F0SA、RXF1C.F1SA和 RXBC.RBSA分别为Rx FIFO0、Rx FIFO1、Rx buffer,它们都有64个元素,元素的大小根据数据长度不同而不同,范围为4-18字,它们的位定义相同:5 K6 Y) g- |; u' H5 `1 y0 d
! E9 k8 u. @  z3 b
20191121172451477.png

# n5 j( q/ j9 ]6 H/ C! E( b; g$ x# O( {' Q9 e
R0 ESI(bit31):错误状态标志
& r4 j8 [! w2 }5 g    0:传输节点显性错误。0 P, V$ ?) L$ R+ M
    1:传输节点隐形错误2 s7 Q% k% N8 e% t, f
R0 XTD(bit30):标记是标准ID还是扩展ID
. C( g" @5 s; w$ g8 x* p  t! u    0:11位标准ID
! h  L4 }% [& I4 \4 {# W
4 j3 i* k. r% h' D: @. V1 m    1:29位扩展ID- C% C: R) }& E: _5 z1 b

9 H+ K) Q$ |; W9 f4 d# E& H5 xR0 RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。6 o* \6 {( B# M$ @; u
    0:接收到的帧是数据帧# m, D% x( r5 m
9 q' l. e/ [" J# u% J; E( m4 `
    1:接收到的帧是遥控帧
+ k: D. Q& z' v8 Y+ l7 [5 BR0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。2 R$ j. c$ R* g3 b0 |1 W
R1 ANMF(bit31):
; D; x% ^4 \  ]7 l9 B) z- Q* `8 T7 \; ]' u% o1 b2 B
    0:接收到的帧和FIDX中的过滤帧匹配
! ?3 |  G* _& g" u: A' ]( E) k9 T/ l: d' D4 E5 R3 M
    1:接收到的帧和Rx滤波器中的任何元素都不匹配
# V4 X$ S& T  o3 xR1 FIDX[6:0]bit30:24):过滤器索引,0~127,表示和Rx滤波器中的哪个元素匹配。6 C" h. q$ \- I( K- n
R1 FDF(bit21):帧格式+ X) S3 X# ^0 Z3 ?
    0:标准帧格式
" i7 V) r$ D* C- m9 v$ P* b    1:FDCAN帧格式。" O+ U$ \  T1 Y& L5 O! |
R1 BRS(bit20):比特率切换
6 f2 w$ w( C* A9 \  [: m    0:接收到的帧没有比特率切换
* G6 ]6 v2 ]9 h4 c% R6 I  T2 h" ~7 J1 T8 A( [0 @' L) G
    1:接收到的帧带有比特率切换
% f9 m6 f& m4 ]* y" y6 TR1 DLC[3:0](bit):数据长度。
7 ~1 I" x9 ]9 |    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
0 d6 F; x2 p- F    9-15:如果是传统CAN,接收帧长度为8字节。4 z% j* F0 t3 o! t* e6 v" F
    9-15:如果是 CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64 字节。
% K% T, |; h, b* M9 ]$ qR1 RXTS[15:0](bit15:0):接收时间戳。- y. B; e8 x( ?9 M7 F
R2-Rn:接收到的数据。
( X2 p6 ?! G  ]5 b0 }
: l" F# u& `3 H  ~! q4)、TXEFC.EFSA:发送事件FIFO,有32个元素,每个元素两个字。% g9 L7 U' [  e( U! ?

$ n0 M. Q# k+ z* ]/ M4 G/ v' e! c
20191121174147402.png
. Y* D# i) N0 }- `+ I; f
3 @0 I. y; y9 y% f. f
E0 ESI (bit31): 错误状态标志$ o: M; j# F; Z7 R1 ^
, s" y1 H) h1 l- N  I; t
    0:传输节点显性错误0 ^6 G+ z" }" P
    1:传输节点隐形错误。4 I- Q' G4 N% y: j6 V+ U( h7 X
E0 XTD(bit30):标记是标准D还是扩展ID
  k6 C* A) T& ]% E. F2 R    0:11位标准ID.$ ~5 x& z. o" g. {% m; u1 S
    1:29位扩展ID! x" x+ c* A2 ~+ n# {8 U5 _

% Y" ~5 _( ^$ M* v8 U: kE0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。6 ?# `8 i3 w$ |& P- o0 x- L
    0:发送的帧是数据帧: K+ x* @% k5 a
    1:发送到的帧是遥控帧5 O6 T; z+ F; I$ ]
E0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11 位ID还是29位ID。" }, G0 E8 m4 ]% j/ {! h! a! ^
E1 MM[7:0](bit31:24):消息掩码,从Tx buffer拷贝到Tx Event FIFO中。
) w1 {% e" N% }( K2 d( n0 Q1 AE1 EFC(bit23:22):事件类型5 S( _  Z- `& w9 i; s3 N9 m( p
    00:保留。' L2 ^( T& R5 }! O) q; {( z, P
    01:发送事件。
, B* j" H9 a* _& Z( s, p0 v( p    10:发送取消。, Q6 a# f* H" k1 w! K
    11 :保留。
8 [3 \- w; a  l) u# hE1 EDL(bit21):扩展数据长度8 {  I* C5 r/ s3 ?
    0:标准帧格式
2 R9 G* @$ Z- E; O; [; Z/ S    1:FDCAN帧格式。
9 s$ m7 k5 ~6 {4 N# KE1 BRS(bit20):比特率切换: n: B' W0 H# }( }, l
    0:发送的帧没有比特率切换& K1 t% l* d8 F  x9 e& M- M
3 W* o; z7 k: Z( [/ U- k1 t7 b, O0 D. x
    1:发送的帧带有比特率切换1 a* {7 d* O: d3 Y2 u
E1 DLC[19:16](bit):数据长度。
( x0 L0 A) T8 }" Y    0-8:传统CAN+CANFD,长度为0~8字节。$ X, p" I- t. Y( Z, ~
    9-15:长度为8字节。
4 s+ U  l' m3 I! ~' dE1 TXTS[15:0]bit15:0):时间戳。) @/ G5 ^  `9 k

/ ^% R3 {$ h! b% M5)、TXBC.TBSA:发送buffer,有32个元素。# e1 s- Y$ j& B4 f- s- H
" M5 k9 `5 g2 e, z7 ]
20191121175121493.png
) @- K. J/ |' p2 f; R7 @7 d" f, M
% L0 |$ M% d/ l8 @- v: H
T0 ESI(bit31):错误状态标志6 y) ~, K9 R+ k
    0:CANFD帧中取决于被动错误标志。
0 P" I# X: T  V' \  o; p; o    1:CANFD帧中隐形错误。: A- }! F1 O+ p2 h: O# U
T0 XTD(bit30):标记是标准ID还是扩展ID& }: O( j  F: N  ]
    0:11位标准ID
( w8 J9 F. R6 x1 m: E  N* }7 H1 t- p' G/ F' c& d
    1:29位扩展ID
+ l+ U* l$ ~6 A* o) g6 \6 y7 f5 d
) E/ k, @2 T( B/ f! m% oT0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
3 |6 u2 i' J# u    0:发送的帧是数据帧
+ Z: D4 `; r, b  l" A0 W4 ]3 |2 z    1:发送到的帧是遥控帧/ E/ {. L  `7 t, H! ^: K6 P
T0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。
9 {1 b* [- o3 D" p# {. \T1 MM[7:0](bit31:24):消息掩码,配置Tx buffer的时候由CPU写入。/ V( x6 V* w- W! r5 D
T1 EFC(bit23):事件FIFO控制
) f' @% H0 \! |5 S" ]& _3 C; r    0:不存储发送事件。3 l! C( K( J  d% [& \* \3 C: T3 B
    1:存储发送事件。# g1 H  V8 [* a: t
T1 FDF(bit1):帧格式8 c- P+ w, u1 ?; H! C
    0:标准帧格式( o  N7 x7 R1 h* Z
    1:FDCAN帧格式。( l+ g; y- N% j, S  S! c5 U1 M4 z8 y
T1 BRS(bit20):比特率切换: S7 W: Y& w4 R" H- r) a* \
    0:发送的帧没有比特率切换
5 c, _" b, y" c1 S- y! N6 O
8 {; m6 L3 e7 H5 ]1 e( p1 ^    1:发送的帧带有比特率切换
/ Y- d' p3 `/ M7 U6 p, K* ~T1 DLC[19:16](bit):数据长度。
3 ~2 s8 a8 x2 M2 H$ o2 c0 C# `    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。+ D0 I  J! ?$ k0 |; h
    9-15:传统CAN,接收帧长度为8字节。# [# b( g0 y6 \* F" e: x
    9-15:CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64字节。, f) H$ o+ M# c2 x, b# y
T2-Tn:发送的数据。- ]. l7 y9 i0 }6 [+ t; V1 A, R5 z& J
: j9 j7 {, y4 X- `; {% @& @0 H8 o+ p
三、过滤器设置
: A1 @) a7 P* U4 `4 K7 M2 B8 D0 X0 {& l' `# |# T. q
        标准帧和扩展帧过滤器的设置分别往SIDFC.FLSSA和 XIDFC.FLESA区域写数据即可,下面以标准帧为例,标准帧过滤器共有3种过滤模式:+ Q1 u, {! @0 Y, }* b
$ j! O8 L. B5 e9 i8 {
        1、指定范围过滤
3 M$ C" F( m. M% I/ u/ n        通过SIDFC.FLSSA的SFID1和SFID2来设置需要过滤的ID范围,其中SFID2的值要大于SFID1,这样只有ID值在SFID1~SFID2之内的消息才能被接收到。比如我们现在要设置只接收ID在0X123~0X321范围内的消息,使用标准滤波器n,SIDFC.FLSSAn(n=0~128)的各个位设置如下:
) z& k& h" g: K" ]( N
8 d/ }* I5 ~* Q8 x, p7 j# C
  1. SIDFC.FLSSAn.SFT=0        //范围滤波
    8 c% u* _. E  S& y
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到RxFIFO中
    7 K  K1 m( n2 b8 V2 U0 `* l0 I
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    2 k* ?# Z/ i0 x$ F! w
  4. SDIFC.FLSSAn.SFID2=0X321  //ID2
复制代码
! v$ d% `- t- ^' z
        2、指定ID过滤7 e+ Z( P. Q: |9 u( e8 X

& F* G0 h3 {; q( U9 d- \! |" |        我们也可以设置只接收指定的一个或者两个ID的消息,如果只接收指定的一个ID消息的话SFID1=SFID2。比如我们要设置只接收ID为0X123的消息,设置如下:, a' E) v; x3 p5 b  |  o! L
; J' g& Y9 z3 y, u# H$ ^
  1. SIDFC.FLSSAn.SFT=1        //指定D过滤* l: ]' A5 j# l1 a% Z1 z6 ?1 h" P
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到Rx FIFO中- b* A1 u) M/ o  g- H# {
  3. SDIFC.FLSSAn.SFID1=0x123  //ID11 X5 a0 C+ p4 z5 j
  4. SDIFC.FLSSAn.SFID2=0X123  //ID2
复制代码
# s9 T# Z& q; f6 j1 j
        3、传统的位过滤: r* |! Q+ H9 Q; p7 D
        第3种过滤模式就是以前STM32的CAN上存在的位过滤模式,在屏蔽位模式下,过滤消息D和过滤掩码一起工作决定接收哪些消息,其中SFID1为过滤的消息ID,SFID2 为过滤掩码。举个简单的例子,我们设置过滤器SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:
9 e% R& t  |# z: O, M
  O1 H, f& k9 S. H/ V* d; ~
  1. SIDFC.FLSSAn.SFT=2          //传统位过滤) k- |% U' `5 f% t0 \
  2. SDIFC.FLSSAn.SFEC=1         //如果滤波匹配成功的话将消息保存到Rx FIFO中3 i/ i, r0 g' }9 J3 e- }" Y/ C
  3. SDIFC.FL SSAn.SFID1=0xFF00  //ID1" o* i! a* L  Y) }# u9 k; p
  4. SDIFC.FLSSAn.SFID2=0xF00    //掩码
复制代码
* x3 K4 J2 I2 G- F: D
        其中SFID1是我们期望接收到的消息ID,我们希望最好接收到ID=0xFF00的消息。SFID2的0xF000规定了我们必须关心的ID,也就是接收到的消息ID其位[15:12]必须和SFID1中的位[15:12]完全一样,其他的位不关心。也即是说接收到的消息ID必须是0XxFxx这样的才算正确(x表示不关心)。7 b: ^; |, r& P8 U9 k$ q2 p- f( S( i( ]

$ `% x' t. N1 R3 f; @& E! d8 {四、CAN的收发过程
, t/ F7 q0 r5 u" z# [, g" {( s! T/ }$ @: z/ Y# i; }
        1、CAN接收过程4 g) b2 ?. I% Q+ q

6 \: y/ E2 P- G1 `4 H. b; R3 Y3 s        CAN接收到消息后会进行过滤,过滤时会从SIDFC.FLSSA或XIDFC.FLESA区域的第0个元素开始匹配,直至符合过滤器中的某个元素的规则,则过滤完成,过滤完成的消息会按照过滤器元素的配置进行处理。比如过滤器元素的SFEC/EFEC位决定过滤后的消息是放入接收FIFO0、接收FIFO1还是专用的接收buffer中。
# U4 N( d& X+ C7 E7 U3 i! g
6 k1 n' l! b8 [, _7 h" O; J4 _        接收FIFO 0 和接收FIFO 1 最多可分别保存64个元素。两个接收FIFO的配置是通过寄存器RXF0C和RXF1C完成的。. C$ _& R$ i; V0 g/ I+ Z1 a

5 q9 K) f6 N1 p7 u+ s
20191127114550965.png
5 s6 ?3 |% n6 B% i4 g. Z$ A! J' X

) w2 Z  H3 A, `' }        当IR寄存器的RFnF(n为0或1,代表接收FIFO0或接收FIFO1)指示接收FIFO已满条件时,在至少已读取一条消息且接收FIFO 获取索引递增之前,不会继续向相应的接收 FIFO 写入消息。如果在相应的接收 FIFO 已满时收到消息, 此消息会被丢弃,中断标志IR[RFnL]会置 1。也就是说,接收FIFO满了后会触发RFnF中断,如果继续接收,消息会被丢弃,并触发RFnL中断。5 l7 y0 _+ N* P4 T6 \$ S. V3 P
' B8 E! x# e: O( s% ?7 O
1 T- e+ q$ A7 k  E' l" L3 z$ f' j! J
20191127111235302.png

! a8 ?: O% I9 E0 a5 j1 Y1 v( l, E7 w
        为了避免接收FIFO溢出,可使用接收FIFO水印。当接收FIFO填充级别达到由RXFnC[FnWM] 配置的接收FIFO水印时,中断标志IR[RFnW]会置 1。比如接收FIFO0大小配置为64,水印值配置为60,当接收了60条消息时会触发水印中断,提前进行处理,这样就避免了FIFO溢出。! O7 K/ r) W8 D2 I7 i* e0 b( K; i
        读取消息就是直接从RXF0C.F0SAn或RXF1C.F1SAn(n为索引号 0~64)中读,消息的组成结构在上面已经说过了,比如HAL库HAL_FDCAN_GetRxMessage函数读数据过程(假定从FIFO0中读):, F/ ?- W* a% ]# v; m

' Y$ K& f* S( |& h  P4 _* X9 c
  1. /* Calculate Rx FIFO 0 element address */
    8 ], K- s1 ^5 t! l4 v
  2. GetIndex = ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8);3 f8 C1 N% `+ K: b% N( a9 E. |, B
  3. RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4));
复制代码
+ d& M' S( J2 |
1)、((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8):作用是获得FIFO0状态寄存器FDCAN_RXF0S的bit[13:8],读这里可以知道接收到的数据保存在FIFO0中的第几个元素中,GetIndex的范围是0-63,刚好对应64个元素。当FIFO接收到一条消息,GetIndex会加一,当从FIFO中取出一条消息,GetIndex会减一。
/ l. I8 E3 s) m  k) j2 ~- |5 A9 r* G! i2 j& R
2019112119095892.png
; O0 @6 f- v  O9 L. g
. {& x4 [/ `6 H1 H5 t3 E
2)、hfdcan->msgRam.RxFIFO0SA:是RXF0C.F0SA区域的开始地址。: M$ h* u* j( n( c

& b0 S' A' `, M0 f  }2 O  L3)、hfdcan->Init.RxFifo0ElmtSize:是接收FIFO0的元素大小,根据数据长度不同而不同5 Y, n, V" ~1 Y6 M
2 ]* I" ]# Q5 B( K2 P% ~

. d9 k. h. i9 B# E& v7 L: M$ H. n9 [9 q: R2 v! U
如果消息长度是8个字节,那么算上固定的R0、R1,元素大小就是4个字。
# {% e  U) g1 M% E$ z  S1 X" a$ M
如果消息长度是64个字节,那么元素大小就是64/4+2=18个字。8 c8 J6 t* I5 |. P4 R

' a+ N# _4 h+ U+ a5 E: C5 t, e        计算出了元素在FIFO0中的地址,直接按数据结构读数据就可以了:
$ s9 S0 J9 e1 v
# v9 d7 F$ f, x: |8 ?/ R
  1. pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;
    % \5 Z2 V4 K. g2 N; f7 z7 L
  2. pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);  z  M! i2 Y0 o! l; M1 D
  3. pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);4 d5 T) @& D2 J9 d! l5 f
  4. pRxHeader->ErrorStateIndicator = (*RxAddress++ & FDCAN_ELEMENT_MASK_ESI);  //这里地址自加了一次( L- [* {2 s/ T) s+ I' a
  5. pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);/ Q! P7 a9 k4 h4 n
  6. pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);) U9 j( V$ L7 V- Q7 ~! S
  7. pRxHeader->IsFilterMatchingFrame = ((*RxAddress++ & FDCAN_ELEMENT_MASK_ANMF) >> 31); //这里地址又自加了一次
      r4 w1 S6 |+ R1 R, g1 F
  8. ......
    7 Y5 L3 x9 ?" T& @: T
  9. pData = (uint8_t *)RxAddress;; w% D; Q1 s+ R/ T+ K, @
  10. for(ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++)/ h* H; Q" U/ [2 c# f% f; T, j
  11. {9 P, y$ w: ?5 p
  12.     *pRxData++ = *pData++;
    # v4 C8 q/ ]9 P* ^  y2 @: B# I8 o
  13. }
复制代码

6 c0 g' \9 T2 Z  p5 G1 t( \        2、CAN发送流程( u& x- s# R1 q& a# g, ^0 h2 E! [, ^
* E3 Q5 T; |* o- P# N# X# }
        在消息RAM中TXBC.TBSA是发送buffer,最多有32个元素。发送buffer可以配置为专用发送buffer和发送FIFO/队列。发送FIFO/队列是指要么是发送FIFO,要么是发送队列,即发送FIFO模式或发送队列模式,由TXBC[TFQM]决定:
5 I* C: l, H5 v5 I
" r2 J' D, G& z. J" f2 [) W
20191127150042199.png
# N( g: _  v+ Y1 e2 A

, d9 {2 b7 b9 \% O        因此发送buffer可以有三种组合:全部是专用发送buffer、专用发送buffer加发送FIFO、专用发送buffer加发送队列。
, J$ Y0 ^1 F$ k
! m6 U, o- _2 A6 a, N        下面来介绍一下专用发送buffer、发送FIFO、发送队列的情况:5 J9 U8 c3 Y. ^$ y; @& K
5 Y- i& G3 A; p) B+ h
        1)、专用发送buffer' P. v7 P  p9 y- s- h' q
- |$ [; z. H# g7 I- u, X& ]
         专用发送buffer可完全在CPU的控制下发送消息。每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
2 x! G' q+ e, ~" X        如果数据部分已更新,则会通过添加请求的TXBAR[ARn] 位请求发送。请求的消息在内部会与发送FIFO/队列中的消息进行仲裁,在外部会与CAN总线上的消息进行仲裁, 并会根据其消息ID发送出去。8 H  q- U# s3 X# A( N  D

) h/ P( x- B+ F6 s& w* s5 n) B
20191122101555794.png

' ~. S* l4 T! e5 A7 r& K5 ^7 v! x( k
8 }3 n# b- Z8 m2 n        专用发送buffer会在消息RAM中分配四个32位字(元素大小为4个字)。因此消息RAM中专用发送buffer的起始地址是:
0 Q* n' f1 Y5 y$ e
& I4 a3 V9 ^0 b发送buffer索引 (0…31) *4+发送buffer起始地址。8 }0 k# t  A6 y: v

/ v: _9 V( f: y8 u% D, Q" s( G) k2 f$ i7 t

; R; m0 w% }  `4 |* n        2)、发送FIFO8 [+ h$ m. w( G4 x
' ]% T$ v2 A4 q! t) h+ `/ H
        发送FIFO中存储的消息是先从获取索引TXFQS[TFGI] 引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送FIFO为空。发送FIFO可按消息写入发送FIFO的顺序发送来自不同发送buffer但消息ID相同的消息。FDCAN会计算获取索引和放入索引之差作为发送FIFO空闲级别TXFQS[TFFL],用于指示可用(空闲)的发送 FIFO 元素数。
, H. T+ E' j6 X, x( c        新的发送消息必须写入以放入索引 TXFQS[TFQPI] 引用的发送buffer开始的发送FIFO中。 添加请求会将放入索引增加到下一空闲发送FIFO元素。放入索引达到获取索引后,会指示发送FIFO已满(TXFQS[TFQF]=“1”)。在这种情况下,下一条消息已发送且获取索引已递增之前,不应继续向发送FIFO写入消息。
! m) [: o' l. \9 E6 i' q- W! l0 `5 c2 e7 B
20191127160804244.png
0 x+ ^: F9 ], q: j" o

# ?, ~! L2 `0 f. v* |9 I% V        发送FIFO其实就是个环形队列,放入索引是队头,获取索引是队尾,队头和队尾之间保存着消息,相减当然就是待发送消息个数。当从发送FIFO取出数据,获取索引会自加,自加到等于放入索引时,表示发送FIFO为空。当放入数据到发送FIFO,放入索引自加,当绕了一圈自加到等于获取索引时,表示发送FIFO满了。" Z5 n0 O/ m$ U- s

& i/ J$ u) m" ]$ X, I2 p; l2 U        如果有一条消息添加到发送FIFO,则会通过向与发送FIFO放入索引引用的发送buffer相关的TXBAR位写入“1”来请求消息的发送。
$ _1 b$ D& g; g7 n        如果有多条 (n条) 消息添加到发送FIFO,则会写入以放入索引开始的n个连续发送buffer中。 随后会通过TXBAR请求发送。放入索引随后会循环递增n。请求的发送buffer数不应超过发送FIFO空闲级别指示的空闲发送buffer数。
% u6 H5 P' F; R        如果获取索引引用的发送buffer的发送请求取消,获取索引会增加到下一个具有挂起发送请求的发送buffer,并会重新计算发送FIFO空闲级别。如果取消对其他任何发送buffer的发送,获取索引和FIFO空闲级别保持不变。
1 A! Y1 ~- M0 V* k        发送FIFO元素会在消息RAM中分配4个32位字。因此下一可用(空闲)发送FIFO 缓冲区的起始地址是:3 l# Q8 V7 \+ I8 \# L) }4 j1 b# [
: i' _1 V* ?/ }* D. y. p" @
放入索引 TXFQS[TFQPI] (0…31)的值*4+发送buffer起始地址。" `( a# J0 C( \; E& H
5 ?" c: p2 P; M% g
        3)、发送队列0 f6 g' s3 J+ n, `" w! A0 K
        发送队列中存储的消息是先从消 息ID最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。
7 s% T/ O) X: c3 s  |5 N7 t        新消息必须写入放入索引 TXFQS[TFQPI] 引用的发送buffer中(放入索引 TXFQS[TFQPI] 只是队列头的数字)。添加请求会将放入索引循环增加到下一空闲发送buffer。如果发送队列已满(TXFQS[TFQF]=“1”),则放入索引无效,并且在至少有一个请求的消息已发出或挂起的发送请求已取消之前,不应继续向发送队列写入消息。
% R" v+ C0 B  e8 T7 z( Q        应用可使用寄存器 TXBRP来代替放入索引,并可将消息放入任何没有挂起传输请求的发送缓冲区中。! [* k. O( G) C1 A; j- I9 x
        发送队列缓冲区会在消息 RAM 中分配四个 32 位字。因此下一可用(空闲)发送队列缓冲区 的起始地址是:
) G# N8 n- ]( \1 }" G" f1 C6 e! n" Y5 I/ v3 x
发送队列放入索引 TXFQS[TFQPI] (0…31) 的值*4+发送buffer的起始地址。
2 O7 e# ?; Y6 ?, @4 \
5 j0 l- d3 L* I; P. K1 c        因此可以知道专用发送buffer、发送FIFO、发送队列的区别是对放入其中的多条消息的发送顺序不同:3 [" [8 ~  g$ q0 S; ?  R% q
/ x7 y0 f/ F& N# k* o
        1)、发送buffer全部配置为专用发送buffer
2 X8 B9 F' `( a% T% _( C$ l4 {( R8 s
        每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。# q* _- V: _. A2 Q. O
- a/ `, V8 k/ `: }
        2)、混合专用发送buffer和发送FIFO5 x. X! ?/ H0 a, X

7 P; i  J; v. r* j        在这种情况下,消息RAM中的发送buffer部分会被划分为一组专用发送buffer和一个发送FIFO。专用发送buffer的数量是通过 TXBC[NDTB] 配置的。分配给发送FIFO的发送buffer数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送buffer。' d6 d8 _+ H, R3 d
5 W- `" u5 G3 ]; c! T/ o9 k
20191127162943182.png

  D$ m2 s& K* d. c6 v1 q2 n2 G0 R9 o; M9 S. h
        发送优先次序:% q, ~8 @4 b! W( ]) |' @
A、扫描专用发送缓冲区和时间最久的挂起发送FIFO缓冲区(TXFS[TFGI] 引用的缓冲区)0 p! y- }  I4 R! [5 ?% @
B、消息ID最小的缓冲区优先级最高,下次将发送该缓冲区的数据) |+ C0 t  @# L: W
: s2 _- F) }) f- i9 u/ H5 U
        3)、混合专用发送buffer和发送队列
1 a4 }) h/ x2 }6 H" |* ^3 U9 ?
" ]" Z+ |1 r/ F' X9 V        在这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队 列。专用发送缓冲区的数量是通过 TXBC[NDTB] 配置的。发送队列缓冲区的数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送缓冲区。
9 o2 P9 U/ P# |% [, n$ q% I
: z/ Q" F- ]" b+ H
20191127163202212.png
% J( p+ A' T& J) |' H! R5 X
6 _: a; y+ g; K9 N! P  Y3 Q+ d; ]
        发送优先级设置:
0 g- ]! A& i- j5 c. NA、扫描所有激活了发送请求的发送缓冲区" w& f: W1 ~7 P# N& n* v; N8 ]1 l
B、消息 ID 最小的发送缓冲区优先级最高,下次将发送该缓冲区的数据
5 S& }  S2 {8 M, e1 }: b& I
9 ~, B+ ?. V. `6 k0 z        再来介绍一下发送事件FIFO,它并不是发送FIFO,不是用来存储发送消息的,而是用来存储发送消息的状态的。* x! z) N- o9 y

$ D- x( a/ t% O$ @/ J4 t        FDCAN 在 CAN 总线上发送消息 后,消息 ID 和时间戳会存储在发送事件 FIFO 元素中。为了将发送事件关联到发送事件 FIFO 元素,已发送的发送缓冲区中的消息标志会被复制到发送事件 FIFO 元素中。
/ o  s& M1 @1 g4 K        发送事件 FIFO 最多可配置为 32 个元素。发送 FIFO 中介绍了发送事件 FIFO 元素。根据元素 大小 (TXESC) 的配置,会使用 2 到 16 个 32 位字 (Tn = 3 ..17) 来存储 CAN 消息数据字段。5 \/ }1 S( v6 ]4 b" x5 N
        发送事件 FIFO 的用途是将处理发送状态信息与处理发送消息分开,也就是让发送缓冲区仅 保存要发送的消息,而将发送状态单独存储在发送事件 FIFO 中。这样做有很大的优势,尤 其是在处理动态管理的发送队列时,发送缓冲区可在发送成功后立即用于新消息。覆盖发送缓冲区之前,不需要保存该发送缓冲区的发送状态信息。2 l0 h6 Q' L8 M9 s1 p
8 z$ B& L- V) V% j
        为了防止发送事件FIFO溢出,发送事件FIFO仍然支持水印功能。
) {* j& W* Y$ C2 I$ [: d7 d  {" g$ A
        CAN发送消息的代码实现:
2 g! a/ i# ?' m4 m* y* o  e7 @- i- W. x- y$ L
        发送流程与接收流程刚好相反,只需要把消息按照TXBC.TBSA格式构建好,然后写入发送buffer,写进去后设置FDCAN_TXBAR寄存器的指定位为1来请求传输即可。如HAL库函数HAL_FDCAN_AddMessageToTxFifoQ:
' S6 s1 W  ]6 k0 \3 h0 F0 L% W+ _) `; E1 g7 R
  1. PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> 16); //获取元素编号 - M; Y( ~0 L) y& D) M5 z  a
  2. FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex); //复制消息到Tx buffer - |3 c+ ]5 p! C2 ]7 P- M4 l4 F
  3. hfdcan->Instance->TXBAR = (1 << PutIndex); //发出传输请求
复制代码

" u# h( }. I2 X; \4 D7 |3 Y        发送buffer请求寄存器FDCAN_TXBAR,描述为:
# C7 R+ z6 _6 k4 F, `$ t7 N5 C. B8 k4 m! b. z
1 W; P- }: q: ^& p7 m

: `5 ~1 Y. C$ |. I% A4 Z* g        此寄存器用来设置FDCAN的哪个发送buffer可以发送数据,FDCAN有32个发送buffer,当把消息复制到这些buffer中后,就需要设置此寄存器来标记此buffer可以发送。
+ c# F5 T3 I, o) ^! S- Q3 {' Y/ M, J9 Y/ Q* g

5 \3 s. V; I' }/ }; C: T" `5 J- H; x2 _2 t0 [2 p
五、初始化" {8 q4 ^0 L% Z" A
9 z7 \! C2 L: @1 n( |7 `
        初始化可以直接使用HAL库,
7 F, e  G8 t$ o& I6 F4 F% s9 F( U- K+ q6 X
  1. u8 FDCAN1_Mode_Init(void)6 c& c5 X" L* t3 {
  2. {  F$ W" `3 p! P8 V& @3 c2 L2 q
  3.     FDCAN_FilterTypeDef FDCAN1_RXFilter;. Q, D6 r  A2 F5 B

  4. 2 m) N$ k/ @3 S  C4 N9 `/ ~
  5.     HAL_FDCAN_DeInit(&FDCAN1_Handler);                              //先清除以前的设置
    ' M$ [: [2 [$ [2 P! v9 C
  6.     FDCAN1_Handler.Instance=FDCAN1;
    0 @+ d# z8 O, |! ?* @9 t: ?
  7.     FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC;            //传统模式9 W! A3 h- I: I" i
  8.     FDCAN1_Handler.Init.Mode=FDCAN_MODE_NORMAL;                     //正常模式9 V7 ]" k. e! S/ O# R
  9.     FDCAN1_Handler.Init.AutoRetransmission=DISABLE;                 //关闭自动重传
    - s' o  ~5 L; n
  10.     FDCAN1_Handler.Init.TransmitPause=DISABLE;                      //关闭传输暂停           
    " q! M* M( L# t- H
  11.     FDCAN1_Handler.Init.ProtocolException=DISABLE;                  //关闭协议异常处理3 d& f. e) |' g2 Z. q1 a
  12.         
    ( r2 U& b. A  d! x& O) Y, I
  13.         //时钟为200M,baudrate=200M/(NominalTimeSeg1+NominalTimeSeg2+1)/NominalPrescaler,这里配置为1M
    ! Z; c5 z3 f& @* X
  14.     FDCAN1_Handler.Init.NominalPrescaler=10;                        //分频系数
    # Q- N# A" E$ J. |9 d& I
  15.     FDCAN1_Handler.Init.NominalSyncJumpWidth=8;                     //重新同步跳跃宽度2 h  G$ W: W0 G2 t4 h7 R* ^' n" ~
  16.     FDCAN1_Handler.Init.NominalTimeSeg1=11;                         //tsg1范围:2~256
    - J4 N1 M0 f! R+ v! }; Y/ X
  17.     FDCAN1_Handler.Init.NominalTimeSeg2=8;                          //tsg2范围:2~128
    # n3 P+ \: X; X8 T( \3 i- ^
  18.         
    * Z5 M& A9 G. F/ }; i
  19.     FDCAN1_Handler.Init.MessageRAMOffset=0;                         //信息RAM偏移,10KB消息RAM共有2560字,故可以偏移0~2560# n4 Z# _( o" r5 C
  20.         //使用了多少个滤波器就要设置为多少3 G5 x- z* H1 X: l7 q1 k
  21.     FDCAN1_Handler.Init.StdFiltersNbr=3;                            //标准帧滤波器个数,0~128
    & d: W( m7 m0 x0 H" ?" O
  22.     FDCAN1_Handler.Init.ExtFiltersNbr=2;                            //扩展帧滤波器个数,0~64! D  W) U+ p% o- H. \
  23.         6 b# \( p4 l, W
  24.         //接收FIFO0、FIFO1和buffer配置,此处没有使用FIFO1故个数设置为0+ C! Q- v# J0 W& D! V
  25.     FDCAN1_Handler.Init.RxFifo0ElmtsNbr=64;                         //设置接收FIFO0元素个数,0-646 ~6 O2 u. k+ B8 C7 f
  26.     FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO0元素的数据域大小:8字节        
    # n9 b3 P3 }' ?8 r! M
  27.     FDCAN1_Handler.Init.RxFifo1ElmtsNbr=0;                          //设置接收FIFO1元素个数,0-64) L$ y* y* F. `6 i
  28.     FDCAN1_Handler.Init.RxFifo1ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO1元素的数据域大小:8字节               
    2 H9 W) |0 Y7 P9 ?* M! s
  29.     FDCAN1_Handler.Init.RxBuffersNbr=64;                            //接收buffer元素个数,0~64
    / q5 \6 w% a9 @3 v& G8 N
  30.         FDCAN1_Handler.Init.RxBufferSize=FDCAN_DATA_BYTES_8;            //接收buffer元素的数据域大小:8字节        
    9 r' e, Y& t* k- _! I
  31.         
    9 y6 H- u8 T! R% D/ \
  32.         //没有使用发送事件FIFO功能,故TxEventsNbr设置为0。把发送buffer全部作为专用发送buffer使用,故TxFifoQueueElmtsNbr设为0.
    * F  s2 K& y/ V  ^
  33.     FDCAN1_Handler.Init.TxEventsNbr=0;                              //发送事件FIFO元素个数,0~325 z- @2 o9 U, f, @, C1 j
  34.     FDCAN1_Handler.Init.TxBuffersNbr=32;                            //发送buffer元素个数,0~32
    $ Q% V9 @: ?# {; ]! h; L
  35.     FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=0;                      //发送Buffer被用作发送FIFO/队列的元素个数,0~32
    - U, \" ]$ `& n3 ~7 K
  36.     FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION;    //发送FIFO模式选择,可以选择FIFO模式或队列模式
    8 c) Z& y, f6 b
  37.     FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8;              //发送元素的数据域大小:8字节# U) z$ j8 i: X  j8 u# C& `: k
  38.         
    3 M1 p9 ]7 p/ C) t) F- {
  39.     if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1;          //初始化FDCAN
    + G! a4 ^. a$ l& d9 L) B9 l

  40. 8 h4 h. Q+ B- b1 C7 D
  41.     //配置RX滤波器,标准帧   ' M& D* |3 m9 t! G. A
  42.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    + k/ n5 Z, J5 l6 u* t8 U8 Q
  43.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    . ^1 @. N( Y. t; z
  44.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型7 H0 A8 Y# I6 `$ O9 @" ~$ B, @& ^
  45.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    % t7 i  p. F6 c4 `8 O0 e6 x
  46.     FDCAN1_RXFilter.FilterID1=0x112;                                //11位ID
    1 O8 d) y* E  e* E9 P
  47.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码$ E) L: v# W1 @: ^
  48.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    . X* c9 V/ u% j, @

  49. 6 c5 [. N9 Z7 e4 [# a' O
  50.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID6 Q! E6 n! _% s, j2 h6 X- W
  51.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                   3 @  `) Y+ i. t8 x0 t
  52.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型+ @  x" Q# H1 W2 j4 e. v
  53.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    6 B+ \, }) Q& R* z" S
  54.     FDCAN1_RXFilter.FilterID1=0x113;                                //11位ID
    ! ]. j* v& U1 {
  55.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码* W4 ~# z  @) ^2 P
  56.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    6 b" m& e% k1 }/ o" ~! ]
  57.         
    5 p# z$ O, t$ q0 i; @8 a
  58.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID  k/ h' S5 B' u! l3 J8 j' P9 A
  59.     FDCAN1_RXFilter.FilterIndex=2;                                  //滤波器索引                  
    2 L* M" C1 ?# `/ l! W" G
  60.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型0 l  n6 B9 \  J
  61.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    3 u6 q5 I5 _) b/ L: l' K3 {5 d* b8 E
  62.     FDCAN1_RXFilter.FilterID1=0x114;                                //11位ID0 I$ K* K$ ~. v4 w2 A- o1 V, d4 G
  63.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    , V$ ]" u! c3 ]% M, `, y3 G. d
  64.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化9 _4 q* \+ X: i: A
  65.         7 s9 W. [# B# I* x# O! R2 C
  66.         //配置RX滤波器,扩展帧。标准帧和扩展帧的滤波器索引是分开的   
    8 o/ E2 o$ k$ @$ g' K+ ^$ d, `9 l
  67.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
      G$ a2 d" @) L  ~$ n+ ]
  68.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    * P; Z' F! w0 i: D2 V# a
  69.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    7 I- |$ V4 r- @  h. P
  70.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    7 ?( i/ E5 e+ l9 a; R% _
  71.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(2 << 12);                  //32位ID
    5 O0 ]/ @4 S$ n6 D5 ]) G% H+ y, v
  72.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码3 m4 O0 T2 @6 X. n( j& k( x0 ^2 r
  73.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化# @. c' k  ^8 U: O' h; H5 \

  74. ' u* d+ U' E3 ]- A6 n3 |' u
  75.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
    " ^& @) Y  q* [! o7 R
  76.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                  
    . i# G% L( H: z' v
  77.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型: S0 w" f% L2 B5 U- v4 X
  78.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    ) @4 \; Z: E2 ^4 z
  79.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(3 << 12);                  //32位ID2 W% o6 G3 Y: u
  80.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码1 a. p- P& A% e* E: N: I; x/ C1 H( h
  81.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;    //滤波器初始化$ Y* D9 U; `; F# E  B
  82.         4 p' T: g$ z4 j2 f' G
  83.         //滤除的消息直接丢弃1 b& Q, C3 R" g
  84.         HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);  //设置被滤除掉的消息的处理方式
    ! R" H6 N: h! J
  85.         
    4 Y/ S1 S* b0 ^: K$ a% k6 G
  86.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);   //使能新消息接收中断
    1 k& n( `& e* A( j* F( r  n
  87.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_TX_COMPLETE,0xffffffff);   //使能消息发送中断,0xffffffff表示所有的发送buffer都触发中断        
    7 w, Y* d& e8 Y3 ?" u& a
  88.         % }6 }# `  R+ B/ x  t; m  O
  89.     HAL_FDCAN_Start(&FDCAN1_Handler);                               //开启FDCAN
    / o, [1 Y) @0 u- K
  90.     return 0;
    - H0 W, m8 n& U8 Q8 g! \' `" l
  91. }
复制代码

% D  t1 ~) V+ l+ }- F+ c4 ]" G2 `% y2 q( Z% }2 k+ _- {
六、CAN发送示例(来自正点原子)1 O1 w' \/ G/ ^) V

& I6 r; I- u$ D, }7 K4 x* O2 j
  1. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)        
    7 g* u2 i0 \4 G$ l3 n& S8 x) G
  2. //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8                                     9 y; R1 I2 P& A- M& ~4 B
  3. //msg:数据指针,最大为8个字节.
    & k7 D6 W% v; V$ X7 S
  4. //返回值:0,成功;* `2 ~6 U2 \! a/ j7 i
  5. //                 其他,失败;
    / d2 ]! b8 |% r: [4 Q( z
  6. u8 FDCAN1_Send_Msg(u8* msg,u32 len)  V8 q% c" ^) c" z7 t0 t
  7. {        
    3 H1 Z. o$ j; c% a6 U6 I
  8.     FDCAN1_TxHeader.Identifier=0x12;                           //32位ID
    , X2 P) t( C- U( f6 x+ q
  9.     FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID
    % c; h/ o/ E/ L7 c% \) H( Y
  10.     FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧7 D; I) U# X9 _( D, S9 B8 L. l
  11.     FDCAN1_TxHeader.DataLength=len;                            //数据长度
    . ~+ v. P5 i' `2 n0 \
  12.     FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;            
    5 Y( C8 F/ S! u" ]
  13.     FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换
    * a+ o; |& [# {7 w$ Q$ O) p
  14.     FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式, H0 e' `+ }4 a5 J: A
  15.     FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    3 t# P% G$ S. s" _
  16.     FDCAN1_TxHeader.MessageMarker=0;                           3 u) }! z. [8 [1 w- w+ W6 j) }3 y

  17. + P& s2 t% ^! C9 g4 a! I
  18.     if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//发送
      x0 u: @$ K3 q1 S
  19.     return 0;        
    $ R8 |# N1 o: ]; l! J! K
  20. }
复制代码

( V4 c* p( R& z3 W+ i2 M. @' S七、CAN接收示例(来自正点原子,因为滤波器被关联到FIFO0,因此消息只会放入到FIFO0)
7 w. N( \# g( O7 a, |. Z# W, `# `" ?& v6 s. n. K
  1. //can口接收数据查询
    4 c5 o% N6 [( J! B( o1 G  i
  2. //buf:数据缓存区;         1 ]6 I: P/ @8 h
  3. //返回值:0,无数据被收到;2 W* Q8 r  |$ Z* D3 y6 _
  4. //                 其他,接收的数据长度;
    $ F% y, K; C, l3 {0 J" V' `
  5. u8 FDCAN1_Receive_Msg(u8 *buf)( s6 O5 n* I# R1 Z, s
  6. {        3 @- M  ]0 v1 L9 {4 r
  7.     if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收数据
    ) E0 _  b) `0 D8 L& ~# v1 P
  8.         return FDCAN1_RxHeader.DataLength>>16;        6 I7 E, b! @/ O' @- ^1 n7 G
  9. }
复制代码

8 Y0 I6 Z2 J/ E, Z4 Q, e参考:《正点原子》  STM32H7开发指南-HAL库版本_V1.0 (文档中有很多错误的地方,笔者被误导了好久,阅读的时候还是要以H7官方手册为准)
5 }" V+ T+ l  v! ]* A3 p) F  S9 U) G$ e) e  c7 d
) _  y) C: e2 c9 L
收藏 评论0 发布时间:2021-12-22 14:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版