请选择 进入手机版 | 继续访问电脑版

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

【经验分享】STM32H7的FDCAN

[复制链接]
STMCU小助手 发布时间:2021-12-22 14:00
一、介绍" X& l+ ~& E/ Z. T9 M, I' v

- A% Y6 Q; _- g; G        FDCAN(Flexible Data-Rate CAN)是CAN的升级版。特点包括:
3 g2 E* l- `" M* y* @! x/ v, C! s4 l6 t" j- f
       1、每帧数据段最大长度由8字节上升到64字节。
; H0 C& u: Z; v+ S, V6 g8 J0 {* k2 g& L# i" H
        2、速度由1Mbps上升到5Mbps,甚至还可以更高。在一个数据帧中仲裁段(ID和ACK)的速率和CAN一样最高1Mbps,这样可以保证总线的健壮可靠,但是数据段可以5Mbps甚至更高,一个数据帧中使用不同的波特率,这就是FD(Flexible Data-Rate)的由来。
- I7 Q% f# X. P+ t
8 j* a* t! |3 ~9 K7 g5 K1 W* j        3、向下兼容CAN。1 R* s7 a# }6 Z9 e$ _* o
- c+ U% T% r% `& i# G4 B( C/ I
        H7的FDCAN包含2个可配置接收FIFO。多达64个专用接收buffer,多达32个专用发送buffer。可配置发送FIFO/队列,可配置发送事件FIFO。  Z0 N& n& ~% ^0 u5 L. C
$ f7 A, |8 I1 @7 D+ B+ `
二、结构9 n, v8 \6 Q. y% Q$ g$ E7 o# a
# W' M# m& a# o3 G. j
        先看结构框图:
* d8 M. k1 d" t# b9 J) N. v9 D" [, P% d
20191121162856859.png
9 G/ u; ~( \% e
( _; P. y1 |5 {7 u
1、两条中断线:fdcan_intr0_it和fdcan_intr1_it。可以通过FDCAN_ILE寄存器的 EINT0和 EINT1这两个位来使能或者关闭。
" F# B2 q1 G+ A. {+ O- U* x! u" c5 U
20191127102816991.png
: }7 n6 R" G7 r" Z7 ]

# k. J  e  _6 S* |1 m# C, i2 g        可以通过FDCAN_ILS寄存器来选择FDCAN的中断是在fdcan_intr0_it上触发,还是在fdcan_intr1_it上触发,默认所有中断都在fdcan_intr0_it上触发,没有特殊的要求,只需要用一条中断线就可以了。
! g" {: u4 @, b8 ?, |! U$ M& q2 ~
( n! m! X2 v3 p% J/ K+ S' [# p. \2、TX Handler:负责将消息RAM中的数据发送到CAN内核,最多可配置32个发送buffer进行发送。发送buffer可用作专用发送buffer、发送FIFO(发送队列的组成部分)或二者的组合。发送事件FIFO会将发送时间戳与相应的消息ID存储在一起,另外还支持取消发送。
7 B' k; p. A7 A# ]  h4 c! e0 o5 i: H
0 u, o# o! L. E* }3 M, ~; Q3、RX Handler:负责将CAN内核的数据传输到消息RAM,支持两个接收FIFO(每个FIFO的大小均可配置)以及最多64个专用接收buffer(用于存储所有通过验收过滤的消息)。专用接收buffer仅用于存储具有特定标识符的消息,与接收FIFO有所不同。每条消息均与其接收时间戳存储在一起。
2 m7 ?# J! [: ?* V! b) j6 V/ \& I
8 }: H1 Z8 N3 Y4、CAN core:CAN内核,读RX引脚数据处理后给RX Handler,接收TX Handler处理后控制TX引脚。' q; D! c: }# u: `

/ w1 \6 E7 v9 G+ X8 H# V5、Message RAM interface:消息RAM接口,外面连接着消息RAM。消息RAM是FDCAN的核心,本质是一段最大10KB的内存,把这段内存分成不同的区域,每个区域的作用不同,可以实现:过滤器、接收FIFO、接收buffer、发送事件FIFO、发送buffer。内存分配如下:) L! j& j# \! {$ }

/ X* @- U# T1 a6 o/ X$ H
20191121164211703.png

; D! g8 p" v" V5 z& E; f) a! ]
& I# n* Y9 p7 M, Q) C        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字。
$ k0 Y9 J, k& t7 v" V
( u9 p) @" J' {/ _6 i        1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,最多可以有128个元素。& O! X/ I; _$ g7 D8 p
5 K1 }' m8 O3 Q, D
        2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,最多可以有64个元素。(F1配置寄存器来设置过滤ID,H7直接划了个内存区来设置过滤ID)
( Z" n4 s; X) ~& V) }
( y; I& ]) U. x1 I9 H  ?* s2 c$ @, C        3)、RXF0C.F0SA:接收FIFO0,最多可以有64个元素,可以接收64条消息。
2 `6 l: k% v9 c+ [! x
- o, j2 t5 b2 u9 q1 a' `; j* z8 m        4)、RXF1C.F1SA:接收FIFO1,最多可以有64个元素,可以接收64条消息。# q) f  Z9 y- P) X/ a7 E

2 Z/ h0 O1 I  B% R5 S+ m9 x        5)、RXBC.RBSA:接收buffer,最多可以有64个元素。" I+ b# D/ X  N* A( _8 y8 H
" h1 i0 U% |4 Y8 f7 N0 J
        6)、TXEFC.EFSA:发送事件FIFO,最多可以有32个元素。(不是发送FIFO)
) i/ i/ h1 W3 {8 D7 {& `* E! @4 s9 F) }9 G& z! ?. ?' x; n! M
        7)、TXBC.TBSA:发送buffer,最多可以有32个元素。
3 `# {: I4 b7 h% q7 S
. v" o2 Q8 z: M3 f$ h# f0 p        8)、TMC.TMSA:触发存储器,最多可以有64个元素。
7 l7 \1 D, h2 k: S; G, B
' E: g& X" J2 X《注:这8个区域的元素个数和元素大小都是可以配置的,但是这8个区域的地址又是连续的。因此在初始化的时候,会根据每个区域的元素个数和大小来计算下一个区域的起始地址,并保存到相应的寄存器中》, t) M- L  f3 L( [1 t
1 Z6 {: l7 P9 u2 @# O) w7 O8 ~8 I
        下面来详细介绍这几个功能区域:
3 K3 V( ~' s7 e! B7 m( M
$ W8 q2 a- @# _. o* f1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,有128个元素,每个元素占一个字,定义为:
1 y/ L3 U- h% p; M, {
% [8 E0 t" v: O7 l
20191121170625565.png
  F1 u$ U# M) A/ W4 E
0 z9 c4 V  s" @: O9 g( V* j
SFT[1:0](bit31:30):这两位用来表示过滤类型,一共有四种:
# r5 J( K# {& u' h4 k    00:范围过滤,过滤到SFID1到SFID2中的所有信息。
& z, K3 O2 A. B# f6 a) x: ~& A    01:双过滤,过滤到SFID1和SFID2中的信息。% ^$ c9 Z0 y. h
    10:传统位过滤,SFID1 是过滤值,SFID2 是掩码。
8 M9 F6 Y  l- C1 F    11:禁止过滤器元素& y; x$ I% D. r3 S3 |
SFEC[2:0](bit29:27):标准过滤配置
, w( U, r2 ^6 u. i% x    000:禁止过滤器元素# a$ Y; I- M# b1 I/ j2 p& p8 x
    001:当过滤匹配以后存储在Rx FIFO0中。
2 F7 l2 G2 q% x    010:当过滤匹配以后存储在Rx FIFO1中。
  o7 r  Q' a! h    011:当过滤匹配以后丢弃。
/ C4 H6 o* G  v/ q; u    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。
! O/ s: u& A( ~. `; v; H    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。
! a( N8 g/ F2 c/ P    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。
2 T  Y, N+ [  Z- k. w    111:存储到Rx buffer中或者作为debug消息,FDCAN SFT[1:0]忽略。, m. @4 Q: ?1 d! R0 X% ^7 h
SFID1[10:0](bit26:16):标准过滤ID1,第一个要过滤的ID。, m) H8 S: w2 C& t7 F' y0 r4 @" E
SFID2[15:10](bit15:10):标准过滤ID2,此位根据SFEC的配置不同而不同,当SFEC=001~110的时候此位域表示标准过滤ID。当SFEC=111的时候此位域表示Rx buffer或者debug消息。
1 o. b/ K/ {" c/ \! f. S
8 i0 r! G6 t8 g1 \% E; {SFID2[10:9](bit10:9):设置接收到的消息是存放在Rxbuffer中还是处理为debug消息的消息A、B或C。
1 H# J- f/ ]8 A  ]( o/ \; G) J    00:将消息存储在Rx Buffer中。. y# g4 H3 W: _5 A+ t0 Q

' X9 |& h7 c9 U* C7 Q$ z    01:debug消息A。      Y) x( R# X0 ~/ i7 @( ?) B
4 B& _+ K9 L/ q- `' @; [( v
    10:debug消息B。: [1 K5 \/ J( ?+ Q, S5 ?

# a6 ]* g! w/ P! d3 c    11:debug消息C。
0 R/ P: ^0 I- O. U6 C* X
( {% g6 r4 F0 T" ~SFID2[8:6](bit8:6):确定是否将滤波器事件引脚作为外部接口。
6 E2 ?1 }, \' X  O. \( R
8 D2 y' v: x* w* ?  l, Q( G6 L- XSFID2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer 的开始地址RXBC.RBSA的偏移。
& n, ~, L3 X$ a  y' K
* q% F$ f. v. F$ }+ g/ t2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,有64个元素,每个元素占2个字,定义为:  y$ j* n" w1 x$ k

6 g7 O0 l; E  {
20191121171836710.png
: N) @) u: g% C
4 R& }+ \3 Y7 Y5 p- h2 I& Y5 ^; x
F0 EFEC[2:0](bit31:29):扩展过滤配置
) [8 A2 T9 o8 f; E$ z2 U& g    000:禁止过滤器元素
; n8 r# @$ @! H% m/ {4 @# D9 t4 a    001:当过滤匹配以后存储在Rx FIFO0中。) P0 V9 K! p5 n8 D9 n
    010:当过滤匹配以后存储在Rx FIFO1中! W2 d! `& f: E* D( [" ?1 y
    011:当过滤匹配以后丢弃。% X1 E3 s, S' c, P: E, {
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。
( o$ B6 ]$ G5 r9 s' I    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。
' A9 ?; A) k8 q" c, k7 }    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。
( Y2 e! s/ A' N/ D    111:存储到Rx buffer中,EFT[1:0]忽略。" Q' c* H2 d8 Q' d' s9 L% C( ]
F0 EFID1[28:0](bit28:0):扩展过滤ID1。
( O* P9 i- c9 e" T- bF1 EFTI[1:0](bit31:30):扩展过滤类型
0 m( K( z: N! w, B4 l3 h! X    00:范围过滤,过滤到EF1ID到EF2ID中的所有信息。5 j& z& E5 B, K0 |* V8 e- e
    01:双过滤,过滤到EF1ID和EF2ID中的信息。
, Q; T0 l! N: z6 [% g# A+ W    10:传统位过滤,EF1ID 是过滤值,EF2ID 是掩码。
, _# B3 P: z8 j    11:范围过滤,过滤到ED1ID到ED2ID中的所有信息,没有使用FDCAN XIDAM的掩码
) A+ y5 q, z3 x- [2 x6 @F1 EFID2[10:9](bit10:9):设置接收到的消息是存放在Rx buffer中还是处理为debug消息的消息A、B或C。
0 k( c- W9 j3 l! b    00将消息存储在Rx Buffer中。& ^3 O( Z( }- ^4 n9 U: I6 p7 R
    01:debug消息A。- ?  Y0 v# q) ]; N! ^
    10:debug消息B。
" F! J9 w! j$ l: ?7 O    11:debug消息C.
( W. {  i+ ?+ l2 |3 GF1 EFD2[8:6]bit8:6):确定是否将滤波器事件引脚作为外部接口。
, J+ M, p  V9 G- Q1 \2 u; hF1EDIF2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer的开始地址RXBC.RBSA的偏移。9 b* Q  z0 b2 ]

/ H6 c+ z2 Y2 W& M5 |$ ^# [3)、RXF0C.F0SA、RXF1C.F1SA和 RXBC.RBSA分别为Rx FIFO0、Rx FIFO1、Rx buffer,它们都有64个元素,元素的大小根据数据长度不同而不同,范围为4-18字,它们的位定义相同:
) v% a9 N& ~4 K
. O& S! V6 T2 a& D/ o/ k
20191121172451477.png
2 L0 z: P: o1 z1 @

6 j. K2 g6 X1 X5 E% i9 E! @R0 ESI(bit31):错误状态标志
# `. ]- L4 z$ x    0:传输节点显性错误。
: y# S& P/ \, f+ B: ?) w# [! \# P    1:传输节点隐形错误
0 {# v7 k- M9 K% _R0 XTD(bit30):标记是标准ID还是扩展ID3 W! Y; x% T( |3 p. p( a
    0:11位标准ID
9 s, h+ _5 Q7 L$ E3 ^
! w1 |" P9 V. S* [9 C, j/ w    1:29位扩展ID
; D; o6 u4 F7 Y0 `4 L5 [
$ k% P" `4 \. a4 XR0 RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
/ b4 m2 |0 [" O; F7 c1 J. }. w6 ?* Q    0:接收到的帧是数据帧
8 `& |0 B- M/ i( W& a1 _/ Z6 n3 [- F
    1:接收到的帧是遥控帧
0 f* V) J$ P# _( c; n. X! e# aR0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。
7 _, b2 M3 O" c5 S9 G/ B" OR1 ANMF(bit31):/ s2 N. F; ]2 x. I5 |! a, b

' W  z& @" I) a    0:接收到的帧和FIDX中的过滤帧匹配6 I) s  r( ?5 G) _
8 j% y+ [: L' M: V
    1:接收到的帧和Rx滤波器中的任何元素都不匹配
+ v$ z3 u7 }$ h3 A: ]R1 FIDX[6:0]bit30:24):过滤器索引,0~127,表示和Rx滤波器中的哪个元素匹配。
7 t% ], V) \5 |4 fR1 FDF(bit21):帧格式
1 {) y1 W1 ^+ Y! T1 Q6 I    0:标准帧格式" U" J% t' b8 ^
    1:FDCAN帧格式。
' \) n& ?5 q2 U& }' X( ]* KR1 BRS(bit20):比特率切换' Y# M* K# s- X1 N% o" V# q
    0:接收到的帧没有比特率切换+ @' l! V8 h& A: {5 L2 ~+ ^6 Z  A

$ j3 @1 `0 ~% ~' T/ m. \8 \    1:接收到的帧带有比特率切换; E4 M5 Q3 @" k
R1 DLC[3:0](bit):数据长度。% G: p: f! c, s
    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
5 Y5 x) G" v$ R" l. U- ]+ O1 @    9-15:如果是传统CAN,接收帧长度为8字节。2 [! s  d: M: _9 ~7 Q1 W$ s
    9-15:如果是 CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64 字节。  j/ K. g+ a% O7 {* r
R1 RXTS[15:0](bit15:0):接收时间戳。. y4 q8 C5 m' i- s8 _0 Q4 a# D8 C, O
R2-Rn:接收到的数据。
, q% f! W7 g2 d0 B$ {/ v/ C# m% q4 g
! ?/ B! h) r8 I4 c' S* w, J0 U8 C3 o, P4)、TXEFC.EFSA:发送事件FIFO,有32个元素,每个元素两个字。, L5 T! v. ^3 x/ Y$ I9 f9 A
6 F6 H8 Z, A5 Q& n
20191121174147402.png
  U* l0 J1 h  S- ]3 P
( |3 G: \3 j) F
E0 ESI (bit31): 错误状态标志3 ~9 k7 ?' V# M1 s
% Z9 `+ q: t9 S; q
    0:传输节点显性错误4 P# b  v- k6 ]" r0 y2 d
    1:传输节点隐形错误。# \) B1 V5 a% r8 e! S; l
E0 XTD(bit30):标记是标准D还是扩展ID
* ^* N3 [& f2 H" K7 k( P% i    0:11位标准ID.( E  R1 ]1 o) h
    1:29位扩展ID# \! k, N+ N8 E7 K6 P

( `! Z$ a/ _, R3 u& v- a3 iE0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
! M5 K6 r, r; f    0:发送的帧是数据帧
. V: q8 B; P9 J& _. T8 y    1:发送到的帧是遥控帧# d$ J; E6 P6 H- C, m) S6 |
E0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11 位ID还是29位ID。# D% R& ^7 Z0 w2 v$ @' ?
E1 MM[7:0](bit31:24):消息掩码,从Tx buffer拷贝到Tx Event FIFO中。
0 r9 I+ i8 K3 X5 bE1 EFC(bit23:22):事件类型) G" B5 E% i+ `8 A7 w! V0 c
    00:保留。; o, v' x" r8 {8 t1 {, }/ h1 B2 t
    01:发送事件。
% X* ?: j0 J, i) L) u: i    10:发送取消。9 o- _" S8 a# n  b0 b
    11 :保留。& n; g% u+ E* h" w
E1 EDL(bit21):扩展数据长度
' r  g; E" A; p/ }/ J" @! W; F    0:标准帧格式
0 E( S$ j- A, ?  s3 l    1:FDCAN帧格式。" a; W* p2 x; D  r% u4 v, B4 E
E1 BRS(bit20):比特率切换
) r/ ^- Z: N, Q    0:发送的帧没有比特率切换0 I7 t& V* S  H

9 B# ^) B2 K# N    1:发送的帧带有比特率切换
2 E* |' c/ E$ X4 q$ Y3 DE1 DLC[19:16](bit):数据长度。
5 N" U6 Q3 C7 |3 w$ y2 R1 U    0-8:传统CAN+CANFD,长度为0~8字节。1 f! O- m* s4 q: f) R2 j
    9-15:长度为8字节。
1 p- x, q5 i- {' _- z9 XE1 TXTS[15:0]bit15:0):时间戳。5 V+ ^6 p! Z3 _. |) y4 |/ E/ F

& b7 n5 a6 ~0 d6 L3 F8 r" ^8 G5)、TXBC.TBSA:发送buffer,有32个元素。
3 z. R3 x0 j, G" Z- i& C5 c
+ x+ B; Y6 }' E9 l, n& a8 g- {0 y& Q
20191121175121493.png

0 [# _/ |* X: j6 J. L+ W( k
) S! Y' R- w1 r- d5 r& `T0 ESI(bit31):错误状态标志
' b/ I4 L. e" q2 H7 b, {# @( O# i    0:CANFD帧中取决于被动错误标志。
5 O9 J8 h" v" A* u& y    1:CANFD帧中隐形错误。# h1 A9 L, n2 m- M* n2 G9 i$ Z- w
T0 XTD(bit30):标记是标准ID还是扩展ID- m; |# }, b0 P' z& ^1 w) q
    0:11位标准ID% i6 W6 X* ?3 _! f

" V. i9 k. G: s2 @6 b    1:29位扩展ID
: }& U, ^; |* ~: ?! Z  y6 S; k9 V7 a5 V0 ~' k4 k
T0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
! ]  [2 I* I/ ^( ?2 F* {1 p    0:发送的帧是数据帧
' w. ]6 ~. |# G" y    1:发送到的帧是遥控帧2 L2 U6 {, K" j
T0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。4 G& }( h/ j; ?
T1 MM[7:0](bit31:24):消息掩码,配置Tx buffer的时候由CPU写入。
6 X* h, V: m( _2 w6 y1 r1 `T1 EFC(bit23):事件FIFO控制
) o3 m! p8 N5 u9 ~) P7 k/ Z/ H    0:不存储发送事件。
' c7 Z: ^9 o$ |- r- G- f+ [$ N    1:存储发送事件。
; y" u; J! f$ ]/ ^  p/ D: H4 Z! _0 hT1 FDF(bit1):帧格式( v  H1 X* u7 l8 g" R% i5 J
    0:标准帧格式
" d0 s( @& b9 }! b1 K4 A: D    1:FDCAN帧格式。- I5 O$ A8 z5 v
T1 BRS(bit20):比特率切换
8 ?" V0 N% S# i  |    0:发送的帧没有比特率切换) `+ d4 I$ o. A- r: k+ [2 m/ l
, g' d: y( s" T1 [! ^, w9 Z$ x! _
    1:发送的帧带有比特率切换1 V+ Y8 \8 `% _& s2 w: H
T1 DLC[19:16](bit):数据长度。
1 U* j/ |! C" O* U! ?" z8 I  m( W, M' E    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。# o- A% @* z& C6 |! y4 i- n5 E3 N
    9-15:传统CAN,接收帧长度为8字节。; V. P; {. R1 _6 C& R( V
    9-15:CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64字节。% m  d+ ]/ t: G9 D. _. [0 {
T2-Tn:发送的数据。
% t/ S5 D$ n& X, I1 V% q
) s8 ~0 ~# b, C; I8 z三、过滤器设置: X! i& m8 e3 _, ~: s4 p1 f

3 l: G5 x* r2 }9 R7 ~        标准帧和扩展帧过滤器的设置分别往SIDFC.FLSSA和 XIDFC.FLESA区域写数据即可,下面以标准帧为例,标准帧过滤器共有3种过滤模式:
5 }8 ^1 t! ^4 A+ v1 u' f
) ]$ W+ y$ h0 S% a5 h7 [        1、指定范围过滤
: D( j3 G2 D8 ?! H- U& G/ o$ Z        通过SIDFC.FLSSA的SFID1和SFID2来设置需要过滤的ID范围,其中SFID2的值要大于SFID1,这样只有ID值在SFID1~SFID2之内的消息才能被接收到。比如我们现在要设置只接收ID在0X123~0X321范围内的消息,使用标准滤波器n,SIDFC.FLSSAn(n=0~128)的各个位设置如下:
$ C6 V& Q3 k& G5 i! K  G
% I9 U6 p3 I5 J
  1. SIDFC.FLSSAn.SFT=0        //范围滤波3 A/ ~, F8 z; Q$ h6 z# j/ [
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到RxFIFO中
    - J$ M) k+ h/ [: n4 U& p% R
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    $ A& E* a. `! l: ~
  4. SDIFC.FLSSAn.SFID2=0X321  //ID2
复制代码
9 E" y; {3 o! u, S
        2、指定ID过滤2 \( k" `0 m% ?4 O) ?) v) X
) l" _  r3 G5 n$ p
        我们也可以设置只接收指定的一个或者两个ID的消息,如果只接收指定的一个ID消息的话SFID1=SFID2。比如我们要设置只接收ID为0X123的消息,设置如下:; q: ]* s0 c" y- f9 g; V$ B

0 C9 _/ B+ y+ \4 ]
  1. SIDFC.FLSSAn.SFT=1        //指定D过滤
    7 j- Q& w7 ]' T) p! Z& }0 c
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到Rx FIFO中
    / X1 w4 \6 j. z- L8 }
  3. SDIFC.FLSSAn.SFID1=0x123  //ID17 s+ ~# [) F$ \# I$ _4 {
  4. SDIFC.FLSSAn.SFID2=0X123  //ID2
复制代码
* B: |: I! v: y" o
        3、传统的位过滤+ y" B7 V1 v6 p. \
        第3种过滤模式就是以前STM32的CAN上存在的位过滤模式,在屏蔽位模式下,过滤消息D和过滤掩码一起工作决定接收哪些消息,其中SFID1为过滤的消息ID,SFID2 为过滤掩码。举个简单的例子,我们设置过滤器SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:
/ w7 W+ L1 h0 i  N" {0 f
# k1 f  Z+ d0 L# ?5 X2 i
  1. SIDFC.FLSSAn.SFT=2          //传统位过滤9 V. ~) M+ a& m* v8 t/ x
  2. SDIFC.FLSSAn.SFEC=1         //如果滤波匹配成功的话将消息保存到Rx FIFO中- I: m% w/ S  b* {
  3. SDIFC.FL SSAn.SFID1=0xFF00  //ID16 D+ u" y3 a, a. B
  4. SDIFC.FLSSAn.SFID2=0xF00    //掩码
复制代码
1 H3 r2 z. \# l9 j
        其中SFID1是我们期望接收到的消息ID,我们希望最好接收到ID=0xFF00的消息。SFID2的0xF000规定了我们必须关心的ID,也就是接收到的消息ID其位[15:12]必须和SFID1中的位[15:12]完全一样,其他的位不关心。也即是说接收到的消息ID必须是0XxFxx这样的才算正确(x表示不关心)。  o- S& f) m8 `6 O% v

) r- ~, E6 M$ u1 i- z6 ^+ ~; ~& q0 p四、CAN的收发过程8 m2 l8 u; z* ?- E# Y
( l1 T: B. D( l* e: I6 G
        1、CAN接收过程
& G  q8 U* X+ U& h1 p2 v5 W9 w4 o* r& h8 Q+ }4 }+ m; K
        CAN接收到消息后会进行过滤,过滤时会从SIDFC.FLSSA或XIDFC.FLESA区域的第0个元素开始匹配,直至符合过滤器中的某个元素的规则,则过滤完成,过滤完成的消息会按照过滤器元素的配置进行处理。比如过滤器元素的SFEC/EFEC位决定过滤后的消息是放入接收FIFO0、接收FIFO1还是专用的接收buffer中。
6 ~, ~& D4 w/ T0 s2 v! x& @, N2 w& U$ V8 I% Y
        接收FIFO 0 和接收FIFO 1 最多可分别保存64个元素。两个接收FIFO的配置是通过寄存器RXF0C和RXF1C完成的。
7 M) O8 ]! Z; B) X$ [, N6 h4 R- d! r3 E% O
20191127114550965.png

7 r- ~7 I! Z: f. k
+ ]3 O5 G6 w/ U; }2 V# u5 n        当IR寄存器的RFnF(n为0或1,代表接收FIFO0或接收FIFO1)指示接收FIFO已满条件时,在至少已读取一条消息且接收FIFO 获取索引递增之前,不会继续向相应的接收 FIFO 写入消息。如果在相应的接收 FIFO 已满时收到消息, 此消息会被丢弃,中断标志IR[RFnL]会置 1。也就是说,接收FIFO满了后会触发RFnF中断,如果继续接收,消息会被丢弃,并触发RFnL中断。! S& V# C7 Z2 e3 S# Y! k; p- w
# E$ \4 ^8 ], ?3 o

7 z# {0 K. O. R; `( ~. s8 _9 A! A
20191127111235302.png
& O' |* |. l8 W3 ]

9 a$ C1 @. k7 l9 Y        为了避免接收FIFO溢出,可使用接收FIFO水印。当接收FIFO填充级别达到由RXFnC[FnWM] 配置的接收FIFO水印时,中断标志IR[RFnW]会置 1。比如接收FIFO0大小配置为64,水印值配置为60,当接收了60条消息时会触发水印中断,提前进行处理,这样就避免了FIFO溢出。
+ B4 R0 ]7 F  B5 F        读取消息就是直接从RXF0C.F0SAn或RXF1C.F1SAn(n为索引号 0~64)中读,消息的组成结构在上面已经说过了,比如HAL库HAL_FDCAN_GetRxMessage函数读数据过程(假定从FIFO0中读):7 f! T5 e( Q. t; i
: f7 q- [3 D5 }' m
  1. /* Calculate Rx FIFO 0 element address */
    ' F3 ^. {+ X' |1 \) K
  2. GetIndex = ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8);
    0 c4 Y, r. B, t: g7 H9 D6 z7 ]9 w
  3. RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4));
复制代码

6 Y% J7 M# f( F9 b2 i  B1)、((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8):作用是获得FIFO0状态寄存器FDCAN_RXF0S的bit[13:8],读这里可以知道接收到的数据保存在FIFO0中的第几个元素中,GetIndex的范围是0-63,刚好对应64个元素。当FIFO接收到一条消息,GetIndex会加一,当从FIFO中取出一条消息,GetIndex会减一。$ Y4 h6 E  L- ^$ f5 ?

+ d: z' F( S; c8 r( S
2019112119095892.png
8 q0 a# v) C0 S
- d; e# c# ], C8 ^. y: @  I
2)、hfdcan->msgRam.RxFIFO0SA:是RXF0C.F0SA区域的开始地址。. r! p/ N- C+ n* `: u  S5 {# K

' T# e8 c) t6 _0 T3)、hfdcan->Init.RxFifo0ElmtSize:是接收FIFO0的元素大小,根据数据长度不同而不同# w4 H: s% H& A, F' i6 [
# ], A: t. ]) y! b+ J, m" w
! E$ O' ~) h* N& K

) a  m- ~1 c  b" ?: z如果消息长度是8个字节,那么算上固定的R0、R1,元素大小就是4个字。
) R$ Z, Z3 A# Y8 y9 L0 G
0 |( J) D, ]0 r" o- k0 b如果消息长度是64个字节,那么元素大小就是64/4+2=18个字。! U5 x+ Z" ?3 g. @6 d* N, }
# C% _$ Y+ G+ o$ x# G1 d. p* o7 U- `
        计算出了元素在FIFO0中的地址,直接按数据结构读数据就可以了:; G: L& _0 n& e) G; j9 F0 ?
+ _0 M) a4 p) {- _' T
  1. pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;
    7 L: z% E& R7 \1 \( n! b! ]
  2. pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);4 Y/ O& p& w- a( t
  3. pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);
    4 @5 C$ t: P- y$ V* {% K% w
  4. pRxHeader->ErrorStateIndicator = (*RxAddress++ & FDCAN_ELEMENT_MASK_ESI);  //这里地址自加了一次0 J! Z7 {* f1 u4 Z0 _* A, _
  5. pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);; d" g) T: d9 P6 s
  6. pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);
    5 X/ @' k7 Z; }
  7. pRxHeader->IsFilterMatchingFrame = ((*RxAddress++ & FDCAN_ELEMENT_MASK_ANMF) >> 31); //这里地址又自加了一次9 l' h1 k& E7 X/ j! N: A* K
  8. ....../ A" Q! S/ d3 F5 Q, \' l
  9. pData = (uint8_t *)RxAddress;
    , ~2 [3 w/ }/ ~9 N8 c: N! E
  10. for(ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++)
    9 Y* j9 M8 |1 Z* B* M4 a
  11. {9 y5 K2 z9 A8 @) \6 n( ~
  12.     *pRxData++ = *pData++;
    6 O' m( _) v" |7 b, X( r3 L/ X
  13. }
复制代码
. f! q; n  A5 R$ Y3 N; H' ^9 ~( d3 W
        2、CAN发送流程+ N' a, s2 o  T' ?: f- G

/ C, I5 H1 }! u# z5 U        在消息RAM中TXBC.TBSA是发送buffer,最多有32个元素。发送buffer可以配置为专用发送buffer和发送FIFO/队列。发送FIFO/队列是指要么是发送FIFO,要么是发送队列,即发送FIFO模式或发送队列模式,由TXBC[TFQM]决定:5 b5 p; z, c2 }! F& n8 q, B' E- l

) {- W7 c) g% ]6 O$ ^, D
20191127150042199.png

% e: ^# |( I, a- d) l5 W* r% e! v: W, y8 D: C; P# b& @( T8 ~
        因此发送buffer可以有三种组合:全部是专用发送buffer、专用发送buffer加发送FIFO、专用发送buffer加发送队列。
5 K2 ]0 k0 E4 W) S- X7 {( `" {9 E
1 v# [7 U& D, K! X: v        下面来介绍一下专用发送buffer、发送FIFO、发送队列的情况:
+ i3 G. I' W! M" Y0 M3 Q3 d5 \, s2 u- [# O, @8 i/ j2 w7 P9 E
        1)、专用发送buffer
7 T, W( l5 ~1 F( F, ^, `/ _1 E' ?4 R1 O8 e. y' H6 D
         专用发送buffer可完全在CPU的控制下发送消息。每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
8 h2 f! s+ K( e        如果数据部分已更新,则会通过添加请求的TXBAR[ARn] 位请求发送。请求的消息在内部会与发送FIFO/队列中的消息进行仲裁,在外部会与CAN总线上的消息进行仲裁, 并会根据其消息ID发送出去。* O$ c2 p/ g  D+ h1 T# W

8 o# v" ?, P- m& o$ x) ?: `0 ?* R
20191122101555794.png
4 g3 V  u# Z- _9 D
; }/ L6 b1 j. r( b; n$ B" S- h
        专用发送buffer会在消息RAM中分配四个32位字(元素大小为4个字)。因此消息RAM中专用发送buffer的起始地址是:: B/ U8 p  |7 A1 `% J
& L. O0 V; A; l* @) w0 S. r
发送buffer索引 (0…31) *4+发送buffer起始地址。
' p9 q; B7 `* `8 i; u3 k- N5 ]. O# B# A

( G9 P# R% u& P6 t( p$ f0 ]6 r, r' K
        2)、发送FIFO6 R& [; D# z7 z5 U3 d

! ~) G* ~% f' F0 J  Z  ?2 z4 V        发送FIFO中存储的消息是先从获取索引TXFQS[TFGI] 引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送FIFO为空。发送FIFO可按消息写入发送FIFO的顺序发送来自不同发送buffer但消息ID相同的消息。FDCAN会计算获取索引和放入索引之差作为发送FIFO空闲级别TXFQS[TFFL],用于指示可用(空闲)的发送 FIFO 元素数。
$ t/ M6 U( a# G" h* o; ~7 K0 t        新的发送消息必须写入以放入索引 TXFQS[TFQPI] 引用的发送buffer开始的发送FIFO中。 添加请求会将放入索引增加到下一空闲发送FIFO元素。放入索引达到获取索引后,会指示发送FIFO已满(TXFQS[TFQF]=“1”)。在这种情况下,下一条消息已发送且获取索引已递增之前,不应继续向发送FIFO写入消息。
1 d* W, C* c8 V% A$ O: c# d( E7 B: R, g* W0 }5 j
20191127160804244.png
4 |7 g; J) {% N' U' |6 L
4 `4 Z; I- g5 I$ J
        发送FIFO其实就是个环形队列,放入索引是队头,获取索引是队尾,队头和队尾之间保存着消息,相减当然就是待发送消息个数。当从发送FIFO取出数据,获取索引会自加,自加到等于放入索引时,表示发送FIFO为空。当放入数据到发送FIFO,放入索引自加,当绕了一圈自加到等于获取索引时,表示发送FIFO满了。
5 J( H* _. }! G6 _9 g2 s. I6 W$ Y% E" _, {+ C, Y
        如果有一条消息添加到发送FIFO,则会通过向与发送FIFO放入索引引用的发送buffer相关的TXBAR位写入“1”来请求消息的发送。4 z- O+ x7 d$ b0 Q7 P3 r. d
        如果有多条 (n条) 消息添加到发送FIFO,则会写入以放入索引开始的n个连续发送buffer中。 随后会通过TXBAR请求发送。放入索引随后会循环递增n。请求的发送buffer数不应超过发送FIFO空闲级别指示的空闲发送buffer数。
, v" w2 `0 Y/ M. [# ]% b) b# F5 a9 m        如果获取索引引用的发送buffer的发送请求取消,获取索引会增加到下一个具有挂起发送请求的发送buffer,并会重新计算发送FIFO空闲级别。如果取消对其他任何发送buffer的发送,获取索引和FIFO空闲级别保持不变。
, e  e: S3 ?0 Q( q9 c/ y$ L        发送FIFO元素会在消息RAM中分配4个32位字。因此下一可用(空闲)发送FIFO 缓冲区的起始地址是:* V* G, a# m# E3 F9 x

0 X- m0 R) E/ z放入索引 TXFQS[TFQPI] (0…31)的值*4+发送buffer起始地址。
) O  @/ O9 v( G- d4 ]  o2 [) r, r% Z2 Q' f3 k! }
        3)、发送队列
  j8 u9 x* A3 o# L- n# u; M        发送队列中存储的消息是先从消 息ID最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。
$ A7 `. O$ E! }        新消息必须写入放入索引 TXFQS[TFQPI] 引用的发送buffer中(放入索引 TXFQS[TFQPI] 只是队列头的数字)。添加请求会将放入索引循环增加到下一空闲发送buffer。如果发送队列已满(TXFQS[TFQF]=“1”),则放入索引无效,并且在至少有一个请求的消息已发出或挂起的发送请求已取消之前,不应继续向发送队列写入消息。% q# Y" o- m) L% b$ F  V5 I* ^# G
        应用可使用寄存器 TXBRP来代替放入索引,并可将消息放入任何没有挂起传输请求的发送缓冲区中。: V' g! s1 ^: z4 L
        发送队列缓冲区会在消息 RAM 中分配四个 32 位字。因此下一可用(空闲)发送队列缓冲区 的起始地址是:
3 P5 m9 D* k) e  K  @* B6 C' u! Q' r: b) V; ?6 a
发送队列放入索引 TXFQS[TFQPI] (0…31) 的值*4+发送buffer的起始地址。
% M+ B: U' m8 z# d6 |2 x. n$ N! g! D! `; C+ Z
        因此可以知道专用发送buffer、发送FIFO、发送队列的区别是对放入其中的多条消息的发送顺序不同:
+ `! t0 |" Y! ]" i* C( L' ]/ c7 R: o
# E  I$ i! I) q        1)、发送buffer全部配置为专用发送buffer
( c0 B  r( h8 o' o1 Z; O) o0 r% j$ d* G' B9 a
        每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
- O8 u; j' M  Q. a6 S
( M, B( Z+ o' z        2)、混合专用发送buffer和发送FIFO
% @; p" K& P0 v% z' g1 T, K% y
! @% Y" X" T% \% _        在这种情况下,消息RAM中的发送buffer部分会被划分为一组专用发送buffer和一个发送FIFO。专用发送buffer的数量是通过 TXBC[NDTB] 配置的。分配给发送FIFO的发送buffer数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送buffer。. _# B8 ^% x% ?; a$ s" C
( w% H% v* r$ ~% B% |4 _
20191127162943182.png

8 N- T( o4 l+ p. o$ {! T! t+ G7 q8 R! |
        发送优先次序:
- j% T6 X% f: H) w" XA、扫描专用发送缓冲区和时间最久的挂起发送FIFO缓冲区(TXFS[TFGI] 引用的缓冲区)
1 x( P# q* d  D# z, ?4 @B、消息ID最小的缓冲区优先级最高,下次将发送该缓冲区的数据6 ]7 g- R0 P0 R1 `0 x& [( B

* o: B5 K, a5 \. \        3)、混合专用发送buffer和发送队列
# D9 n+ Q! j; ]/ D% p; S6 e
) u8 r! b# }: m- c) D+ V" w- [; l        在这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队 列。专用发送缓冲区的数量是通过 TXBC[NDTB] 配置的。发送队列缓冲区的数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送缓冲区。
  x5 f2 X/ R5 w/ }) y) r7 K. W4 n% l9 t& |# }5 L6 ~; m& y* W* V
20191127163202212.png

+ w$ y* T& S& _) F6 d( {) [
; G0 ]2 Q  n% q# N) U% s% Q8 a4 s        发送优先级设置:  ?- G  X; x( [7 C9 f
A、扫描所有激活了发送请求的发送缓冲区
; O/ }2 Z2 a! D+ n0 i4 wB、消息 ID 最小的发送缓冲区优先级最高,下次将发送该缓冲区的数据$ g2 {- ?" b! k$ m8 U- B, n

, ]0 L; _4 c  d* k        再来介绍一下发送事件FIFO,它并不是发送FIFO,不是用来存储发送消息的,而是用来存储发送消息的状态的。6 ^# S9 S" m) f
2 `# n! N5 w0 @  g( i4 _- N
        FDCAN 在 CAN 总线上发送消息 后,消息 ID 和时间戳会存储在发送事件 FIFO 元素中。为了将发送事件关联到发送事件 FIFO 元素,已发送的发送缓冲区中的消息标志会被复制到发送事件 FIFO 元素中。' W8 S0 P! F+ `8 M$ |% F8 W
        发送事件 FIFO 最多可配置为 32 个元素。发送 FIFO 中介绍了发送事件 FIFO 元素。根据元素 大小 (TXESC) 的配置,会使用 2 到 16 个 32 位字 (Tn = 3 ..17) 来存储 CAN 消息数据字段。. f8 o  z  x6 ?* X  Y
        发送事件 FIFO 的用途是将处理发送状态信息与处理发送消息分开,也就是让发送缓冲区仅 保存要发送的消息,而将发送状态单独存储在发送事件 FIFO 中。这样做有很大的优势,尤 其是在处理动态管理的发送队列时,发送缓冲区可在发送成功后立即用于新消息。覆盖发送缓冲区之前,不需要保存该发送缓冲区的发送状态信息。
4 i3 z: m9 c4 K( d  Z7 o2 m  L* n' G5 u3 h4 m6 Q/ Q/ {" I
        为了防止发送事件FIFO溢出,发送事件FIFO仍然支持水印功能。# E1 l8 J, O& u7 I
9 c) c; K2 O7 ?; Z% _
        CAN发送消息的代码实现:
$ U6 U5 `$ U- z8 \/ n3 J- J
+ ?/ |) H6 p  b  Q- [        发送流程与接收流程刚好相反,只需要把消息按照TXBC.TBSA格式构建好,然后写入发送buffer,写进去后设置FDCAN_TXBAR寄存器的指定位为1来请求传输即可。如HAL库函数HAL_FDCAN_AddMessageToTxFifoQ:" A3 ?* D- q2 B6 t9 B- b  P

# }! C& N# I, o/ `6 L# g8 a
  1. PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> 16); //获取元素编号 1 ^: t7 \/ u  E. O! _
  2. FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex); //复制消息到Tx buffer 5 S. a; ^% u2 s; E! X7 Q# X
  3. hfdcan->Instance->TXBAR = (1 << PutIndex); //发出传输请求
复制代码

4 {& c& |( f* R" K9 z        发送buffer请求寄存器FDCAN_TXBAR,描述为:
9 y/ E; |# |) `4 w3 o3 r
' [7 B# O4 M9 `. J1 o

) w8 _1 \5 w" a7 ^$ x
- E% w6 _) l# {$ W: b8 S! \7 K        此寄存器用来设置FDCAN的哪个发送buffer可以发送数据,FDCAN有32个发送buffer,当把消息复制到这些buffer中后,就需要设置此寄存器来标记此buffer可以发送。
! w; J+ S* C5 J: J
1 E5 p# [  z! [
; ~8 ?; o0 g' H) L5 h$ ?6 a! P% Y  [; D# s) b' S
五、初始化
& v2 I0 V7 W! }1 N" }" |+ g, x
9 e+ \* F2 P+ w3 U        初始化可以直接使用HAL库,5 o# ~" o: [: m' N
, }  O: ~: S; ]) V
  1. u8 FDCAN1_Mode_Init(void)
    $ n6 Q) F( Z$ o7 Z
  2. {3 p+ X' i' O6 N
  3.     FDCAN_FilterTypeDef FDCAN1_RXFilter;
    7 _- O! Q% d: x' S" u

  4. 3 c* J7 P+ u+ ~1 o# b
  5.     HAL_FDCAN_DeInit(&FDCAN1_Handler);                              //先清除以前的设置/ h* d( P; z5 W! K
  6.     FDCAN1_Handler.Instance=FDCAN1;/ z( S+ r0 h' R7 F$ |& ^
  7.     FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC;            //传统模式! E& }1 e6 h; r% {
  8.     FDCAN1_Handler.Init.Mode=FDCAN_MODE_NORMAL;                     //正常模式
    0 X- h; w$ I4 [  h2 g- Z: c
  9.     FDCAN1_Handler.Init.AutoRetransmission=DISABLE;                 //关闭自动重传
    1 V2 X5 R1 `0 t
  10.     FDCAN1_Handler.Init.TransmitPause=DISABLE;                      //关闭传输暂停           
    / ~  I( p7 n: Z: y' L0 O
  11.     FDCAN1_Handler.Init.ProtocolException=DISABLE;                  //关闭协议异常处理
    * j& B5 Q! }$ L: E8 n
  12.         
    0 ]/ M7 E* ^6 M% M, l! I! P* R
  13.         //时钟为200M,baudrate=200M/(NominalTimeSeg1+NominalTimeSeg2+1)/NominalPrescaler,这里配置为1M
    6 U  d3 r5 M' Y/ k7 J8 _
  14.     FDCAN1_Handler.Init.NominalPrescaler=10;                        //分频系数
    1 c, D% B% h2 v6 V2 s7 Q
  15.     FDCAN1_Handler.Init.NominalSyncJumpWidth=8;                     //重新同步跳跃宽度: P) D/ e+ |5 q. B
  16.     FDCAN1_Handler.Init.NominalTimeSeg1=11;                         //tsg1范围:2~256" j# s. |# x" Y
  17.     FDCAN1_Handler.Init.NominalTimeSeg2=8;                          //tsg2范围:2~1281 ~9 K- O" S0 l+ Z' I
  18.         & m. }" U7 M. q' ?
  19.     FDCAN1_Handler.Init.MessageRAMOffset=0;                         //信息RAM偏移,10KB消息RAM共有2560字,故可以偏移0~2560* E  [: S' ?* r' v
  20.         //使用了多少个滤波器就要设置为多少
    5 a# e* W) [$ {  q; n$ K* k
  21.     FDCAN1_Handler.Init.StdFiltersNbr=3;                            //标准帧滤波器个数,0~1283 D4 _# K# [0 v6 R
  22.     FDCAN1_Handler.Init.ExtFiltersNbr=2;                            //扩展帧滤波器个数,0~64
    - h3 O; ~' g- b0 N2 k
  23.         
    8 E; _, B: |" k* B% r# b
  24.         //接收FIFO0、FIFO1和buffer配置,此处没有使用FIFO1故个数设置为0& x1 [  Y- U6 t: `
  25.     FDCAN1_Handler.Init.RxFifo0ElmtsNbr=64;                         //设置接收FIFO0元素个数,0-64
    5 ~: Q- Y/ Q  x0 c
  26.     FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO0元素的数据域大小:8字节        % p9 ^* J' K( I5 e8 Q( `: ]$ `
  27.     FDCAN1_Handler.Init.RxFifo1ElmtsNbr=0;                          //设置接收FIFO1元素个数,0-64' i$ |4 I* ^) b% y
  28.     FDCAN1_Handler.Init.RxFifo1ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO1元素的数据域大小:8字节                8 I$ U/ l: y0 y) F) O
  29.     FDCAN1_Handler.Init.RxBuffersNbr=64;                            //接收buffer元素个数,0~64
    ) n) A7 ]6 u' h6 U* e) l( @: \% b; D5 J
  30.         FDCAN1_Handler.Init.RxBufferSize=FDCAN_DATA_BYTES_8;            //接收buffer元素的数据域大小:8字节        5 I( ]& ]8 S! }3 V2 @9 B
  31.         0 ?5 ?7 S% _' C
  32.         //没有使用发送事件FIFO功能,故TxEventsNbr设置为0。把发送buffer全部作为专用发送buffer使用,故TxFifoQueueElmtsNbr设为0.8 W% H" Y" t# Q; D
  33.     FDCAN1_Handler.Init.TxEventsNbr=0;                              //发送事件FIFO元素个数,0~32/ _- ^2 d3 |7 C* U
  34.     FDCAN1_Handler.Init.TxBuffersNbr=32;                            //发送buffer元素个数,0~32& P# Z% A& A5 p1 A7 v. O
  35.     FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=0;                      //发送Buffer被用作发送FIFO/队列的元素个数,0~32( B4 @% M7 N1 D: j
  36.     FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION;    //发送FIFO模式选择,可以选择FIFO模式或队列模式
    ! a" ]6 Z" N% R! ~, G& S# Y
  37.     FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8;              //发送元素的数据域大小:8字节, x1 `) S9 w* z/ a& p0 ?
  38.         2 L4 W" N% y5 U" o
  39.     if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1;          //初始化FDCAN
    9 z  K/ [( i, c+ J5 w/ u) H

  40. 5 D% ^  P+ R5 T, ^! \% f! J, s. B
  41.     //配置RX滤波器,标准帧   
    / d3 G* N/ H  @4 S
  42.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    % A4 K% J* @& T+ y
  43.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    ( p7 [4 W- A; d+ ^* X' o
  44.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型! ], h$ \. j$ o+ s4 |- n" E/ U
  45.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  # z- q' [% {- ~5 p
  46.     FDCAN1_RXFilter.FilterID1=0x112;                                //11位ID
    4 D! I8 P' k+ L% p6 W! n& g; E
  47.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    / `9 D0 V- ^  I6 U/ j) T
  48.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    + V* s+ L% V( e: n- s

  49. # E; `. M2 r- a- @3 y% Z/ _
  50.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
      r0 ~; V! f  i6 e3 I
  51.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                   8 n3 C' Y/ f' u0 N. r! i. w0 i
  52.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    + d5 u( z# E4 Y
  53.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    , b/ m* W; b# e+ z$ T, e% ]* @4 U
  54.     FDCAN1_RXFilter.FilterID1=0x113;                                //11位ID
    & }. W; T; n3 U9 o# K, y9 _
  55.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    - `# L& q; e- y5 @! I: U1 \+ w/ F
  56.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    . S- J3 d# q! H! N
  57.         . Y. M3 Y  P, W0 V% ?% D+ x$ s
  58.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    5 [! E9 }( [3 u: T  D: h7 q
  59.     FDCAN1_RXFilter.FilterIndex=2;                                  //滤波器索引                   $ G6 J: h: \7 P' f6 C$ l, c
  60.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型1 {" m. B, K( s1 ~) N8 C- M4 D
  61.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    " f; m: w( ]* E) u* ]
  62.     FDCAN1_RXFilter.FilterID1=0x114;                                //11位ID
    ! `, n$ \: p. j
  63.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码+ @  l4 ?+ q5 b& j
  64.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化  r! I, c' }2 a
  65.         
    ) Z8 I* ^& Y( C  K( X! P
  66.         //配置RX滤波器,扩展帧。标准帧和扩展帧的滤波器索引是分开的   + D  A* k: ~6 }8 J
  67.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
    0 G: I, `! h1 p; j
  68.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    ; X, b; B3 _/ H* z
  69.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    5 v) ]1 [& H% Q# R6 B* n. @
  70.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  ( Z( h# j! ^7 }6 `: F! t8 }5 {
  71.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(2 << 12);                  //32位ID
    % y. i' h1 d( t, f- R3 W6 f5 Y7 \
  72.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码) u8 b7 ], C8 g
  73.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    & G4 t( E. H; T; W+ u5 @( \' }2 i

  74. $ `( U- c- E) V
  75.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID# E9 a  C* C) L5 a4 S9 ^% {# u
  76.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                   9 R$ E: h4 ~9 Z: T2 u9 W2 @* H
  77.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    ) ?, ^; ^9 x; j+ r5 t- t
  78.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  " z, I" Q. I# d2 B+ O% \  x
  79.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(3 << 12);                  //32位ID
    - [: _4 o" Z( o- ]- `2 a$ x
  80.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码
    4 f# t1 q  C% |6 D  D/ R0 A+ f
  81.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;    //滤波器初始化8 t( X( C" e4 L) ]' f
  82.         / r" r/ G/ g( ?) q9 Z4 `. C$ i
  83.         //滤除的消息直接丢弃
    . b* J- a$ N' d& V3 Y# J
  84.         HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);  //设置被滤除掉的消息的处理方式
    $ }& N4 @* h1 N7 D: t. j6 F4 ]
  85.         
    " D+ F4 I: e5 }, t, @6 O
  86.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);   //使能新消息接收中断
    " j! q3 `& B1 ?5 @! [( C! v" {
  87.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_TX_COMPLETE,0xffffffff);   //使能消息发送中断,0xffffffff表示所有的发送buffer都触发中断        . v, y) e1 w7 }2 t$ T9 M
  88.         
      j0 Z8 ~9 I* h  F; ]8 `
  89.     HAL_FDCAN_Start(&FDCAN1_Handler);                               //开启FDCAN4 p; K8 ]5 }1 ]/ w1 F, e  F- c
  90.     return 0;6 F4 M- L$ B4 F' R2 P) I% r* ?
  91. }
复制代码
# e# t/ w. |* g0 p

* {3 i, [/ ?+ _3 A- b六、CAN发送示例(来自正点原子)
* q+ n% i$ I% s* p( s" I$ B: X# ~0 F
  1. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)        + o$ T3 t( ^6 b" ~- r
  2. //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8                                    
    0 N$ P* _/ ]) J# K8 K
  3. //msg:数据指针,最大为8个字节.4 q) p; z. \$ x0 o4 _3 o  n$ L# Y
  4. //返回值:0,成功;
      k& T2 U# s" q& w2 k5 Q, s& O' E
  5. //                 其他,失败;
    " H- J" ]0 J% T6 h% n4 d  w" \
  6. u8 FDCAN1_Send_Msg(u8* msg,u32 len)
    + U% b" E9 S% ^& E0 p  T
  7. {        
    ; d4 O# \% X5 _
  8.     FDCAN1_TxHeader.Identifier=0x12;                           //32位ID7 \1 A8 F$ o  i: F( I. C1 ]! T
  9.     FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID- [) ~7 J, o0 Y; @/ F
  10.     FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧
    4 i' {) N2 |  F( t( R
  11.     FDCAN1_TxHeader.DataLength=len;                            //数据长度/ l* q: m9 `3 E, i+ h+ Y
  12.     FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;            5 V9 R+ a% T. Z& Z
  13.     FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换; u' B+ h6 R. f* L' ]8 ?
  14.     FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式) I8 k* s2 u3 ?* c
  15.     FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    $ L* o/ f' ]6 H
  16.     FDCAN1_TxHeader.MessageMarker=0;                           
    % @( ]# X: T# b/ Q' O: E( P2 _
  17. 1 ?8 `0 Z' I0 i: |3 S
  18.     if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//发送4 C8 u9 l0 d8 v" H* b  t
  19.     return 0;        
    ' n- \* a( Z' }& C
  20. }
复制代码

" {1 d+ y: W! X七、CAN接收示例(来自正点原子,因为滤波器被关联到FIFO0,因此消息只会放入到FIFO0)4 q, l0 p8 u( Q

8 e' M. k# z. ?! X8 `- @5 D( ^- Q
  1. //can口接收数据查询
    ; n: J/ p) y8 ?& O/ W
  2. //buf:数据缓存区;         
    # q# a3 e( F1 i! I5 E
  3. //返回值:0,无数据被收到;. l" j; P/ A+ t+ X$ S2 l. Q
  4. //                 其他,接收的数据长度;8 M1 W6 G" f- D" |2 C
  5. u8 FDCAN1_Receive_Msg(u8 *buf)
    . W8 b" M# u: l% Z5 s
  6. {        5 c# `, S6 z3 u
  7.     if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收数据
    4 \% r  I% R9 p+ G" q" I# K, `
  8.         return FDCAN1_RxHeader.DataLength>>16;        
    * @; P/ k4 l: F% f) e  {
  9. }
复制代码
+ w) M* _) v6 _' f$ K
参考:《正点原子》  STM32H7开发指南-HAL库版本_V1.0 (文档中有很多错误的地方,笔者被误导了好久,阅读的时候还是要以H7官方手册为准)
% p2 h4 Y. c" [" V5 B
# P, j# b  Y8 S* i& n$ b. m6 Z0 _! |4 F4 w1 o1 l+ N
收藏 评论0 发布时间:2021-12-22 14:00

举报

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