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

【经验分享】STM32H7的FDCAN

[复制链接]
STMCU小助手 发布时间:2021-12-22 14:00
一、介绍9 N- w/ u! v0 h! Y1 t7 o
, T7 e+ K9 L; ^+ Z1 D
        FDCAN(Flexible Data-Rate CAN)是CAN的升级版。特点包括:
3 w7 u: k  ^) |8 t1 v  u8 `
7 I0 K2 T4 L& ?: ~7 R5 ?5 R" {2 J. F( {       1、每帧数据段最大长度由8字节上升到64字节。1 p3 a4 L; O, `5 C$ {' O
; Q5 m- i$ @! D4 Y2 e
        2、速度由1Mbps上升到5Mbps,甚至还可以更高。在一个数据帧中仲裁段(ID和ACK)的速率和CAN一样最高1Mbps,这样可以保证总线的健壮可靠,但是数据段可以5Mbps甚至更高,一个数据帧中使用不同的波特率,这就是FD(Flexible Data-Rate)的由来。9 t  L4 M5 ?& a$ B# i

( E1 X4 N2 L- E        3、向下兼容CAN。
4 C, y3 {9 M' A  A0 R( Y& F$ ~$ A! l$ z5 R- Q
        H7的FDCAN包含2个可配置接收FIFO。多达64个专用接收buffer,多达32个专用发送buffer。可配置发送FIFO/队列,可配置发送事件FIFO。5 ?8 ~2 {0 W: v

4 x; u& g# F& t( W6 h9 x二、结构! c; @" u8 V7 g$ ?
8 f) G, X) s7 t9 b- q: m! }0 {- n
        先看结构框图:
) h- C- Y& u1 G
  P9 F& J7 R; L# ~  `7 {4 ^$ q, B
20191121162856859.png

7 a6 W! h# S7 V6 x. Q& y/ ]) O1 v7 @* v
1、两条中断线:fdcan_intr0_it和fdcan_intr1_it。可以通过FDCAN_ILE寄存器的 EINT0和 EINT1这两个位来使能或者关闭。
7 R& o$ j9 y, U* L( f- I4 U0 ]$ D8 z# e, @5 P+ X7 G
20191127102816991.png

. y* ^" \7 q1 B! r% e: I3 ^8 [. ~* A& i5 x
        可以通过FDCAN_ILS寄存器来选择FDCAN的中断是在fdcan_intr0_it上触发,还是在fdcan_intr1_it上触发,默认所有中断都在fdcan_intr0_it上触发,没有特殊的要求,只需要用一条中断线就可以了。/ }* C  U7 R$ T! Z; |  |
9 s) s! o4 s% F! J2 C
2、TX Handler:负责将消息RAM中的数据发送到CAN内核,最多可配置32个发送buffer进行发送。发送buffer可用作专用发送buffer、发送FIFO(发送队列的组成部分)或二者的组合。发送事件FIFO会将发送时间戳与相应的消息ID存储在一起,另外还支持取消发送。: V* b5 t/ t. V" y  Q0 z1 R
1 N+ _/ Z; a; A9 f! y
3、RX Handler:负责将CAN内核的数据传输到消息RAM,支持两个接收FIFO(每个FIFO的大小均可配置)以及最多64个专用接收buffer(用于存储所有通过验收过滤的消息)。专用接收buffer仅用于存储具有特定标识符的消息,与接收FIFO有所不同。每条消息均与其接收时间戳存储在一起。
4 A  G. \  c4 h* M: e3 w
9 g1 t9 X  o" c& D( f: ~# v/ k4、CAN core:CAN内核,读RX引脚数据处理后给RX Handler,接收TX Handler处理后控制TX引脚。
! b# s4 E  }1 e' e" [
9 \# H/ h* I: J& {5、Message RAM interface:消息RAM接口,外面连接着消息RAM。消息RAM是FDCAN的核心,本质是一段最大10KB的内存,把这段内存分成不同的区域,每个区域的作用不同,可以实现:过滤器、接收FIFO、接收buffer、发送事件FIFO、发送buffer。内存分配如下:7 @6 c$ i! U+ o5 t% e# h8 o9 U

. l+ K' x/ k( A: F# S
20191121164211703.png

0 T! g- a1 ^, O8 C! j9 q! r1 u
+ g/ J# f' R5 J+ ^( E        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 m# j5 M5 D& q. j) G0 B$ D; u% Q7 c2 \% n: B
        1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,最多可以有128个元素。; Y, l, c/ M- C: T! t, u
9 [6 h3 K) {. D0 n
        2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,最多可以有64个元素。(F1配置寄存器来设置过滤ID,H7直接划了个内存区来设置过滤ID)/ c/ T+ V1 b2 E% g' @7 [$ a8 g, J/ b; X

- Q/ N  P/ ~/ Y+ w        3)、RXF0C.F0SA:接收FIFO0,最多可以有64个元素,可以接收64条消息。
& o, d8 o9 V5 N5 a8 t4 e- l( q* I0 _- q6 K3 |) z3 x  Z
        4)、RXF1C.F1SA:接收FIFO1,最多可以有64个元素,可以接收64条消息。
  H$ V$ t; r1 r% Q# R: t, l& A( ]
        5)、RXBC.RBSA:接收buffer,最多可以有64个元素。
$ N% d/ \2 z$ a( u7 S# H: Z8 e6 B
        6)、TXEFC.EFSA:发送事件FIFO,最多可以有32个元素。(不是发送FIFO)% G0 J0 H9 M+ p' u

1 N5 y6 b' J9 i7 T+ C) [8 B        7)、TXBC.TBSA:发送buffer,最多可以有32个元素。$ F5 x7 c( v! B) a
/ A9 D; P+ ^! L7 }3 d4 d$ s
        8)、TMC.TMSA:触发存储器,最多可以有64个元素。- H& w2 F* I# m7 C7 }* E
3 }( L- p- f+ {& w' D
《注:这8个区域的元素个数和元素大小都是可以配置的,但是这8个区域的地址又是连续的。因此在初始化的时候,会根据每个区域的元素个数和大小来计算下一个区域的起始地址,并保存到相应的寄存器中》! v8 J0 K. {7 w' ?/ d
3 l1 f+ \6 F! Q! c- ^% v
        下面来详细介绍这几个功能区域:: `8 ^& E% e: D  S- _
7 n9 L5 G9 K) f0 T" W1 W: D/ s3 m
1)、SIDFC.FLSSA:这个区域用来存放11位过滤ID,有128个元素,每个元素占一个字,定义为:
5 T  \# G9 N8 ]3 T6 v
/ \0 l. M2 m% x5 m' h% D. o
20191121170625565.png

2 L% ^0 y0 G- I0 f  j6 J; u
$ E/ A- j9 \5 T7 `! Y5 q; Q9 {, hSFT[1:0](bit31:30):这两位用来表示过滤类型,一共有四种:
  h% z, D$ a) q' p$ }5 H    00:范围过滤,过滤到SFID1到SFID2中的所有信息。  A: i" _" `- ^: ?+ l( A5 h8 w
    01:双过滤,过滤到SFID1和SFID2中的信息。
8 P, g1 d/ Q& `% V/ L7 s    10:传统位过滤,SFID1 是过滤值,SFID2 是掩码。7 W2 T: E8 L4 U
    11:禁止过滤器元素* H" v+ I3 T- C- M# {# v5 j
SFEC[2:0](bit29:27):标准过滤配置
6 _, U4 ]6 D9 G3 r    000:禁止过滤器元素4 d8 i( V- E% t3 R* u& M: y$ i
    001:当过滤匹配以后存储在Rx FIFO0中。) @# N( G0 R& s
    010:当过滤匹配以后存储在Rx FIFO1中。/ P" O" T, E+ K, W% h7 T' ?
    011:当过滤匹配以后丢弃。8 h6 X4 d1 q( ~, H) f! F. _
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。' w+ I. q  w4 w5 ]. x2 Y  `
    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。, U' b& t7 T3 [# v5 N9 y3 K
    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。
5 B: g2 E  ~# q6 p6 z    111:存储到Rx buffer中或者作为debug消息,FDCAN SFT[1:0]忽略。
+ n: x0 f9 m( q5 O! x2 K" \% H. lSFID1[10:0](bit26:16):标准过滤ID1,第一个要过滤的ID。0 g* e! b: g+ j1 a
SFID2[15:10](bit15:10):标准过滤ID2,此位根据SFEC的配置不同而不同,当SFEC=001~110的时候此位域表示标准过滤ID。当SFEC=111的时候此位域表示Rx buffer或者debug消息。
3 o5 Y' m+ m& V1 X/ `0 J8 F$ e* v- {' y! E
SFID2[10:9](bit10:9):设置接收到的消息是存放在Rxbuffer中还是处理为debug消息的消息A、B或C。5 J7 E1 p6 ]! J6 R, U+ G1 K
    00:将消息存储在Rx Buffer中。
3 M8 }4 e  q! F1 ]
/ g3 N# ?6 p5 a( {) A. f' Z5 F    01:debug消息A。   
! W$ R* M0 T# H( `( d+ h1 v! e7 v+ n9 |3 R6 l0 L( o" S
    10:debug消息B。8 E4 b1 q% w0 Y- u9 q
& N) e, z: e. N& m- }# {6 K0 F
    11:debug消息C。
8 Q5 Z$ h. C! y* j) ?1 }
2 C; ]7 N! h* w: uSFID2[8:6](bit8:6):确定是否将滤波器事件引脚作为外部接口。
0 w1 b7 q9 h  y
; ^! U& w  f& F; oSFID2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer 的开始地址RXBC.RBSA的偏移。% u4 ~$ N4 f8 L: k/ z2 A
0 {# D$ S0 V; y+ {3 {9 v5 r
2)、XIDFC.FLESA:这个区域用来存放29位过滤ID,有64个元素,每个元素占2个字,定义为:
' X7 Q3 n* t/ N, F+ k* S5 G5 w5 b5 v, T9 Q9 F. Y0 P
20191121171836710.png
5 v% g4 k& y( m* W" `. G
. `0 B+ v. e& ~6 q& Q9 O" _! h8 m
F0 EFEC[2:0](bit31:29):扩展过滤配置2 ]8 Y  U1 M9 h
    000:禁止过滤器元素, J7 O3 ?- Z2 `" o
    001:当过滤匹配以后存储在Rx FIFO0中。/ e! i$ b9 N  i" b9 D
    010:当过滤匹配以后存储在Rx FIFO1中( J5 O% x8 p# |' E; ?  |5 G  L- a, R
    011:当过滤匹配以后丢弃。0 ^: i1 B9 y3 @
    100:当过滤匹配以后设置IR寄存器的HPM位,触发高优先级中断。
/ S' A$ k/ X8 M1 \. Y    101:当过滤匹配以后存储在Rx FIFO0中并设置IR寄存器的HPM位,触发高优先级中断。) a- z, ]9 O3 T/ Y
    110:当过滤匹配以后存储在Rx FIFO1中并设置IR寄存器的HPM位,触发高优先级中断。* m! @! ]9 W; |, x  I* }
    111:存储到Rx buffer中,EFT[1:0]忽略。, i) u' D! ]  @* }. |0 {3 S
F0 EFID1[28:0](bit28:0):扩展过滤ID1。
, l$ `2 H8 G9 }4 A6 {/ TF1 EFTI[1:0](bit31:30):扩展过滤类型
: @& |! _" ^; K. R    00:范围过滤,过滤到EF1ID到EF2ID中的所有信息。
$ _$ d$ u8 [; L* h4 c    01:双过滤,过滤到EF1ID和EF2ID中的信息。2 z# t) F; H, E. z) h( `! q
    10:传统位过滤,EF1ID 是过滤值,EF2ID 是掩码。
) h9 e3 l: f5 m    11:范围过滤,过滤到ED1ID到ED2ID中的所有信息,没有使用FDCAN XIDAM的掩码
1 H. J7 Y0 `. K4 \F1 EFID2[10:9](bit10:9):设置接收到的消息是存放在Rx buffer中还是处理为debug消息的消息A、B或C。
$ A1 A3 w$ Z, c; H! R    00将消息存储在Rx Buffer中。7 _& E" K) ]; \4 M
    01:debug消息A。* I0 B7 R' C! Z& K$ U6 _5 c' `$ ~  p* j
    10:debug消息B。+ k' }: d( G' C* T0 s; D. S6 V
    11:debug消息C.
' _' Y: c+ g+ e* x1 eF1 EFD2[8:6]bit8:6):确定是否将滤波器事件引脚作为外部接口。' {- O5 |* f: o# y5 N
F1EDIF2[5:0](bit5:0):定义当匹配以后存储消息的区域相对于Rx buffer的开始地址RXBC.RBSA的偏移。
) u0 P: N4 N4 q# t- l, d! e
2 ^. ^, L: }8 ]* J  C3)、RXF0C.F0SA、RXF1C.F1SA和 RXBC.RBSA分别为Rx FIFO0、Rx FIFO1、Rx buffer,它们都有64个元素,元素的大小根据数据长度不同而不同,范围为4-18字,它们的位定义相同:
" n5 k# z8 o8 @9 L' `8 k9 I- j- O8 C8 @. v* x$ p- D
20191121172451477.png
! J$ V. p- `8 T1 h- O* k

; n: q: _, t' y( gR0 ESI(bit31):错误状态标志) {+ U+ D4 p4 q8 k
    0:传输节点显性错误。1 F* w  A5 F7 {/ O4 v9 j0 v9 M2 B' o
    1:传输节点隐形错误' r3 w: V  Y( t5 e; Y" r: s2 F) U* Y
R0 XTD(bit30):标记是标准ID还是扩展ID
6 i. e4 V" i8 x8 G    0:11位标准ID
2 c% S& g, ^+ N  `; J. D
+ ~9 Q  @: R. a% x    1:29位扩展ID
/ k. Q$ p8 H2 d
4 ]# s( H7 z3 Q3 I' [R0 RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
7 M* j* [& i# z' K& W    0:接收到的帧是数据帧
! s8 q0 a8 F+ `/ n: ^, j
. \! P$ e" C0 b' z# H( }; f; B, Y4 E    1:接收到的帧是遥控帧# D* [, b/ u0 _& {- c* c6 p6 w( X+ Y! J
R0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。0 E" h1 M6 k" |$ G
R1 ANMF(bit31):3 g4 I3 ~" c% N2 d" L

1 Q& p6 G# k6 c, M) w' C    0:接收到的帧和FIDX中的过滤帧匹配+ Y2 L: z5 g" _9 H, a3 r
$ C3 [5 `% K1 R6 j
    1:接收到的帧和Rx滤波器中的任何元素都不匹配
! E% ^  A& v/ @8 M( u. k5 |R1 FIDX[6:0]bit30:24):过滤器索引,0~127,表示和Rx滤波器中的哪个元素匹配。
6 Y! W& q$ d& {  n( JR1 FDF(bit21):帧格式
5 n! s" d6 Z5 q$ W) Y2 s4 e- C    0:标准帧格式2 d( B( f  h; E" R$ ]& a6 c$ B
    1:FDCAN帧格式。8 U3 f0 S" {( t, Q: P4 I
R1 BRS(bit20):比特率切换/ e# D3 j: `! \; K" T
    0:接收到的帧没有比特率切换0 }( v8 C  @+ r3 }; k% I- r
9 V( \) H  p7 C" f4 P2 \
    1:接收到的帧带有比特率切换7 T9 S4 u/ v  F/ \6 b, u
R1 DLC[3:0](bit):数据长度。
$ ~" X' \4 c# L; ^    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。
* T2 y* w, \1 p; l    9-15:如果是传统CAN,接收帧长度为8字节。* E4 W# z: c, E5 o, E
    9-15:如果是 CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64 字节。
3 ~; Z; s  l! f  g% PR1 RXTS[15:0](bit15:0):接收时间戳。7 v/ I- y7 _5 k9 {5 e$ H" I
R2-Rn:接收到的数据。5 S4 Y5 S! K) C9 x. H3 F
3 q! I$ G1 h, x; _, Y: V
4)、TXEFC.EFSA:发送事件FIFO,有32个元素,每个元素两个字。7 g6 G  @% x2 _: o9 z6 @
( D3 q1 Q4 S1 ~: w, s7 g
20191121174147402.png

$ U7 g: Q8 b9 T2 r( T1 z3 K7 u
& g( h  o2 @: qE0 ESI (bit31): 错误状态标志
7 X5 p3 R/ O, W2 R. _8 Y% e- b( w7 j$ i% A  w
    0:传输节点显性错误
6 ^; \" M( M6 x7 `$ h$ p    1:传输节点隐形错误。
, ]% D" i9 C/ n0 o# u5 `E0 XTD(bit30):标记是标准D还是扩展ID
/ e: x3 Z- _& `3 M1 S. X( ~    0:11位标准ID.
5 z& d: |% k! C& Z& d! f    1:29位扩展ID. @# @. k: M/ B5 V+ a, G
' b7 k; o0 [" l8 Y
E0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。: W7 i$ z* |7 w  i7 h
    0:发送的帧是数据帧
' j3 \& \9 `: P, ^( f, }: I, H" J    1:发送到的帧是遥控帧
8 N4 O7 d( h  ?2 Z0 EE0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11 位ID还是29位ID。+ q+ t" o% r, L) P, L
E1 MM[7:0](bit31:24):消息掩码,从Tx buffer拷贝到Tx Event FIFO中。
/ E$ p8 t; L+ i8 qE1 EFC(bit23:22):事件类型( t( ?5 M- J! k
    00:保留。+ U% O) m/ S* z/ f* i
    01:发送事件。
# G- E! K" D" [* @/ ^5 n    10:发送取消。( e. ?8 ~) n0 Y
    11 :保留。" u8 q3 Z% \" s( u
E1 EDL(bit21):扩展数据长度
" {3 }& |, }8 C: u( e6 p" ?# \. ^    0:标准帧格式" C7 C& e% O* w- u( M
    1:FDCAN帧格式。3 B2 s5 b" c- m" |- O
E1 BRS(bit20):比特率切换+ u8 d$ d- ~# l6 O
    0:发送的帧没有比特率切换
# M  ^4 w; |  D- o
/ e* j$ P+ `2 J4 I    1:发送的帧带有比特率切换
3 h3 g7 k6 G8 T& X9 OE1 DLC[19:16](bit):数据长度。
- Z+ I2 I9 z5 t( A    0-8:传统CAN+CANFD,长度为0~8字节。
, j3 z* e1 H- q    9-15:长度为8字节。
) D0 D3 C* u8 s# F1 W( Z6 oE1 TXTS[15:0]bit15:0):时间戳。% f% m/ Q7 s& n: P1 C( s/ ^
) S9 ?. L" q, {
5)、TXBC.TBSA:发送buffer,有32个元素。9 F! D/ N/ r5 Y* ?. O! _8 _8 |
/ H' G6 Q" x, u4 f
20191121175121493.png

/ L2 a  m& B. @* Q; ]9 O3 }) N- g" _
T0 ESI(bit31):错误状态标志/ n& e- J' o$ T' `& z1 D9 L4 J
    0:CANFD帧中取决于被动错误标志。( L0 E3 u! Q8 w! N* c( z" x
    1:CANFD帧中隐形错误。2 L3 {0 W' z2 h3 a9 l$ T) m- F
T0 XTD(bit30):标记是标准ID还是扩展ID
7 L: Q& Q0 J; a+ Z( U    0:11位标准ID" c% C- b: s; y8 f
2 Y8 [6 E5 ?. Y' d
    1:29位扩展ID, N" c' ~: M$ Z8 o2 r2 S* Y

6 j. I( t1 z, a; Z1 FT0RTR(bit29):遥控传输请求,标记当前帧是数据帧还是遥控帧。
  M7 t2 m8 _+ v% J' M, I. E    0:发送的帧是数据帧
% ?0 H2 s9 ^  C    1:发送到的帧是遥控帧3 e" @: x9 z0 H6 r* f& M" A
T0 ID[28:0](bit28:0):帧ID,根据XTD位决定是11位ID还是29位ID。2 L$ w# G0 X( \: A9 Z
T1 MM[7:0](bit31:24):消息掩码,配置Tx buffer的时候由CPU写入。
" `+ |0 D, o1 RT1 EFC(bit23):事件FIFO控制
$ f; N4 X# g8 [. U3 }1 c( o. [4 c    0:不存储发送事件。
, s6 X: p: c9 H  d& P    1:存储发送事件。
" ]* `* m) k2 eT1 FDF(bit1):帧格式
! j4 y8 p) h( V: }# `; C    0:标准帧格式
% Q( q/ M5 Z. S  ?$ N0 _    1:FDCAN帧格式。
% n0 C8 l" N6 m, m( N" R- k* JT1 BRS(bit20):比特率切换
: d  `+ i+ b- s& V    0:发送的帧没有比特率切换/ v/ K- w* c  L3 o

8 Z  K6 {' @4 a1 U; F    1:发送的帧带有比特率切换
: G& H) O( }) q9 l$ ]& MT1 DLC[19:16](bit):数据长度。: a; Z* H& x7 |; I& V
    0-8:传统CAN+CAN FD,接收帧长度为0~8字节。0 i; w6 d; G! L
    9-15:传统CAN,接收帧长度为8字节。
# k& p8 Z3 F7 n/ U! M0 J; M! r    9-15:CAN FD模式的话表示接收到的长度12/16/20/24/32/48/64字节。' J, K4 g- e- V5 K" _
T2-Tn:发送的数据。+ s2 g- |# D; J3 i$ K+ U

. u  ?5 d. n2 M* B# R! P- [三、过滤器设置
* B6 \- H: ]$ n7 D$ k
6 g0 x  @/ l0 H( o        标准帧和扩展帧过滤器的设置分别往SIDFC.FLSSA和 XIDFC.FLESA区域写数据即可,下面以标准帧为例,标准帧过滤器共有3种过滤模式:
" J# a( r% |& J3 e+ t" D6 h: {& h/ T6 \+ k- K
        1、指定范围过滤7 u; k% _. R0 A) u
        通过SIDFC.FLSSA的SFID1和SFID2来设置需要过滤的ID范围,其中SFID2的值要大于SFID1,这样只有ID值在SFID1~SFID2之内的消息才能被接收到。比如我们现在要设置只接收ID在0X123~0X321范围内的消息,使用标准滤波器n,SIDFC.FLSSAn(n=0~128)的各个位设置如下:5 i; A; s0 g( l% J; ]

% c- M7 R) u+ S- p) C( O! r
  1. SIDFC.FLSSAn.SFT=0        //范围滤波
      e5 y" A" Q6 p4 M
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到RxFIFO中
    - x$ a3 c1 C7 }! J* s
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1
    % I/ O9 W  W: s! `: G/ I$ k6 |: Q
  4. SDIFC.FLSSAn.SFID2=0X321  //ID2
复制代码

$ W2 l" H2 k2 \2 A7 X7 |4 z4 Z        2、指定ID过滤6 t, h/ \$ s4 U1 Z; p. D

8 J& w3 g8 Y. i4 H& o5 O: \        我们也可以设置只接收指定的一个或者两个ID的消息,如果只接收指定的一个ID消息的话SFID1=SFID2。比如我们要设置只接收ID为0X123的消息,设置如下:
$ n0 c+ Z6 o. u0 h& K" ?5 F6 h. O5 e$ J& `! ]' i
  1. SIDFC.FLSSAn.SFT=1        //指定D过滤
      u1 }% B5 `) O
  2. SDIFC.FLSSAn.SFEC=1       //如果滤波匹配成功的话将消息保存到Rx FIFO中, W6 c0 }5 q* |3 S$ b3 v3 ?
  3. SDIFC.FLSSAn.SFID1=0x123  //ID1  e$ I6 d8 C2 G+ q
  4. SDIFC.FLSSAn.SFID2=0X123  //ID2
复制代码
+ n9 Z& }0 l; N( V2 t
        3、传统的位过滤3 _, J' ~6 q4 y
        第3种过滤模式就是以前STM32的CAN上存在的位过滤模式,在屏蔽位模式下,过滤消息D和过滤掩码一起工作决定接收哪些消息,其中SFID1为过滤的消息ID,SFID2 为过滤掩码。举个简单的例子,我们设置过滤器SIDFC.FLSSAn工作在:传统位过滤模式,然后设置如下:
, d$ Q! Z. g1 ^  V4 ~+ n0 X3 T$ v
  1. SIDFC.FLSSAn.SFT=2          //传统位过滤
    ; J8 R9 g+ f! s7 m
  2. SDIFC.FLSSAn.SFEC=1         //如果滤波匹配成功的话将消息保存到Rx FIFO中
    ! O( H' |( _9 s' S
  3. SDIFC.FL SSAn.SFID1=0xFF00  //ID1
    9 v* ^- f" x( I- Q
  4. SDIFC.FLSSAn.SFID2=0xF00    //掩码
复制代码
: ~2 x4 ]& {! k1 u- q
        其中SFID1是我们期望接收到的消息ID,我们希望最好接收到ID=0xFF00的消息。SFID2的0xF000规定了我们必须关心的ID,也就是接收到的消息ID其位[15:12]必须和SFID1中的位[15:12]完全一样,其他的位不关心。也即是说接收到的消息ID必须是0XxFxx这样的才算正确(x表示不关心)。
9 v% I0 ]& E5 W6 p* p
! V$ v" |, S5 \' R四、CAN的收发过程
: N% @+ f! M3 r, A0 M1 a! H( c3 \) [' j
        1、CAN接收过程
, C, {. ^* P# J& q( j. s& l; K0 @' c2 D# M  n
        CAN接收到消息后会进行过滤,过滤时会从SIDFC.FLSSA或XIDFC.FLESA区域的第0个元素开始匹配,直至符合过滤器中的某个元素的规则,则过滤完成,过滤完成的消息会按照过滤器元素的配置进行处理。比如过滤器元素的SFEC/EFEC位决定过滤后的消息是放入接收FIFO0、接收FIFO1还是专用的接收buffer中。
3 q2 `9 z+ Y) C; }) p6 m7 J0 ^% K. t" j9 r; c3 D
        接收FIFO 0 和接收FIFO 1 最多可分别保存64个元素。两个接收FIFO的配置是通过寄存器RXF0C和RXF1C完成的。% u1 o4 w4 \) X, A; L3 a. |" D. t

7 c5 q& t# \+ J5 r( ~/ F: |
20191127114550965.png

2 W+ n( J* m4 i% s4 b# Q' C" L* x% R$ i
        当IR寄存器的RFnF(n为0或1,代表接收FIFO0或接收FIFO1)指示接收FIFO已满条件时,在至少已读取一条消息且接收FIFO 获取索引递增之前,不会继续向相应的接收 FIFO 写入消息。如果在相应的接收 FIFO 已满时收到消息, 此消息会被丢弃,中断标志IR[RFnL]会置 1。也就是说,接收FIFO满了后会触发RFnF中断,如果继续接收,消息会被丢弃,并触发RFnL中断。
. G; G8 {$ F/ m, j0 h! |! G0 f! v' H3 Q8 O1 f
5 W1 y* H& J7 W; s, O$ \
20191127111235302.png
% i- ?7 _: I9 q) c" h

( \! D7 ^& q) A* q9 R/ s) v& L3 W3 N        为了避免接收FIFO溢出,可使用接收FIFO水印。当接收FIFO填充级别达到由RXFnC[FnWM] 配置的接收FIFO水印时,中断标志IR[RFnW]会置 1。比如接收FIFO0大小配置为64,水印值配置为60,当接收了60条消息时会触发水印中断,提前进行处理,这样就避免了FIFO溢出。
% S4 x4 E* I3 s& ~& u        读取消息就是直接从RXF0C.F0SAn或RXF1C.F1SAn(n为索引号 0~64)中读,消息的组成结构在上面已经说过了,比如HAL库HAL_FDCAN_GetRxMessage函数读数据过程(假定从FIFO0中读):* [3 P0 O) d9 [# ]' c) b

9 h, o. W; j' b
  1. /* Calculate Rx FIFO 0 element address */
    9 \( m! E* J4 C1 u% I
  2. GetIndex = ((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8);3 c; D, X/ I5 i
  3. RxAddress = (uint32_t *)(hfdcan->msgRam.RxFIFO0SA + (GetIndex * hfdcan->Init.RxFifo0ElmtSize * 4));
复制代码
  }! _$ r( A; W8 g& T
1)、((hfdcan->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8):作用是获得FIFO0状态寄存器FDCAN_RXF0S的bit[13:8],读这里可以知道接收到的数据保存在FIFO0中的第几个元素中,GetIndex的范围是0-63,刚好对应64个元素。当FIFO接收到一条消息,GetIndex会加一,当从FIFO中取出一条消息,GetIndex会减一。
! [3 @9 U, j; W% `
+ W  n: @/ Y5 p% e: h& w) w
2019112119095892.png

& a, g: U4 ^% D0 t: A. d) G( r# L- p, E& j! A! T8 M5 N5 L( e2 M  [
2)、hfdcan->msgRam.RxFIFO0SA:是RXF0C.F0SA区域的开始地址。
  o6 P3 X7 Z  {, y# P9 n6 b9 v' @4 ^1 Z) V9 q9 M" \
3)、hfdcan->Init.RxFifo0ElmtSize:是接收FIFO0的元素大小,根据数据长度不同而不同2 d$ G6 l% k5 l2 A, O4 [4 H5 e

" l5 w8 {$ V, i# p# P1 a' j
- P8 B1 C0 K( M5 |
+ a+ O& ]$ J! y' U, |2 I9 q) D# s7 M
如果消息长度是8个字节,那么算上固定的R0、R1,元素大小就是4个字。
, }2 v7 ]1 O3 S2 R: Q; l+ P
; Q/ R0 @  z4 v$ P7 l如果消息长度是64个字节,那么元素大小就是64/4+2=18个字。" m; \5 J5 ^1 X4 {( z. w; d- `' p7 G

( M8 a8 i/ E2 H6 v# w        计算出了元素在FIFO0中的地址,直接按数据结构读数据就可以了:2 y! `4 ]8 |5 s2 m8 p  h

0 f: O8 s' N7 j; E# g
  1. pRxHeader->IdType = *RxAddress & FDCAN_ELEMENT_MASK_XTD;7 J7 t& Y2 p8 C. k
  2. pRxHeader->Identifier = ((*RxAddress & FDCAN_ELEMENT_MASK_STDID) >> 18);$ ?' U0 V, Y, z) x
  3. pRxHeader->RxFrameType = (*RxAddress & FDCAN_ELEMENT_MASK_RTR);
    + M* |( v4 l9 y8 t  L5 R( I2 s
  4. pRxHeader->ErrorStateIndicator = (*RxAddress++ & FDCAN_ELEMENT_MASK_ESI);  //这里地址自加了一次( [- i7 c, X% t" G& C2 S
  5. pRxHeader->RxTimestamp = (*RxAddress & FDCAN_ELEMENT_MASK_TS);1 B4 R& W# D, w/ E7 y5 M. E7 K9 y
  6. pRxHeader->DataLength = (*RxAddress & FDCAN_ELEMENT_MASK_DLC);7 |+ C' R* Z# n, `
  7. pRxHeader->IsFilterMatchingFrame = ((*RxAddress++ & FDCAN_ELEMENT_MASK_ANMF) >> 31); //这里地址又自加了一次
    4 t+ M, j( P' D% m
  8. ......
    ' T: i, ?% Y: _
  9. pData = (uint8_t *)RxAddress;
    1 r" V3 h$ b0 N& \+ F# R" M- p. `9 S
  10. for(ByteCounter = 0; ByteCounter < DLCtoBytes[pRxHeader->DataLength >> 16]; ByteCounter++)6 H! u/ d/ I: U2 l
  11. {
    ; l' P7 F, H% u2 _/ t  N! e
  12.     *pRxData++ = *pData++;# z) q9 k! S( X* ]
  13. }
复制代码
) B, W8 H3 [' b7 f" J5 [. _
        2、CAN发送流程) r3 r4 ^* ]! [7 _4 [

# C9 B: L* r, t" v( }- `        在消息RAM中TXBC.TBSA是发送buffer,最多有32个元素。发送buffer可以配置为专用发送buffer和发送FIFO/队列。发送FIFO/队列是指要么是发送FIFO,要么是发送队列,即发送FIFO模式或发送队列模式,由TXBC[TFQM]决定:0 N! q- c1 x6 O' o+ i
2 j8 k6 Z8 V" ?1 ?4 R' P& j& u
20191127150042199.png

. T9 S3 \2 Z1 P5 P5 ?
1 u' E' l9 o% _) I2 ]/ L% X# V        因此发送buffer可以有三种组合:全部是专用发送buffer、专用发送buffer加发送FIFO、专用发送buffer加发送队列。
4 Q2 H* k/ R' H: z6 ]8 F$ J$ ?+ M" I: Q6 G8 X6 O
        下面来介绍一下专用发送buffer、发送FIFO、发送队列的情况:
) `1 j+ w$ O! h: E' P# ?, P) y' |/ W" |; N9 e3 ?4 V/ @2 B
        1)、专用发送buffer
2 Q* r  R6 U  @9 M( y4 p3 y
9 |5 {1 l$ c3 y, ^) z         专用发送buffer可完全在CPU的控制下发送消息。每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
0 ?) m# z/ t0 A        如果数据部分已更新,则会通过添加请求的TXBAR[ARn] 位请求发送。请求的消息在内部会与发送FIFO/队列中的消息进行仲裁,在外部会与CAN总线上的消息进行仲裁, 并会根据其消息ID发送出去。
/ [2 V! u) V+ ^; N5 y: ]
& `" E7 o# `* l8 E
20191122101555794.png

7 @* H( z0 T! C; X# d0 y7 r7 Y8 A3 L' O5 |9 T2 P3 W6 l
        专用发送buffer会在消息RAM中分配四个32位字(元素大小为4个字)。因此消息RAM中专用发送buffer的起始地址是:- A9 ?. E/ j4 d) h6 o/ m1 W! l' f

! N4 G' z3 t& W发送buffer索引 (0…31) *4+发送buffer起始地址。( k% C+ Y5 I2 I6 Z( u: T: T% T
) s! S5 |1 f6 R8 q

8 S+ T8 z7 ?/ U- F2 X. Z  _% X7 d
        2)、发送FIFO
$ a+ D" k+ x- q! T" ?/ a$ e3 ~0 G( l
        发送FIFO中存储的消息是先从获取索引TXFQS[TFGI] 引用的消息开始发送的。每次发送后,获取索引会循环递增,直至发送FIFO为空。发送FIFO可按消息写入发送FIFO的顺序发送来自不同发送buffer但消息ID相同的消息。FDCAN会计算获取索引和放入索引之差作为发送FIFO空闲级别TXFQS[TFFL],用于指示可用(空闲)的发送 FIFO 元素数。
: v, }  T: S$ d# F9 d) Y        新的发送消息必须写入以放入索引 TXFQS[TFQPI] 引用的发送buffer开始的发送FIFO中。 添加请求会将放入索引增加到下一空闲发送FIFO元素。放入索引达到获取索引后,会指示发送FIFO已满(TXFQS[TFQF]=“1”)。在这种情况下,下一条消息已发送且获取索引已递增之前,不应继续向发送FIFO写入消息。: s' ]7 c, S: @( ~$ ~/ U$ |! H
5 P8 p7 S( M' Y/ U0 \5 j
20191127160804244.png

* A0 z# @, S; B( a* [9 V, G% Q( T% o5 [0 A  k, K* v
        发送FIFO其实就是个环形队列,放入索引是队头,获取索引是队尾,队头和队尾之间保存着消息,相减当然就是待发送消息个数。当从发送FIFO取出数据,获取索引会自加,自加到等于放入索引时,表示发送FIFO为空。当放入数据到发送FIFO,放入索引自加,当绕了一圈自加到等于获取索引时,表示发送FIFO满了。
) [: L* g' t# g7 t" J
7 i8 K, z5 m. I* K5 M. \/ J        如果有一条消息添加到发送FIFO,则会通过向与发送FIFO放入索引引用的发送buffer相关的TXBAR位写入“1”来请求消息的发送。  C' h- \- c& S$ r) s( l2 l
        如果有多条 (n条) 消息添加到发送FIFO,则会写入以放入索引开始的n个连续发送buffer中。 随后会通过TXBAR请求发送。放入索引随后会循环递增n。请求的发送buffer数不应超过发送FIFO空闲级别指示的空闲发送buffer数。' z4 Q6 K5 ?2 ]
        如果获取索引引用的发送buffer的发送请求取消,获取索引会增加到下一个具有挂起发送请求的发送buffer,并会重新计算发送FIFO空闲级别。如果取消对其他任何发送buffer的发送,获取索引和FIFO空闲级别保持不变。
0 }) p& u2 T, L  x; S! p; `        发送FIFO元素会在消息RAM中分配4个32位字。因此下一可用(空闲)发送FIFO 缓冲区的起始地址是:
. ?/ H; t6 V$ N3 U! n2 w
$ v* A" I, g4 i9 A0 r放入索引 TXFQS[TFQPI] (0…31)的值*4+发送buffer起始地址。( b& e: C5 e( I; d- l

5 ?1 F! ]- B) `; r' u. |- h        3)、发送队列+ A# Z+ P  F/ Q
        发送队列中存储的消息是先从消 息ID最小(优先级最高)的消息开始发送的。如果多个队列缓冲区配置为使用同一消息 ID,则会先发送缓冲区编号最小的队列缓冲区。% G/ {$ f) L6 {: _. [4 C* T8 @4 {/ v
        新消息必须写入放入索引 TXFQS[TFQPI] 引用的发送buffer中(放入索引 TXFQS[TFQPI] 只是队列头的数字)。添加请求会将放入索引循环增加到下一空闲发送buffer。如果发送队列已满(TXFQS[TFQF]=“1”),则放入索引无效,并且在至少有一个请求的消息已发出或挂起的发送请求已取消之前,不应继续向发送队列写入消息。
8 g7 S1 p! {3 n' u# u  f, ]        应用可使用寄存器 TXBRP来代替放入索引,并可将消息放入任何没有挂起传输请求的发送缓冲区中。1 g. E" I& h, ]/ m1 t8 |
        发送队列缓冲区会在消息 RAM 中分配四个 32 位字。因此下一可用(空闲)发送队列缓冲区 的起始地址是:
7 o' r, `, y/ ^3 l0 a* v' X
& [) y, e6 A2 f2 [0 }4 k发送队列放入索引 TXFQS[TFQPI] (0…31) 的值*4+发送buffer的起始地址。( Y' F/ S0 T2 g4 r# F  W/ ?! j8 l

8 @+ Q) L  Z; S3 `  k6 I2 u- Y# Z        因此可以知道专用发送buffer、发送FIFO、发送队列的区别是对放入其中的多条消息的发送顺序不同:
8 ^3 E) e* c0 Y; R; T  j" y: r3 O, }
        1)、发送buffer全部配置为专用发送buffer' i6 s" `; G0 O' ]7 I' ~' B% z

1 x6 D* ~1 k8 j9 q        每个专用发送buffer都配置了特定的消息ID。如果多个发送buffer配置为使用同一消息ID,则会先发送buffer编号最小的发送buffer中的消息。
7 ^/ f& @/ h/ Y  P* e. s4 B8 Z7 [9 V$ a' F7 A7 P/ b  k: G
        2)、混合专用发送buffer和发送FIFO& M. t, S4 u7 d3 L
) |- h; H/ I: q* G$ C* m$ c
        在这种情况下,消息RAM中的发送buffer部分会被划分为一组专用发送buffer和一个发送FIFO。专用发送buffer的数量是通过 TXBC[NDTB] 配置的。分配给发送FIFO的发送buffer数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送buffer。8 u6 g6 Q0 o8 j# [" r

  o7 K9 K) p6 O6 R: {: u
20191127162943182.png
% x9 G* |) b1 E* [
# z" I4 Q5 h7 t0 d) k" m
        发送优先次序:
. x3 \) @( q! H: X7 M! \( _4 q5 ~A、扫描专用发送缓冲区和时间最久的挂起发送FIFO缓冲区(TXFS[TFGI] 引用的缓冲区), q2 ^0 F; x5 j" L/ B/ R
B、消息ID最小的缓冲区优先级最高,下次将发送该缓冲区的数据
) O3 e" @9 l+ C: x+ W% m: ]; U. Z7 l
        3)、混合专用发送buffer和发送队列- x) B* J5 [+ ^
: k; Y* \, b- A0 F; O  w) ^  ]
        在这种情况下,消息 RAM 中的发送缓冲区会被划分为一组专用发送缓冲区和一个发送队 列。专用发送缓冲区的数量是通过 TXBC[NDTB] 配置的。发送队列缓冲区的数量是通过 TXBC[TFQS] 配置的。如果 TXBC[TFQS] 编程为 0,则仅会使用专用发送缓冲区。
: @4 ^% i# Z* h' b# e; |: p+ @2 S- j$ L7 h1 q$ W
20191127163202212.png
% \: m/ {- I& d3 S" ]* X

) ?+ E4 o) I8 R3 n. C2 G2 j( @        发送优先级设置:. o( ~( F  ]: L
A、扫描所有激活了发送请求的发送缓冲区
7 E% a$ V! B4 f) p+ M" EB、消息 ID 最小的发送缓冲区优先级最高,下次将发送该缓冲区的数据
# I$ X( D5 |- ]7 ^8 v$ O6 ~6 [2 U9 O; t# w) I5 q1 d; q. K
        再来介绍一下发送事件FIFO,它并不是发送FIFO,不是用来存储发送消息的,而是用来存储发送消息的状态的。
+ m+ g0 J+ w$ M! l' b
4 u8 q7 r6 C1 ^& k2 j  w' d        FDCAN 在 CAN 总线上发送消息 后,消息 ID 和时间戳会存储在发送事件 FIFO 元素中。为了将发送事件关联到发送事件 FIFO 元素,已发送的发送缓冲区中的消息标志会被复制到发送事件 FIFO 元素中。
2 M9 v  E1 L9 u. I  ]! P        发送事件 FIFO 最多可配置为 32 个元素。发送 FIFO 中介绍了发送事件 FIFO 元素。根据元素 大小 (TXESC) 的配置,会使用 2 到 16 个 32 位字 (Tn = 3 ..17) 来存储 CAN 消息数据字段。
0 R3 Q- _2 t* N, k& y6 I7 K& k        发送事件 FIFO 的用途是将处理发送状态信息与处理发送消息分开,也就是让发送缓冲区仅 保存要发送的消息,而将发送状态单独存储在发送事件 FIFO 中。这样做有很大的优势,尤 其是在处理动态管理的发送队列时,发送缓冲区可在发送成功后立即用于新消息。覆盖发送缓冲区之前,不需要保存该发送缓冲区的发送状态信息。
* ~7 q  C4 W  C% ?" K  n6 i; |( b6 t7 c+ I
        为了防止发送事件FIFO溢出,发送事件FIFO仍然支持水印功能。
8 U# t2 ?4 i. W2 m1 M) {6 U. l7 h7 C9 D) V8 J
        CAN发送消息的代码实现:
; Y% P9 E7 t+ k' s- a8 A; p' r) l2 C* n! f) {% L% x4 Z# U& T
        发送流程与接收流程刚好相反,只需要把消息按照TXBC.TBSA格式构建好,然后写入发送buffer,写进去后设置FDCAN_TXBAR寄存器的指定位为1来请求传输即可。如HAL库函数HAL_FDCAN_AddMessageToTxFifoQ:
7 |+ P2 b( L- e. c9 p! t1 n6 ?- k1 [  x4 _
  1. PutIndex = ((hfdcan->Instance->TXFQS & FDCAN_TXFQS_TFQPI) >> 16); //获取元素编号
    6 P9 F# R4 A8 c* C& T5 I: R
  2. FDCAN_CopyMessageToRAM(hfdcan, pTxHeader, pTxData, PutIndex); //复制消息到Tx buffer
    / {0 F; K7 a) Z+ h6 x: _0 T
  3. hfdcan->Instance->TXBAR = (1 << PutIndex); //发出传输请求
复制代码
% r  E$ k  i) F- m
        发送buffer请求寄存器FDCAN_TXBAR,描述为:8 ^" l, r; G: P

2 X' i' d+ R7 w" ^$ E/ e) t
! G4 K% s: ]4 O1 U* I% H: d: H9 G
8 ^9 c: m4 V1 c) {
        此寄存器用来设置FDCAN的哪个发送buffer可以发送数据,FDCAN有32个发送buffer,当把消息复制到这些buffer中后,就需要设置此寄存器来标记此buffer可以发送。  ]: C" ~7 a( R0 p" o9 ]! X
; D/ x- f3 k- J7 d. B1 I/ A7 n2 h
2 h! d$ R8 d8 M, f- X
# y2 G5 u6 x2 Z, X
五、初始化0 u3 p6 z, }# W6 V# r, }$ ^3 \( _

, A+ H6 V1 X, q' K        初始化可以直接使用HAL库,
& ?/ R+ M) c+ R' d+ Z% K
8 y, I7 O6 L7 H# {( r/ [
  1. u8 FDCAN1_Mode_Init(void)5 s# K. C8 ~8 \2 I/ s% v; }* d# c
  2. {/ @2 P# y$ M8 M* d) S' d3 s2 v
  3.     FDCAN_FilterTypeDef FDCAN1_RXFilter;' G  |/ N+ y3 W: B4 e, m! }
  4. ) t! b  V- K3 j. Y1 J
  5.     HAL_FDCAN_DeInit(&FDCAN1_Handler);                              //先清除以前的设置
    3 ?8 G2 K. J9 r, s' j: W$ [2 [
  6.     FDCAN1_Handler.Instance=FDCAN1;6 x4 l/ Z/ }0 o4 k- F
  7.     FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC;            //传统模式
    ( ^, H. H: Y6 X: E: U7 O8 _
  8.     FDCAN1_Handler.Init.Mode=FDCAN_MODE_NORMAL;                     //正常模式( V% H$ S" ^4 C& I7 i8 h
  9.     FDCAN1_Handler.Init.AutoRetransmission=DISABLE;                 //关闭自动重传
    $ ^4 h2 k1 w2 t" _  \- k! M
  10.     FDCAN1_Handler.Init.TransmitPause=DISABLE;                      //关闭传输暂停           
    1 K0 \& P9 H6 ]7 M  {
  11.     FDCAN1_Handler.Init.ProtocolException=DISABLE;                  //关闭协议异常处理
    + C8 J* z$ T% V4 c/ P+ M
  12.         
    ! A/ ]! B  L  u" m: v
  13.         //时钟为200M,baudrate=200M/(NominalTimeSeg1+NominalTimeSeg2+1)/NominalPrescaler,这里配置为1M+ T* l) r/ W2 q/ [- l' w  E
  14.     FDCAN1_Handler.Init.NominalPrescaler=10;                        //分频系数1 D- v1 f6 B1 k% {
  15.     FDCAN1_Handler.Init.NominalSyncJumpWidth=8;                     //重新同步跳跃宽度$ p1 A! h' N& f, d0 D
  16.     FDCAN1_Handler.Init.NominalTimeSeg1=11;                         //tsg1范围:2~256
    ( j% C8 ?% D$ t3 m9 V7 Y
  17.     FDCAN1_Handler.Init.NominalTimeSeg2=8;                          //tsg2范围:2~1287 \, J7 l1 ]) w
  18.         ! ~3 [# C' o6 F8 e" d( V; N6 B( e
  19.     FDCAN1_Handler.Init.MessageRAMOffset=0;                         //信息RAM偏移,10KB消息RAM共有2560字,故可以偏移0~2560
    , _0 Y$ x3 k7 _0 Q
  20.         //使用了多少个滤波器就要设置为多少1 A! I, C0 y* B5 l! r& [" v8 S  H5 m
  21.     FDCAN1_Handler.Init.StdFiltersNbr=3;                            //标准帧滤波器个数,0~128
    ; ?. I- a! c, |
  22.     FDCAN1_Handler.Init.ExtFiltersNbr=2;                            //扩展帧滤波器个数,0~64) B8 M/ B& U9 C+ o1 \% W
  23.         
    3 F% }* t) r/ d- d0 _8 o& R, b
  24.         //接收FIFO0、FIFO1和buffer配置,此处没有使用FIFO1故个数设置为0, u8 L! z  Y( X+ M3 \  m
  25.     FDCAN1_Handler.Init.RxFifo0ElmtsNbr=64;                         //设置接收FIFO0元素个数,0-64+ I8 U: A. O3 i( Z$ m+ _
  26.     FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO0元素的数据域大小:8字节        
    ( ], X7 B+ m% p5 H2 e
  27.     FDCAN1_Handler.Init.RxFifo1ElmtsNbr=0;                          //设置接收FIFO1元素个数,0-64% T% I+ i7 S( X7 W4 s1 h
  28.     FDCAN1_Handler.Init.RxFifo1ElmtSize=FDCAN_DATA_BYTES_8;         //接收FIFO1元素的数据域大小:8字节               
    3 X' {# x& Z, ?) U
  29.     FDCAN1_Handler.Init.RxBuffersNbr=64;                            //接收buffer元素个数,0~64. `& W" _! W) e( a* ]% g
  30.         FDCAN1_Handler.Init.RxBufferSize=FDCAN_DATA_BYTES_8;            //接收buffer元素的数据域大小:8字节        
    5 Y2 q+ x* F$ z
  31.         
    ( {5 ^7 D' b5 h% y
  32.         //没有使用发送事件FIFO功能,故TxEventsNbr设置为0。把发送buffer全部作为专用发送buffer使用,故TxFifoQueueElmtsNbr设为0.
    1 S( \5 u( A1 S6 a
  33.     FDCAN1_Handler.Init.TxEventsNbr=0;                              //发送事件FIFO元素个数,0~32$ Y' Q( N3 s4 Q, o3 `' D5 _1 h' f
  34.     FDCAN1_Handler.Init.TxBuffersNbr=32;                            //发送buffer元素个数,0~32
    9 C0 d: N, v1 q; ^
  35.     FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=0;                      //发送Buffer被用作发送FIFO/队列的元素个数,0~32
    . x5 s# g3 O! `) e
  36.     FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION;    //发送FIFO模式选择,可以选择FIFO模式或队列模式
    " P2 W2 C! {0 V  {6 ?; e
  37.     FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8;              //发送元素的数据域大小:8字节
    + v- d* c1 e9 B2 N9 w6 V
  38.         
    & s7 B: {8 O( Y% v
  39.     if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1;          //初始化FDCAN' V& W; W8 J5 A

  40. ' a' S$ R: R4 a; d
  41.     //配置RX滤波器,标准帧   & M7 w9 |: ^7 t7 w
  42.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    6 {6 R6 Q) P2 g' @  J
  43.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                  
    . E3 S9 f6 k2 e/ X  e
  44.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    " R! f0 x3 ?, f0 f1 l
  45.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
      d# a2 J1 D( n& I- U) j9 `
  46.     FDCAN1_RXFilter.FilterID1=0x112;                                //11位ID
    6 i1 I9 g. P/ u" X* x# Y; g( W* Q
  47.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    9 X) f+ r6 `3 A$ T4 H
  48.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化4 j; n, y( D  e! {' u
  49. + Y5 N" m! Y+ J! H# h
  50.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    $ [2 J4 o  D) ^' ?6 @
  51.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                  
    % {% s- r/ I. D; t$ _
  52.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    / F5 @8 ?$ K+ w; j9 J
  53.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    - c6 {" `5 V+ C2 M/ {& [4 Q
  54.     FDCAN1_RXFilter.FilterID1=0x113;                                //11位ID
    " \/ w9 Z8 J$ t
  55.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    5 @: ]# e6 T; S: G- y4 w
  56.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
    + c( I7 m# m0 [% g2 g; u+ t1 o
  57.         
    7 v$ F! b2 I6 Z1 E5 ~! d9 {
  58.     FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID;                       //标准ID
    1 n; ?' S# l# V3 d
  59.     FDCAN1_RXFilter.FilterIndex=2;                                  //滤波器索引                  
    9 o) ?5 D# e- \1 T( r4 c" s
  60.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    8 |, T: [, P6 y/ D4 |$ ~
  61.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
    6 u1 q6 t8 P- g9 I) V* i+ C" o& F
  62.     FDCAN1_RXFilter.FilterID1=0x114;                                //11位ID
    2 O- C# F0 a8 P5 g  x$ \9 ?$ c3 C3 ]
  63.     FDCAN1_RXFilter.FilterID2=0x7FF;                                //11位掩码
    5 ]- S6 n# Y6 s* D8 E) n, M
  64.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化% V' e" K" d$ L- B& G
  65.         5 x/ e+ @4 l3 y' M
  66.         //配置RX滤波器,扩展帧。标准帧和扩展帧的滤波器索引是分开的   
    3 n# c' e% j, R4 Y2 K' u
  67.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID8 I& h$ K- w' o% `
  68.     FDCAN1_RXFilter.FilterIndex=0;                                  //滤波器索引                   " z% g1 c$ Q4 o! L/ `) a2 o/ G
  69.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    , E5 y, m( j( U9 s6 s5 h, I$ ^
  70.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  
      c6 M( J2 |) I2 @
  71.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(2 << 12);                  //32位ID9 p8 ~+ S7 L3 F9 W/ D! l' {
  72.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码) A4 p% s4 L. {
  73.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化3 U1 p) W" G/ D* K' N" [3 A
  74. 9 ~6 K% ^$ ?. F* ^
  75.     FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID;                       //扩展ID
    $ O# n/ P- b0 X; C2 C" u
  76.     FDCAN1_RXFilter.FilterIndex=1;                                  //滤波器索引                  
    * c  H1 d3 D0 j, Q
  77.     FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK;                   //滤波器类型
    0 ~) C4 n- `# ~: p" o7 |/ d, d
  78.     FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0;           //过滤器0关联到FIFO0  8 {# @& @7 a7 R) C
  79.     FDCAN1_RXFilter.FilterID1=(1 << 20)|(3 << 12);                  //32位ID- c/ q5 E0 z5 l% [
  80.     FDCAN1_RXFilter.FilterID2=0x1FFFF000;                           //32位掩码3 t, v5 k: A* B6 L% t. C4 k
  81.     if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;    //滤波器初始化/ t; r( ^" N6 }! U( z1 ?
  82.         
    % m# W0 O  U* [, @* L
  83.         //滤除的消息直接丢弃
    2 j. H, M0 G( ?3 G  Q! _. \
  84.         HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler,FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE);  //设置被滤除掉的消息的处理方式
    ; D  k0 u" I* x* U; c
  85.         : f5 ^  ~& A4 \5 a% _$ E
  86.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);   //使能新消息接收中断
    0 P! u6 S+ ^% U0 v+ y5 v/ [7 k$ y
  87.         HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_TX_COMPLETE,0xffffffff);   //使能消息发送中断,0xffffffff表示所有的发送buffer都触发中断        : \8 C2 W$ j4 f/ z+ `
  88.         . d  F# q  r) Q) Y$ \4 |
  89.     HAL_FDCAN_Start(&FDCAN1_Handler);                               //开启FDCAN8 E+ V. o$ g& k# e
  90.     return 0;
    5 o) ?3 D# f1 M& z: x6 d2 h
  91. }
复制代码
+ w: o5 y! r" k, S$ r! Z
9 m4 Q! U0 u( g: [; J* I
六、CAN发送示例(来自正点原子)
: `) H4 L- b$ r6 E  }% E5 n! C( r6 s% V
  1. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)        
    + Q0 S: R) a& }
  2. //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8                                    
    $ A* w% F( g1 e$ ^: Z
  3. //msg:数据指针,最大为8个字节.
    ' ?& y% Z! j- P9 h' q
  4. //返回值:0,成功;
      a% ?% {2 h/ O
  5. //                 其他,失败;
    " {: T& W: T  {4 r  \, k& w6 V
  6. u8 FDCAN1_Send_Msg(u8* msg,u32 len)
    4 L4 w" d  Q, E- m  ~3 V
  7. {        - @, w3 c3 G, G9 U$ J/ \+ ~
  8.     FDCAN1_TxHeader.Identifier=0x12;                           //32位ID
    5 n! j- X9 r+ U; \0 }. S  _
  9.     FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID;                  //标准ID* s: v3 V$ {8 n, H8 ~
  10.     FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME;              //数据帧9 X0 d4 P( c  C, x6 u
  11.     FDCAN1_TxHeader.DataLength=len;                            //数据长度
    4 N* G' T0 V: w  `
  12.     FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;              l; y2 i, W) M' P
  13.     FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF;               //关闭速率切换" [8 x- A' S7 k* z% m  z3 k
  14.     FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN;                //传统的CAN模式6 w! S+ d6 Z' \/ a+ E
  15.     FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS;     //无发送事件
    8 z, x9 L3 c- e+ ~: |  H2 l" i, f6 \
  16.     FDCAN1_TxHeader.MessageMarker=0;                           ) O0 n/ \+ d  d

  17. ( j& E  E. Y, F, d) c
  18.     if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//发送
    2 a4 R6 N. c, `3 j4 Z1 V0 ]
  19.     return 0;        
    % b3 W5 i  Y2 Q( }6 ?9 \
  20. }
复制代码
3 O& T% N' m$ Q7 |3 J) A  `; \1 E
七、CAN接收示例(来自正点原子,因为滤波器被关联到FIFO0,因此消息只会放入到FIFO0)( U7 w3 o/ C% _: C  B

+ j0 W1 c7 F3 \) ?2 G: o8 L
  1. //can口接收数据查询
    . b7 ?0 H8 O( G7 c0 t
  2. //buf:数据缓存区;         
    ; D7 R) C, |1 P$ f8 _; F
  3. //返回值:0,无数据被收到;' \  a' W6 x* P# ]$ }
  4. //                 其他,接收的数据长度;
    & v1 {) ^3 R( {: B/ ~; E
  5. u8 FDCAN1_Receive_Msg(u8 *buf), m# [7 k" ~8 B0 j3 R3 h
  6. {        
    ' P. z, P. N' i4 F- j$ D, O4 U
  7.     if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收数据* P) L% ?& D  p$ F/ H! o1 n
  8.         return FDCAN1_RxHeader.DataLength>>16;        
    ' `. p$ S) L" f) H% s
  9. }
复制代码
  E( Q) D1 H; m3 }5 k: {# L, S
参考:《正点原子》  STM32H7开发指南-HAL库版本_V1.0 (文档中有很多错误的地方,笔者被误导了好久,阅读的时候还是要以H7官方手册为准): R. x' _  T( G3 d+ b

! g. E, D( v& j% f- `$ D
- U* x  V( Q1 @7 ?( F, _8 X0 |
赞 收藏 评论0 发布时间:2021-12-22 14:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版