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

【经验分享】STM32G474 CANFD 用例详解

[复制链接]
STMCU小助手 发布时间:2021-11-11 22:00
本篇用起来, 连接关系如下:
! g- l0 Q0 P& m) O8 Y
0 _+ @7 V( d* K: Z" ]9 k4 E- n

20210222185812381.png

3 Y, ~# p+ P$ k; ~

) ?& D1 r8 v4 f" h2 k% m# l( i& GCAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.2 J; N/ U  D+ Y/ d2 x
- _8 q/ ?5 [$ D/ g7 B& ]
STM32工程搭建
  \! L# o) ~0 T2 [6 ?# E' Q6 xSTM32CubeMX配置步骤如下:7 {* E- T2 H) Q" J2 H! }  U) n: y& @

1 F- r) K1 o" e( P9 \1 mMCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
) o1 ?# r/ Y+ N; C6 Y3 }* J; V+ J# S, E( T; o
调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
" q! T; f8 L2 u" v
* B9 p+ n! O5 V5 D) ]) RPinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator  U, v5 a# e6 q" b4 }

/ @; Y: a/ T& d- t9 L5 N' H0 x7 \5 d; bClock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):' `+ g1 r$ U# R1 g8 ]( j

20210222185828575.png


) r7 T! |! O* r4 A: A& ?5 O

20210222195952515.png

1 X: n" ]; r9 n7 L1 U

7 k1 a2 {9 t4 _# b3 n开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:" i. O# E8 n2 f- F& r& r( `
! u" E, B! M- ~- j

20210222185846781.png

8 p2 u( O. A# s5 Q2 u( B5 H, |9 I

, d$ b3 E' C% ^/ c5 X

20210222185905935.png


5 a, J7 W7 h1 x/ g9 b' ^0 ^8 S  P1 a: w7 e4 q' d  {
LPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:
& N, G" O8 |4 p; m
, m) |  n0 C/ D) G- d* @

20210222185926920.png


& Y/ R/ A3 I( a0 I3 @$ v! Q+ F: i* k0 {' }
FDCAN1配置: Pinout & Configuration -> Connectivity -> FDCAN1, Mode选择FD, Frame Format设置FD mode with BirRate Switshing启用位速率变换, Auto Retransmission设置为Enable开启自动重传, Trasmit Pause设置为Enable开启传输暂停, 速率和采样点设置参考上一篇 STM32 CANFD 基础知识的位时间和采样点小节, Nominal仲裁段设置500Kbit/s(160M/NPre/(1+NTSeg1+NTSeg2) = 160M/4/(1+63+16) = 500Kbit/s), 采样点0.8((1+NTSeg1)/(1+NTSeg1+NTSeg2)=64/80=0.8); Data数据段设置为2Mbit/s((160M/DPre/(1+DTSeg1+DTSeg2) = 160M/4/(1+63+16) = 500Kbit/s)), 采样点0.75((1+DTSeg1)/(1+DTSeg1+DTSeg2)=15/20=0.75), Std Filter Nbr标准帧过滤器数量直接设为最大28, Ext Filters Nbr扩展帧滤波器数量直接设为最大8(虽然后面并没有全用上), 勾选FDCAN1 interrupt 0中断, 引脚也从默认调整到板子上用的引脚PD0/PD1:
# j# M! p/ u$ |: ]7 f. Y8 B. |8 _
9 _) R3 o0 R4 l5 [  o  S

20210222185949803.png

) i1 G7 {  s( p4 L9 p. _) N% P! V
; N$ h" u2 j  r. N

20210222190005173.png

9 \$ B7 a4 V% ^# R
4 x4 K9 V7 a1 }: k) h
FDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:
  V& Q( J! V" n7 D, g7 r  R2 k9 f# V/ S9 G$ l

20210222190054536.png


7 c6 N3 t+ p0 a
8 S# b5 }, Q4 m; g. N' EProject Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点.
! G3 Q9 }5 R, v; A+ @7 C; ?9 c% E! \- g  a+ Q. a7 i( Y
Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral
- I4 ?& b( U3 c9 a" t" a2 Z+ K1 g  |. R+ l
点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.# ~. B" Q1 I3 @& L

# P% }' M" \# wKeil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:3 i& g" Y! ~# d4 A* U, C

3 r  B" z3 T  V3 p8 j2 i9 wFlash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.7 t3 ~/ Z8 z5 V, I6 P0 q
Pack选项卡, 去掉默认的Enable勾选' F  ]' K* S; f1 p
到此配置结束. 下面是手动添加的代码详解
7 Q& j/ ]2 D) h# V+ u# _
' N3 {# j# c( M8 X* g! o& E9 j串口配置5 f3 s  c9 z* I. y; U
为 LPUART1 添加printf支持:( \& A8 ?) E. S

7 ~0 t1 T5 w: ^* S( T& y! ?
  1. #include <stdio.h>1 S0 L4 l$ O3 _0 h- F, l

  2. $ X0 c  e1 a/ f& B8 t8 R. ~" @
  3. #ifdef __GNUC__
    # _8 M4 P2 k4 e- d1 O) m
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    - N% \/ \# w- U* q6 G0 d
  5. #else
    9 S' h2 @, I* H' W5 [2 |
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    0 o5 `" b. v, \% n$ \. ^* [
  7. #endif /* __GNUC__ */) F0 T3 g5 C4 o4 |

  8. 7 n3 t9 e2 Q# S4 q9 a' U
  9. PUTCHAR_PROTOTYPE
    3 H- N, }/ q0 v* J8 \* A: m
  10. {
    6 q; f' J  M0 B2 f, S# G  N
  11.   HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
    ' M0 p& \4 k- C1 A4 X
  12.   return ch;
复制代码
+ l& D$ S2 \/ W, a- {5 f
100us定时器
$ N- n5 q3 [/ j' a! ]( i+ e因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.1 r4 @% F* a/ J$ |
1 E. o3 l5 Z  ^! i+ n
  1. /* USER CODE BEGIN 2 */
    ( ^. R, H- J1 e8 L7 x; u
  2. HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.
    2 B# [+ B0 j' P& Q
  3. /* USER CODE END 2 */
    7 I( n# m6 s. ~6 O4 A/ g

  4. 5 ^% f6 N# c3 w( U7 o" }
  5. uint8_t tim6_flag = 0;
    6 l$ P: ]- G! f1 w' }
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) , t4 d; [4 N4 z  T0 q
  7. {; B9 d. v3 B5 c' H7 y& K
  8.     if(htim->Instance == TIM6) {$ |! Y: e! w+ L2 m9 p1 q( X+ ~
  9.         tim6_flag = 1;% @' N! ^  L3 Y
  10.     }
    % U1 L0 q! h) @* \. i+ L3 q/ w
  11. }
复制代码

2 z7 S; g' p. x4 r8 I* ~FDCAN配置
) ~; S0 `: S( H. |主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.% m/ |+ _5 A7 z- y+ f6 F' q- C% g" {
0 q% |( F# ?9 w% Q
  1. FDCAN_FilterTypeDef sFilterConfig1;
    7 U; m. L, h( a8 X
  2. . B1 C& p' {3 v1 b; v
  3. void fdcan1_config(void)
    ) ]7 n( e; U1 ^/ S3 W
  4. {
    ' e0 I. ?  O& K  z
  5.   sFilterConfig1.IdType = FDCAN_STANDARD_ID;
    - L0 E# `+ E$ t; b' o4 I
  6.   sFilterConfig1.FilterIndex = 0;2 ^' u8 e& J' j7 u& T7 o
  7.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;  Q4 b! g6 H' r
  8.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;3 }& V- ^# t; i6 Y" F, B
  9.   sFilterConfig1.FilterID1 = 0x00;1 k  g. C) }- f7 I
  10.   sFilterConfig1.FilterID2 = 0x7FF;
    5 c2 v. X1 m0 J2 _: \
  11.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)) @) z) z2 w5 U; E( R. a' M3 e
  12.   {$ l) y! ?3 p0 Z  F
  13.     Error_Handler();4 |* A$ {2 ?! L, \
  14.   }
    - O) v. F, j) R0 D

  15. 1 [/ Q' J7 f9 w2 S: O7 D
  16.   sFilterConfig1.IdType = FDCAN_EXTENDED_ID;
    : M5 f. ]: R( F2 W2 ?: ?3 _. t
  17.   sFilterConfig1.FilterIndex = 0;1 e3 u1 r' p- \( G" E
  18.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
    % L' I5 I* H" Q# F% P
  19.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;. Q0 L, w: I/ }( c; u1 O, ?6 B+ E' V
  20.   sFilterConfig1.FilterID1 = 0x00;
    ' j( b% G# c+ ?" d: l: Z: i
  21.   sFilterConfig1.FilterID2 = 0x1FFFFFFF;
    1 _$ K1 I& V! U; v% x
  22.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)  x2 r  u0 x" y' e9 G+ n4 f
  23.   {
    $ B1 J+ c$ C5 d9 T
  24.     Error_Handler();
    , K3 z( s% g. ?: G6 j& C1 [
  25.   }
    5 U% [0 X6 H( A2 j* M0 I& r
  26. * ]" ~, A  N* d) ?  o" K
  27.   /* Configure global filter on both FDCAN instances:
    $ d( C4 c6 }5 d; K( X  u
  28.   Filter all remote frames with STD and EXT ID
    ; M8 ~' E- v& V+ c& L: [8 j& M8 Y
  29.   Reject non matching frames with STD ID and EXT ID */
    , n1 L8 v9 I# Q# U8 ]: p8 q
  30.   if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
    5 S4 s: W$ {3 @
  31.   {- V! W( k, Y0 ], }6 f* b$ _) S
  32.     Error_Handler();& p' q& U. i9 q7 Y4 m
  33.   }2 \0 t3 G! N! V( ]7 R7 d' g$ ]

  34. 9 ~  n4 p. o: f) Z/ e5 F: i4 t6 F9 \
  35.   /* Activate Rx FIFO 0 new message notification on both FDCAN instances */9 Z! v$ K7 e5 u
  36.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)6 ~3 n8 O$ Q0 @9 T
  37.   {
    - A8 ~1 d( h3 ~7 ?$ T" _" f: r
  38.     Error_Handler();0 m# _4 {8 b; v( b
  39.   }
    , p* R, O. \% C8 R2 |1 ]
  40. $ [/ j7 B% f3 Z( @! L  x3 j- x* _
  41.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
    * v( i( U+ Y, _$ R4 v  _4 v
  42.   {
    4 Z' p* V7 \4 _1 Y! X
  43.     Error_Handler();& ?2 h% z+ D1 n
  44.   }1 [; P& U" F& A- M& b7 `2 `

  45. + j0 X; O# z8 w8 P, t4 g
  46.   /* Configure and enable Tx Delay Compensation, required for BRS mode.
      ~0 Z1 s* E+ d- y* [, K
  47.         TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler* Q$ C$ |. r7 W5 l& ?. _3 C
  48.         TdcFilter default recommended value: 0 */$ \, g! W$ L/ d- ~; Z/ c. I
  49.   HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);) @# ]4 e. i! t" c+ p" R1 @
  50.   HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);( ~0 [. L7 c6 z/ L# l: `
  51. . {! r- E- U% M. R$ }! |" a) d' y
  52.   HAL_FDCAN_Start(&hfdcan1);5 Z/ U4 W) e( m5 S, X
  53. }
复制代码
5 F: z( P, H) q. X% S( c: T
这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:
3 G8 n+ a* J/ M2 b2 P1 `* b3 o8 T
  1.   sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
    $ q  V5 o# r9 ^8 s
  2.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    ' |1 F. N/ J$ d) h; \7 W
  3.   sFilterConfig1.FilterID1 = 0;' j3 H2 f/ z' l% g+ z1 Q) \
  4.   sFilterConfig1.FilterID2 = 0;
复制代码

0 B3 g- a1 \+ ~" t用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.8 r+ s8 P- i$ f3 T
# {1 p" j6 t4 v& K, ^% _. g
有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:
/ ?- @0 I  |7 }. z3 R2 _! T8 V$ @  I  k
  1. #define SRAMCAN_FLE_NBR                  ( 8U)         /* Max. Filter List Extended Number      */
复制代码

% B, K) K/ s4 A5 s! P! L& K9 {2 @FDCAN2, FDCAN3的配置和FDCAN1类似.
8 T( y# \) E4 t# v4 C: U
" i' F0 M! |7 o5 S7 T! FBus-Off处理7 y, r  e) O% I" z
如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:6 f" _7 o! k. R! N. E: E6 X

% i; h5 i* [  e0 m( S
  1. void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)7 Y% |3 D* {* h( @% f1 W0 Y
  2. {
    ( T0 m# Q9 U+ b$ j7 G* f
  3.   //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);7 O% q& C* M2 U7 ?; v
  4.   if(hfdcan->Instance == FDCAN1) {
    & o7 F! f: ^' t# n( x2 f  g7 A* W
  5.     MX_FDCAN1_Init();/ w) x3 r0 I# g+ K7 d
  6.     fdcan1_config();
    3 [' m9 i4 k, D: `8 d# [
  7.   } else if(hfdcan->Instance == FDCAN2) {
    ' d$ U& v' D1 K: T* a; [
  8.     MX_FDCAN2_Init();! B/ n  H% g) X4 B  T5 t1 Q8 g2 w: y
  9.     fdcan2_config();  D5 D, R2 b* L4 ~  H8 h
  10.   } else if(hfdcan->Instance == FDCAN3) {
    : Y1 Y  z: I8 F9 |* |
  11.     MX_FDCAN3_Init();* k3 R  `5 d4 G6 T
  12.     fdcan3_config();. w, s! q' e3 a& x( z* x& @2 h& ]
  13.   } else {
    & D9 n! J1 \$ p# X: U
  14.   }
    5 P" J* {, d+ I3 H- Q
  15. }
复制代码

2 v# \* H& q& u2 E新消息接收处理2 D7 J" d: ?/ P: x* ~
直接把接收的消息通过2M波特率的串口打印出来.3 q3 T+ H+ y* k6 Y5 L( t
' K# l; A+ g+ H; o2 }
  1. FDCAN_RxHeaderTypeDef RxHeader1;( o; P+ @! }7 P7 }* j6 V
  2. FDCAN_RxHeaderTypeDef RxHeader2;
    # J: O' W4 D5 V1 X
  3. FDCAN_RxHeaderTypeDef RxHeader3;
    9 C, \  k' e' @% q
  4. 4 C' C$ R! l: q2 Y' U( B5 }
  5. //RxHeader1.DataLength => can_dlc
    ' s+ ~& @7 \: s0 g% c8 |1 }( ~" R! k) `  E
  6. //0x00000 => 0 ; S6 [: B* T- Z6 y
  7. //0x10000 => 1
    7 p) k! J' H/ I. L
  8. //0x20000 => 2
    % j/ A( a' N8 S
  9. //0x30000 => 3 ( \0 w  p# m# Y9 S
  10. //0x40000 => 4
    ' I* f/ o' N, r; e9 p; K0 L; }
  11. //0x50000 => 5 : D+ ^: ~. `  I  {. n
  12. //0x60000 => 6   \$ t& N& v2 s4 s
  13. //0x70000 => 7
    - t* k' O3 R& z8 i0 t# o. O" G
  14. //0x80000 => 8 , Q) ]2 h3 X( W$ \4 X7 ~* q# V
  15. //0x90000 => 12& G5 o- |; K4 }8 @% x7 ?& v
  16. //0xA0000 => 16: l/ {8 y7 u3 k
  17. //0xB0000 => 20
    7 R9 h: E) Q+ k' _
  18. //0xC0000 => 24; J4 _/ i; N  U5 o( ?) p+ j2 _8 R8 t
  19. //0xD0000 => 32( A% b& r6 `6 y3 P8 x
  20. //0xE0000 => 487 ]/ N" U. o7 z5 m, [+ S+ t
  21. //0xF0000 => 644 |8 M, w- C; E+ R! u; X( ]0 N& R
  22. uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
    ) s& W" H# s' W# C
  23. uint8_t can_dlc2len(uint32_t RxHeader_DataLength)
    ( B- X- p; |0 ~0 X! s0 d, L$ `
  24. {
    * G+ b7 _6 m, Y- s3 m: d* \* S
  25.   return dlc2len[RxHeader_DataLength>>16];( s, K. W1 E( y2 m. S) I% A0 v7 e) t
  26. }5 n! f3 L2 {7 [9 h
  27. 4 x6 e; A; j7 d$ W
  28. uint8_t cnt = 0;' L8 b$ C" v0 t3 a) E/ a6 i
  29. uint8_t brs[] = {'-', 'B'};4 V4 W& @- Q4 H7 i- G7 ?) q! k
  30. uint8_t esi[] = {'-', 'E'};: |# X) \. N3 K" ?. I% a; H
  31. void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
    3 A6 Z7 c  j. K; l: h" B- h
  32. {- X( Q  [4 T7 f, U" S
  33.   if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {
    " |, @- g( m4 f' j" E
  34.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);* N3 ?- T9 j* \+ A4 q* m
  35.     //RxHeader2.Identifier++;+ |3 d8 x8 |" j: L' v
  36.     //fdcan2_transmit(RxHeader2.Identifier, RxData2);
    * ~' D6 q0 i* k: r' i& |/ |2 E* U
  37. ) c' ^+ X/ C; l. K+ ]& A) `2 l+ w
  38.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    / `' b' {6 `* d" x
  39.     //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));
    + [2 M2 g' _* z7 @

  40. ! m7 S9 Z* c& u: |
  41.     HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);: F5 v0 b1 ^4 `. _9 S8 J$ C
  42.     if (hfdcan->Instance == FDCAN1) {% e8 g8 Q& \  f  p, G
  43.                 printf("fdcan1, ");
    6 ?0 @3 m; y) B% c
  44.         } else if (hfdcan->Instance == FDCAN2) {
    + S( b( U+ B) s# S/ H
  45.                 printf("fdcan2, ");3 K4 C4 t8 ]1 K) ]+ r  a9 T
  46.         } else if (hfdcan->Instance == FDCAN3) {3 q: H. w& j" h8 i% q
  47.                 printf("fdcan3, ");
    ' I4 h+ _! J8 R* B6 g8 R
  48.         }# I7 r& m  `! C
  49.     printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier,
    : K/ [6 a7 Q( z5 n
  50.                                   can_dlc2len(RxHeader1.DataLength),
    ) ?9 J: H( y) l. |, r
  51.                                   brs[RxHeader1.BitRateSwitch>>20 & 0x1],
    1 c) U: c' K' s4 F# E! g- g
  52.                                   esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);
    * H% b3 x, t( z" u, F5 x  h
  53.     for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {
    0 X* A# W# _. t" y. ]( Y4 l# {
  54.       printf(" %02X", RxData1[cnt]);
    2 C. ]: u, b& f
  55.     }* O* [1 I' G" L3 H
  56.     printf("\n\r");
    2 L& ?% }5 l5 V$ Z! z
  57. ) ]) G2 s9 {& A  J
  58. . ?, B/ [7 S% B* m- @+ Z+ u
  59.     //if (hfdcan->Instance == FDCAN1) {
    ( w% t$ z. i+ l+ n' R7 f
  60.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    2 a2 g% n7 q  s: D" V2 ~
  61.     //  //echo$ Q. F/ L! r+ l1 V; e7 r  n
  62.     //  RxHeader1.Identifier++;
    ; @1 o8 s" p: x' g# _3 B& L
  63.     //  fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);
    1 {, G+ z1 a2 R" u; U
  64.     //} else if(hfdcan->Instance == FDCAN2) {
    . n  O5 l4 E4 h
  65.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    * J% g6 I* h4 q
  66.     //  //echo
    2 _. |; u( \2 R
  67.     //  RxHeader2.Identifier++;/ G* X6 J" \) L7 P6 u* J' B
  68.     //  fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);
    - i# S1 q7 @* u- r' a) n4 t
  69.     //} else if(hfdcan->Instance == FDCAN3) {
    0 b9 s2 i& r% @7 L+ @: v; m" E
  70.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);
    & l: k9 h% |9 K' X5 Z: R. L
  71.     //  //echo2 o3 \0 N; a& W  a. i# ]- |
  72.     //  RxHeader3.Identifier++;
    # ^/ K- @5 d0 L" F
  73.     //  fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);  R+ `1 s3 }  O
  74.     //} else {/ `* D4 r2 e. v! p& |8 J, p) N* ~
  75.     //  % {& Q9 C2 X- D$ X( H$ G3 T
  76.     //}7 m  z, n) P1 P7 v
  77.   }
    $ {& L9 k0 _8 h, J
  78. }
复制代码

) v/ a0 y  w# g4 E% c2 t注意注释中 RxHeader.DataLength => can_dlc 的对应关系.7 k6 d' Z" {! b

% w  I! F- u+ |& C" [6 U. n1 C示例如图:
1 l  W9 p7 r' R4 |
: X  Q; ~6 w' z; F
20210222190024669.png

8 C+ c# e& M& L- E, _1 }  T+ m1 n7 G3 m0 I8 D/ b" R% U( x2 ]
图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据., T  o" U6 X, X
" b+ n  O3 n$ W3 C/ V$ p$ L
printf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.) M/ I# ?& B+ h8 \& z2 I. ]$ G
, e5 u! t* m0 h8 A
发送处理
  ]6 F; l# A/ \+ O发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.
, X" d" W* N# }9 E
0 F9 r5 T  t9 R) `& j6 {
  1. #include <string.h>) X) I; D4 w" I

  2. * c( Y& M7 z2 j
  3. FDCAN_TxHeaderTypeDef TxHeader1;, ?7 ?% V; V0 O6 i+ U! c+ y
  4. FDCAN_TxHeaderTypeDef TxHeader2;( \4 L. M2 {2 K
  5. FDCAN_TxHeaderTypeDef TxHeader3;
    0 g8 w0 D, z5 W
  6. 1 |( ~% _! T4 S! N7 ?7 J1 Q) g* z) k
  7. typedef struct {- X6 h" j1 t# W3 q
  8.   uint8_t flag;# P% T0 r3 M9 F& M0 w: P
  9.   FDCAN_TxHeaderTypeDef TxHeader;* y. K4 C) l9 l" l
  10.   uint8_t TxData[64];
    + H1 E( B9 @4 a5 f7 x8 k( {4 Z1 ^
  11. } FDCAN_SendFailTypeDef;! I; [* J8 _# a, X: ?; F0 `
  12. 4 }- W* `3 I2 v# ]
  13. FDCAN_SendFailTypeDef fdcan1_send_fail = {0};8 Q8 f5 M, F5 h5 ?3 i4 A2 \' ?0 E
  14. FDCAN_SendFailTypeDef fdcan2_send_fail = {0};
    : J5 D# M! Z; {  |
  15. FDCAN_SendFailTypeDef fdcan3_send_fail = {0};
    6 [$ @* S/ Y" w. c

  16.   u( S3 }9 F$ @# f
  17. void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
    2 p3 l& v8 X, S: j) Y% }% X
  18. {
    , n5 b6 r! v$ W9 j
  19.   TxHeader1.Identifier = can_id;
      h5 J" d% @3 i, z  Z. b
  20.   TxHeader1.IdType = FDCAN_EXTENDED_ID;  Q. X) Q* A9 k7 l( b% V; `
  21.   if(can_id < 0x800) {  //exactly not right
    2 D! y+ F$ m7 a7 [& t8 f
  22.     TxHeader1.IdType = FDCAN_STANDARD_ID;2 H2 G6 T$ D! m* I* ^) q7 v
  23.   }1 v- k6 Q. X2 Y
  24.   TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
    5 q; ?/ [0 K* |: \7 O/ ?  L
  25.   TxHeader1.DataLength = DataLength;
    & R- T" {/ V9 i' P& m* h
  26.   TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;" S  P3 s% {6 z6 F
  27.   TxHeader1.BitRateSwitch = FDCAN_BRS_ON;* o5 i9 D0 {$ a2 Z9 m/ @4 s* ]
  28.   TxHeader1.FDFormat = FDCAN_FD_CAN;* R, ?4 M( |/ S# b) p
  29.   TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;5 ~$ e3 B7 e2 i( x- _
  30.   TxHeader1.MessageMarker = 0;        //marker++;        //Tx Event FIFO Use8 `7 v3 N8 x2 U( F
  31.   if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {
    7 h- ~* L' D' v1 a8 X
  32.     fdcan1_send_fail.flag = 1;2 I) b; I) }: h2 A
  33.     memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));9 o; {3 |+ o  ~$ \: B
  34.     memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));! B' D. q: M, @0 [" k' g* L
  35.   }
    # _2 w: _0 D3 W+ {& u- j8 t
  36. }
    $ N5 z8 }. J) Q9 l

  37. 9 t; T+ B: [: _; D
  38. int main(void)
    + O! f6 ~( D3 M* |9 |7 D
  39. {7 R# F3 [9 Y, l5 {
  40.   ...% _$ k' P  V0 \: X' i
  41.   /* USER CODE BEGIN 2 */
    ; M' P& M  U9 O
  42.   fdcan1_config();
    : L8 S5 G  C* |# D
  43.   fdcan2_config();
    $ y+ `7 g1 L. z8 ?- u6 W' R# }4 M
  44.   fdcan3_config();! ~! V1 G+ r4 m+ Z8 b

  45. 1 w" }4 h' {. b' d" G
  46.   for(uint8_t i = 0; i < 64; i++) {' S: `7 ]4 ~# T3 P; {) z
  47.     TxData1<i> = i;</i>; Y2 I( W" v/ l
  48. <i>    TxData2 = i;</i>% @3 H0 n* ]4 ^  N4 k, C" w
  49. <i>    TxData3</i><i> = i;
    1 s$ B! S$ J/ z3 k' `5 O
  50.   }8 N: ?) I5 q% n, q8 d
  51. - v* t2 m1 C) s' N- ?( o
  52.   HAL_TIM_Base_Start_IT(&htim6);5 q5 V' ]5 k1 `- Q
  53.   </i>uint32_t count = 0;
    ; W$ G6 u) Q, _1 L# ?0 ~
  54.   uint32_t cnt_100us = 0;
    - j6 N# d9 _7 l% Q
  55.   uint32_t cnt_500us = 0;
    ! ]: L" T2 `4 i! o, b: g' h' |
  56.   /* USER CODE END 2 */* l/ j, R1 ^7 _5 a

  57. 4 G% c- q8 Q: w- i8 w3 Q) D/ v
  58.   /* Infinite loop */
    0 H+ R+ T- e. w9 c2 {0 ?/ p
  59.   /* USER CODE BEGIN WHILE */4 m# k8 b" @. }$ h! }/ O
  60.   while (1)# u  O5 L4 e; @; I+ Y# I! I' @
  61.   {
    4 x2 F9 n( W) v. J# D6 y5 A
  62.     /* USER CODE END WHILE */
    : Q1 r: g  W/ J- O* M# ]6 s
  63. 6 p) h4 [) s" C, l8 A* c
  64.     /* USER CODE BEGIN 3 */5 c  v4 C- |9 q; @' K: z
  65.     if(tim6_flag && count < 1000) {; e0 d9 [  t% i
  66.       tim6_flag = 0;
    3 j; i% R; \" }; U6 {" K
  67.       TxData1[0] = count >> 8 & 0xFF;
    ( L8 D2 f3 y' [2 v4 J
  68.       TxData1[1] = count & 0xFF;% B- H2 Y$ _. y% n$ q5 v7 e- i9 M. K
  69. 9 w, h; d4 K, F6 S+ A& f0 o4 g5 y
  70.       ++cnt_100us;9 z. }/ _) i7 l; C: d# p$ J: z/ k
  71.       cnt_500us = cnt_100us / 5;3 ^  b1 v, Q: `
  72.       if(cnt_500us && (cnt_100us%5==0) ) {$ D$ h/ p7 f! [5 J; N) f+ ]
  73.         switch(cnt_500us) {/ R# S6 \8 n/ F4 v" g  V
  74.           case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1);
    ' t: C/ z9 [! H/ @  q  f& }
  75.                   fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);
    4 L# T" W* ?# i* C
  76.                   fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;. q$ m: S3 S) R0 S3 o
  77.           case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;0 b# t1 C0 K' \+ Z- T7 u% b% P# `
  78.           case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;
    & R8 F- z( d* p9 h
  79.           case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;
    ! h5 L4 G, o- x2 p6 g; U# V5 @% F
  80.           case 7: /* next send */ break;
    5 s8 w) x/ \  W( V/ k
  81.           case 8: break;
    8 ]( e" e% @& l" C2 P' I! G1 `
  82.           case 20: ++count; cnt_100us = 0; break; //10ms, s6 l+ _$ n: g2 f& `' V
  83.         }
    $ t8 j3 S1 q) q
  84.       } else {  //fail retransmission once
    / G6 G( S( R5 m7 v$ g7 a9 g/ }9 g
  85.         if(fdcan1_send_fail.flag) {2 _5 g* n+ l1 ?- k/ H! v: t
  86.           fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier,
    5 h& p! X" x- r8 j: ?) I
  87.                           fdcan1_send_fail.TxHeader.DataLength,* A5 Y7 F$ x9 g
  88.                           fdcan1_send_fail.TxData);6 Y: L5 H: n: e
  89.           fdcan1_send_fail.flag = 0;# B8 ~: Q, K7 U" j
  90.         }7 D( `" k( E! I/ m- ?
  91.         if(fdcan2_send_fail.flag) {
    + c) J) b" \! a7 d5 ]
  92.           fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier, 5 T* v; |. Y; Q5 E/ k' g, m
  93.                           fdcan2_send_fail.TxHeader.DataLength,$ ~' ?& @4 V  k+ T2 e* e
  94.                           fdcan2_send_fail.TxData);( @$ E& F" R: Q
  95.           fdcan2_send_fail.flag = 0;# V8 m; M8 |& v, q/ U2 z
  96.         }7 S9 a6 J1 g' H- L2 ]1 U+ V
  97.         if(fdcan3_send_fail.flag) {6 x* o) y, j. R
  98.           fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier,
    ) m+ h( M4 ~4 v# `
  99.                           fdcan3_send_fail.TxHeader.DataLength,+ V" w2 K: j0 o  y
  100.                           fdcan3_send_fail.TxData);
    9 N; ^/ I0 \7 L+ K6 p
  101.           fdcan3_send_fail.flag = 0;
    6 i$ W# x6 v! p0 Z1 E
  102.         }! L1 P* c( V5 g% d- s' m* ^7 y
  103.       }
    4 }* T5 D) o+ o* g) Z* g
  104.     }  A7 [# Z+ e% c- e. E
  105.   }
    8 l" I% A+ R& ^% }5 o
  106.   /* USER CODE END 3 */  2 f# ~! k4 u9 L( r
  107. }
复制代码

7 B) B/ Z% W# I- W/ Ofdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.
* ^) U& o/ n3 l! S: F
; B  z+ {7 K' ?7 y( o发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.
, T. ?' z2 P# F1 o! }% u+ K2 i
4 W) z& k9 N$ l" A, U- e3 t: d' j这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.4 X* D- D: s4 a
  G7 |& `3 {/ V; @# D" j6 V
因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧.( H6 s+ C0 l; T1 {* Z7 P" P! L
0 V5 m: v4 l, G! J
因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.
  i" r, d' v1 c, x/ ?* E- \
6 |; n4 v- H6 U6 t, }/ y# m- I如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.1 o( l1 Q" E, t% Z
4 S2 E) f: Q, t% _- V
一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.3 w- {  b5 H0 N' A

9 W$ ?1 E$ |! y! g1 e( @程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.7 A" A: }9 z* v: |

6 K  Q7 B/ T" _6 s* \; L% U使用Xavier配合测试一下5 O: ~- G, U7 y) r1 X8 j0 m1 k
把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:0 a0 N- b  U+ w% a
- E! _6 q* j2 O  l9 c/ c
  1. #!/bin/sh
    + ^% e: K+ b/ H9 c9 p6 S% ^- z
  2. / O) e5 {7 }% H; O. o
  3. sudo modprobe can
    5 H8 _" i3 y' n' D9 p
  4. sudo modprobe can_raw; g4 ]' i8 o" v# R$ m, u* W
  5. sudo modprobe mttcan
    2 s7 _" p# x6 f9 R; z, D
  6. : G4 z( B( Z$ g9 F: W- i; \8 W) Z! k
  7. sudo ip link set down can0
    , ]! X/ r6 V, z) a1 @# d3 c) _! ?3 C
  8. sudo ip link set can0 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100- c7 y1 L0 s" B# `$ A/ t
  9. sudo ip link set up can0 + D; y, K6 x# ^
  10. sudo ifconfig can0 txqueuelen 1000
    8 f( c, g. O% E3 [# F# S& E! j

  11.   P+ ]: j$ I$ A$ X0 Y
  12. sudo ip link set down can1
    + y8 _3 J- n/ ?! Z# I1 M; q( @
  13. sudo ip link set can1 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 1004 D  k: ]. b1 p
  14. sudo ip link set up can1
    1 W" T2 ~! t8 s  i
  15. sudo ifconfig can1 txqueuelen 1000
复制代码
Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.* u0 r, t& L* j0 j/ N

: a* ]: u3 c, R" `# ?7 F+ lrestart-ms 100设置总线Bus-Off时, 100ms后重启.! g% `# e2 R1 s3 O" t

- X3 {8 o+ ]# M9 g& o% J8 T8 v设置完后查看设置状态 ip -details -statistics link show can1:8 z5 }% O  j7 w/ z9 O! v' e9 f

: K8 Y4 P3 G/ q& A& x7 ~* A
  1. $ ip -details -statistics link show can1
      O3 V; U$ F6 ]7 o: [' O' F. ]! ~
  2. 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000' j) G: X6 x! ?7 b) N2 Z: c' {9 L3 R5 P
  3.     link/can  promiscuity 0 - x8 x6 w7 G( P
  4.     can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100 - b3 l$ p& s5 S* z8 T3 k& \, W
  5.           bitrate 498701 sample-point 0.792
    * {" C2 _& Y2 E+ s3 F1 H
  6.           tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 1
    0 l: s3 r5 n! N5 e' Z# I2 J3 |
  7.           mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1
    + T. a. N  n2 G$ a$ P* z+ v) O
  8.           dbitrate 2021052 dsample-point 0.736
    ; ]+ R$ X* n9 C, ~! p
  9.           dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1
    + i( [0 J4 C) h
  10.           mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1
    ) d# y/ S: B4 ^, F$ T- Z
  11.           clock 38400000
    + f  u  ]/ F# ^! r0 m  \3 g( H7 b
  12.           re-started bus-errors arbit-lost error-warn error-pass bus-off* G. [. ]" g0 o2 ^1 j# g8 n
  13.           0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 7 w0 ?9 I; D. E1 e
  14.     RX: bytes  packets  errors  dropped overrun mcast   
    4 v& E$ D5 y' A4 Y) W0 Q) i- F$ z
  15.     64578440   1013451  0       0       0       0      
    ) S5 B$ H. E% L( W
  16.     TX: bytes  packets  errors  dropped carrier collsns , a; I; M9 a2 _) F
  17.     952448     15914    0       0       0       0   
复制代码
位速率和采样点的些许误差测试并无影响.: T3 H3 T2 S6 j* V) n- X% w0 n& X* p

/ Q+ |; i9 S  \4 E! p4 o使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:
/ m) V3 S: E* `6 T% e+ ?* H& [: Q) w
$ m+ ?  P( N/ M. E* x- F) M. x! b
  1. (1613988959.105805)  can1  RX B -  123  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    3 `7 l8 z4 b; K- B
  2. (1613988959.106191)  can1  RX B -  124  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F7 g5 A+ \  L5 g. B( s
  3. (1613988959.106609)  can1  RX B -  125  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    5 K$ Q3 e: c( z8 Y+ H& I
  4. (1613988959.107337)  can1  RX B -  12345678  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F( [& @2 e3 W6 {1 b; }
  5. (1613988959.107865)  can1  RX B -  12345679  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    ! W8 F/ x* ~7 g) h3 J- Q
  6. (1613988959.108332)  can1  RX B -  1234567A  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F9 E/ x3 T/ l( S0 W/ [  O4 z
  7. (1613988959.115791)  can1  RX B -       123  [64]  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    * s$ W6 M' M: I3 w* `
  8. (1613988959.116215)  can1  RX B -       124  [64]  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  j( N' \! O1 ]9 n

  9. ) }  A) F# S6 S( P6 I9 I
  10. ... ! [4 y- D* p% O/ {' G* m$ [2 M/ {

  11. ; R& m' \- D5 `4 A# W* N4 q
  12. (1613988969.087131)  can1  RX B E  12345678  [64]  03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F8 f+ @. I' {& s; v2 _2 t3 J! @
  13. (1613988969.087612)  can1  RX B E  12345679  [64]  03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F& h5 V3 I) J) P# v/ t2 S) q2 V4 Q4 K# y
  14. (1613988969.088160)  can1  RX B E  1234567A  [64]  03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F3 ]' o( t5 E. m4 L& N  Q/ h: s
  15. (1613988969.095802)  can1  RX B E       123  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F9 V+ I. O( a/ H& s% I& ]
  16. (1613988969.095935)  can1  RX B E       124  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    ! g8 d' C/ L& ?! B
  17. (1613988969.096294)  can1  RX B E       125  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F; K, a. `! S4 p2 C4 k( ~
  18. (1613988969.097116)  can1  RX B E  12345678  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F0 U$ x2 _5 f! X; r
  19. (1613988969.097604)  can1  RX B E  12345679  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F( j) {* q5 m! H
  20. (1613988969.098102)  can1  RX B E  1234567A  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
复制代码
& X: V6 z( T" F! b" v
这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.) Z  C8 a( y" |! }9 ?5 L
5 ^1 F6 w5 Q/ A- I4 j
Xavier发送脚本, ##后面的3表示开启BRS和ESI:
3 ^8 t/ |9 D  P) d' N$ x
- P1 P4 D8 z- \" T& @6 u8 I
  1. #!/bin/sh
    2 d0 r# v$ r" _, b) P: j# D

  2. 9 z. c! i: k  q5 \
  3. while true; do
    7 M: P. k2 q* y; |- d
  4.     cansend can1 18FF0001##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    - C5 W8 ~% C+ M4 u5 |1 \
  5.     cansend can1 18FF0002##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    + C/ E; M" v: P5 \/ P' Y% Z
  6.     cansend can1 18FF0003##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16  / q3 G2 h) X4 @2 n
  7.     cansend can1 18FF0004##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    1 Q1 W* k+ N2 r2 q
  8.     cansend can1 18FF0005##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16  G, c) H6 }% j3 J$ X
  9.     cansend can1 18FF0006##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16  
    0 U& O2 u4 m# [* }, K8 s3 M, ]7 r
  10.     sleep 0.01& l2 Z8 B/ t: C2 O% ^
  11. done
复制代码
9 b6 V- q! o' V! q6 n( Q& a
可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
/ f( c/ U$ N2 V5 Y& E! z+ W6 P" f) ~5 j' g; G4 e& g4 `3 e
核心思想是:# J- ]2 v; Q7 ?# C3 Y- g/ S

, F( U/ {1 h' y/ R% D1 n4 @Mode 设置为Classic Master或者Classic Slave, 而不是FD
3 N3 {* v, I3 H仲裁段和数据段的通信速率都设置为500Kbit/s( v' r$ y9 C$ o, S

/ q$ A4 O) K. N, w( c9 O- U! p! ^6 l1 V3 a9 B
: W4 x6 k. l) @% p: E  h; `
收藏 评论0 发布时间:2021-11-11 22:00

举报

0个回答

所属标签

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