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

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

[复制链接]
STMCU小助手 发布时间:2021-11-11 22:00
本篇用起来, 连接关系如下:
+ u0 a3 M. P- z' b+ T
8 }5 g2 @' T, h( C5 W4 ?% D

20210222185812381.png

" \; M: p, m8 @3 z

# m9 |* z1 @3 o8 U5 p3 U( }* J% Z+ Y1 FCAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.# Q" U- ~0 d4 Y/ i  |% {5 D1 P
3 G" S# Y* i7 j+ X
STM32工程搭建
  c% X5 m& y* o7 j, v/ KSTM32CubeMX配置步骤如下:
) w0 `& j' m7 f( n9 t1 P
$ `" P4 o4 _2 D; `* W' ?0 jMCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
: N) `# z. z+ |' v$ l
+ t2 ~# y+ F3 Y) A4 u5 K0 L调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
1 D( b) X5 U5 n. P5 T3 w- ^/ D, N8 P+ F5 |- A
Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
' ~' e8 i4 a- j: @% a' N
( ?# s# Z+ b' n! c# vClock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):
$ F( o, ]& z( d1 E  l: p) W4 v7 g

20210222185828575.png


: Q5 \6 ~, z+ c4 S& I

20210222195952515.png


* g+ i" k6 J1 q6 Z+ p4 Z- v$ o5 k$ n- L
开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:
& N: M6 E) P( a0 i7 F' Z2 \9 p# a; W5 o+ R- _% t, ~

20210222185846781.png


$ x5 m# V: E, Z7 y
8 ?& s; @; }% E

20210222185905935.png

# l! O/ g8 r6 U1 j
8 n+ C$ n7 q8 t2 P1 w1 s
LPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:" L" g7 a  a+ e1 M2 X3 m

0 f( Y3 f( |* S: d6 E$ c7 n

20210222185926920.png

  F; R- Y6 ^- \% m, S& X) f
! o3 S' \! ~/ U0 r4 P1 U7 [
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:4 u7 n0 b' ^. F

: R' \# J/ f! w8 o

20210222185949803.png

4 ^& j/ d6 Z& R5 ~# K3 R7 i7 o$ d0 r
4 a6 T# W7 {% h/ @. t

20210222190005173.png


7 s1 T' s2 l/ T8 V' J. F7 h7 s" n1 q! a# K
FDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:
# C6 B/ c# i9 i
( z1 s2 ^( F7 _% @

20210222190054536.png


6 o7 N8 @  [. h; K1 K6 K3 T2 k' v. }6 T
Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点.
2 o8 A4 g0 \0 G
+ B0 x: Q, k& z+ `; l- s* _+ tProject Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral! \% _. J5 u$ b1 {8 ]# W
; p" I  ]* C7 U  k: ~% }
点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.
# M- T4 H2 l. X+ d" ^! ~# N) C! C  h* R, Z" j; F( f$ n7 K& T
Keil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:
% Z6 m  k, y3 ]- D5 q
/ U- `6 k3 l8 R6 t8 kFlash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.
# l3 z8 ^' O3 T6 s. E5 TPack选项卡, 去掉默认的Enable勾选
: t* q/ K; i" z  h$ T到此配置结束. 下面是手动添加的代码详解
4 F' g7 Q8 M+ `5 b2 v
$ Z: E3 u7 @$ y2 P) ^串口配置
. ~  E* D) V. i! w为 LPUART1 添加printf支持:2 s$ V+ Y, h2 m# `5 W; w

2 f2 ]7 [, e3 W; u( Z
  1. #include <stdio.h>
    ; Y2 C. J. c7 C
  2.   L4 c; s; b. t2 e. {4 p/ b
  3. #ifdef __GNUC__
    & L* F* f0 \5 x+ C
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    % Y- d- _' |, @
  5. #else
    ( N( x9 o6 Z9 Q/ v& U, B, @! _
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    . U: t4 }+ Q& f+ T4 ?
  7. #endif /* __GNUC__ */
    2 C: f+ U/ A7 Y! S+ L/ B" f; e
  8. , Y0 I1 \7 g, _! I
  9. PUTCHAR_PROTOTYPE6 u3 g! A6 R9 w2 |- Y* K
  10. {
    4 V. C& q: R  U/ M9 `
  11.   HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
    $ v% i; s' Z8 s  X, X' \
  12.   return ch;
复制代码

+ S! x  V$ E2 h, v9 N, A100us定时器' r3 r  N$ u- N0 o( H( N! A( c9 D
因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.
' g3 }6 B, C0 Z5 o8 s
: G6 h  g* Q$ [/ w/ a8 W
  1. /* USER CODE BEGIN 2 */9 K. o  k4 V0 B% _; o
  2. HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.1 I' P, E& V6 z+ W4 m) {
  3. /* USER CODE END 2 */
    5 U; s) ?3 b' |8 |* Z6 |5 A/ L6 R
  4. & z+ ^1 t) y) u, F
  5. uint8_t tim6_flag = 0;
    , B$ D2 u! F1 `; r
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    6 l8 Z; ?( D8 f& w1 {: T7 g$ I
  7. {
    + [/ Y+ L3 N9 Z6 i2 t+ q
  8.     if(htim->Instance == TIM6) {  U* d0 v) u2 _/ a3 r
  9.         tim6_flag = 1;
    ; c0 z) r$ [* v
  10.     }: k5 p; J9 G8 r; ]
  11. }
复制代码

- \. B5 h. V- U: u' H9 z, t/ vFDCAN配置' B" o1 b  T/ P
主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.
# C9 x+ I4 F+ G6 u: A7 p& R3 b6 g: }/ W( M
  1. FDCAN_FilterTypeDef sFilterConfig1;
    # t) k5 J: l$ A+ J
  2. & w4 |! x& u" k# J; S7 f8 L
  3. void fdcan1_config(void)
    6 e& Y5 S+ o( M
  4. {1 o- _& Q; s! K0 j
  5.   sFilterConfig1.IdType = FDCAN_STANDARD_ID;7 t" e8 s# {1 j8 ~" V& E, t5 o
  6.   sFilterConfig1.FilterIndex = 0;; j6 A( r& Y; `8 y" Z- f- j$ \/ R/ p% h
  7.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;0 R8 A9 e0 t0 d" a! [% }2 J
  8.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;3 n$ S9 o; h8 a' d4 ^0 V/ V
  9.   sFilterConfig1.FilterID1 = 0x00;
    ( F3 z/ o* |( x) A' L
  10.   sFilterConfig1.FilterID2 = 0x7FF;, G# L: O/ [3 @  P
  11.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)0 f& E* K; c0 i1 X$ S) j
  12.   {( q) k9 R6 v, d9 o
  13.     Error_Handler();
      S- l5 A' w, d& d7 G5 a
  14.   }
    ! I9 a6 k' ?1 c7 R0 ~+ V6 N

  15. * B1 c" Z2 u* B* q8 E
  16.   sFilterConfig1.IdType = FDCAN_EXTENDED_ID;! C4 ^9 O: A# l2 t
  17.   sFilterConfig1.FilterIndex = 0;
    0 C2 o5 Q; s' P3 {+ e9 Z2 P
  18.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
    8 f* g1 v$ B8 }& k
  19.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;) p; b& D0 P: i$ G% Q
  20.   sFilterConfig1.FilterID1 = 0x00;
    - D$ |+ m+ ~6 Z; Q) q$ l' n
  21.   sFilterConfig1.FilterID2 = 0x1FFFFFFF;, G) _9 n& `+ Q) }6 L
  22.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)$ Y: s* K. N+ F( J* a: H0 p8 r
  23.   {; h5 r$ t+ N1 M7 [% x) u
  24.     Error_Handler();
    5 j" C7 G9 f9 K% X6 Z
  25.   }' n- i) s  e, @; q; e9 ~

  26. , N* [7 w5 G6 X* @3 j/ E( s
  27.   /* Configure global filter on both FDCAN instances:
    7 _: a8 G$ a* R" t2 b& B
  28.   Filter all remote frames with STD and EXT ID  {) L% n' T( p+ @2 u& ~
  29.   Reject non matching frames with STD ID and EXT ID */
    2 G0 K0 `. \$ n7 k
  30.   if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)- J7 U+ d! q$ \
  31.   {
    - J0 Y4 X, s: P5 K
  32.     Error_Handler();9 s5 v/ b4 A8 R* i
  33.   }9 e- M, x0 M8 C9 j" T

  34. 7 G( H: [4 |1 A! N* g  e
  35.   /* Activate Rx FIFO 0 new message notification on both FDCAN instances */8 |4 ?/ h% a( S& B$ M" O7 }
  36.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)4 p" m6 r3 x; \
  37.   {& y% H; y  x2 ?- K4 ^% @  @$ i2 q/ A. M6 a
  38.     Error_Handler();. J' S" E0 `# @1 k& l9 f
  39.   }
    7 y$ x9 Q8 u+ H" b. G. P+ e

  40. ; X; l" `+ p+ _+ s- _! M
  41.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
    % M# e' w. N+ l5 o, u
  42.   {5 {& S6 V; `8 @5 l; G) i* W
  43.     Error_Handler();
    , ]' @7 j* c! l8 ^: G* X
  44.   }
    1 o, T/ {& Y. h; F6 [" ]6 G
  45. 7 w4 U& B# {, K, R  y
  46.   /* Configure and enable Tx Delay Compensation, required for BRS mode.2 v) V; i# Q7 N* T
  47.         TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
    ; {8 i: Y) W* M: l7 Z# a5 o
  48.         TdcFilter default recommended value: 0 */
    7 w  N5 O/ Z8 v* [0 I0 z
  49.   HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
    5 L+ q  p) E4 s8 Q
  50.   HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);, ~9 q2 E" @# {- X! L6 h; i" p
  51. $ R1 T; H5 b& f% m4 g
  52.   HAL_FDCAN_Start(&hfdcan1);' C2 c0 q/ `* t: g
  53. }
复制代码

' s3 h: T* i8 r+ U4 V0 F! |7 [0 P这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:
# \' e  \/ p* R7 s4 a9 A, V( B$ h
  1.   sFilterConfig1.FilterType = FDCAN_FILTER_MASK;* h0 g& u7 R5 m+ }4 V8 @7 V1 r' s* h: \
  2.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    & T$ A; x* a8 H' L& b" x
  3.   sFilterConfig1.FilterID1 = 0;
    $ |. j* L& V  u: M6 O
  4.   sFilterConfig1.FilterID2 = 0;
复制代码

. i# t! c) _- ^用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.
4 ^- O5 S/ W+ o1 Z& \
* V! Q( h( |1 B" c1 Y; F% C, D有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:* n( z+ F  m+ Q# z% M
6 {7 P! Q% `4 O0 l
  1. #define SRAMCAN_FLE_NBR                  ( 8U)         /* Max. Filter List Extended Number      */
复制代码
9 O7 _5 N" q3 k) O! p
FDCAN2, FDCAN3的配置和FDCAN1类似.# X! w. G+ A; X/ K1 G  _  C4 f

; A3 H* J7 C4 e3 ~' T3 UBus-Off处理
3 x3 H' e5 t! ~4 K) W4 P. D如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:5 _' w  A$ d8 y8 H8 T

0 d* j0 C' z& w2 a1 Q
  1. void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
    4 P8 ]$ J7 {( _: |
  2. {
    ! `( V" Q3 s2 H  }
  3.   //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);
    5 {4 h" ]; t" V9 b- j3 q
  4.   if(hfdcan->Instance == FDCAN1) {
    7 _+ N) m1 N) \; }3 q2 z
  5.     MX_FDCAN1_Init();: x! z* s- q2 Q4 c/ q* H
  6.     fdcan1_config();) k1 Y$ w7 J0 w
  7.   } else if(hfdcan->Instance == FDCAN2) {/ J: v3 D3 N, @
  8.     MX_FDCAN2_Init();
    8 ^: H) J' u2 r+ w3 ^
  9.     fdcan2_config();
    ! S" s7 z0 S2 [) p. D9 k( |) u
  10.   } else if(hfdcan->Instance == FDCAN3) {  D8 y2 m: I, I0 \# e+ R
  11.     MX_FDCAN3_Init();
      @5 d1 }6 F3 m4 A; H7 j8 _
  12.     fdcan3_config();! _2 _0 c* I  }5 o5 `) u
  13.   } else {' D6 {$ z* N+ J0 |
  14.   }) V1 y, w3 j3 k# q0 {( Q) n
  15. }
复制代码
8 T! I$ O& `! z6 M4 _2 Q
新消息接收处理
, ~6 x6 A$ j$ j! t  O: E6 \9 B直接把接收的消息通过2M波特率的串口打印出来.
. G  g1 e% o/ m/ E" g1 r  m+ `) s0 A
& m# Y$ r! Y, G$ R
  1. FDCAN_RxHeaderTypeDef RxHeader1;- D$ c9 r" `% E! x' B" b
  2. FDCAN_RxHeaderTypeDef RxHeader2;, z1 w6 h  o6 y4 Z
  3. FDCAN_RxHeaderTypeDef RxHeader3;
    * L: a; ]3 n3 ?1 i# P- W

  4. " ~- t% r. p- L2 l# g
  5. //RxHeader1.DataLength => can_dlc( l2 _6 P" F" S* s, s# |
  6. //0x00000 => 0 ! v2 H% Q0 F0 b8 D" y4 _
  7. //0x10000 => 1
    . Y! G0 H, o' I6 U% d8 Z
  8. //0x20000 => 2 0 N3 n: R4 o+ K( a4 ~8 P
  9. //0x30000 => 3 / G$ X& ~) R6 \9 W/ ]
  10. //0x40000 => 4
    + b. n! t" S' e; A5 U4 D$ O) K+ N
  11. //0x50000 => 5
    . x7 t+ z; n- p* |! c7 c, q( e5 I( V
  12. //0x60000 => 6 1 k: D4 R7 M8 d9 c3 r! n% \# P
  13. //0x70000 => 7   w2 w+ P0 N7 i
  14. //0x80000 => 8
    7 T* i5 t! n5 p
  15. //0x90000 => 12
    6 k/ i7 r! z: _/ J* d! N, |
  16. //0xA0000 => 16" |/ M# S' {% r1 J
  17. //0xB0000 => 20& b4 P& D* C+ B; E" b
  18. //0xC0000 => 24
    8 A; u* P( T) e5 K9 U4 B& y8 J
  19. //0xD0000 => 32. d% U, A+ |0 f" |1 u% X6 \
  20. //0xE0000 => 48
    ( v; J) k* E( p8 }4 f8 v
  21. //0xF0000 => 64
    * H! N0 K7 t" D9 f, Z3 y
  22. uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
    6 L# ?- f) O4 M
  23. uint8_t can_dlc2len(uint32_t RxHeader_DataLength)
    5 r# P# T6 H6 n8 R: I) ^+ v$ B
  24. {
    , _$ s4 }0 F$ _0 q) e4 g
  25.   return dlc2len[RxHeader_DataLength>>16];8 p$ X; {8 ^) N4 p; ^' s5 w
  26. }
    6 J/ Z  v& B$ c, Z, d
  27. ( s! P! E: h- y5 Z5 p
  28. uint8_t cnt = 0;5 j0 e' J5 z7 Y2 O- I# i) A
  29. uint8_t brs[] = {'-', 'B'};5 r. v$ t$ t1 w! F) A
  30. uint8_t esi[] = {'-', 'E'};$ t% ]& x: \2 h7 u7 b0 c. V
  31. void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)2 z# E8 O- d9 ^  d' N
  32. {* B! u6 G( k! U
  33.   if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {
    4 ]. `9 F3 a' L9 q/ Z
  34.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    2 h  Y! o. I: a9 @' \
  35.     //RxHeader2.Identifier++;
    ) h8 p9 D7 i1 V
  36.     //fdcan2_transmit(RxHeader2.Identifier, RxData2);
      n2 |4 T8 B# Q% t2 J. v! Z  y1 z
  37. 5 ~9 N/ O- X1 E+ `$ N% r$ y3 Y8 H
  38.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);) w! h5 j# R' ^; q% I% }0 h
  39.     //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));
    # J9 }3 Z# F$ f' L9 m8 x

  40. 7 K4 e0 ^, `. ], G0 I2 W) ^" t
  41.     HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    / s$ ]+ M- D0 a8 W1 w  d
  42.     if (hfdcan->Instance == FDCAN1) {
    % [; L4 h( T  {0 n
  43.                 printf("fdcan1, ");
    8 l9 A* z. H5 H9 ^3 M
  44.         } else if (hfdcan->Instance == FDCAN2) {
    8 |7 q" y* S* B
  45.                 printf("fdcan2, ");
    / N1 Z' i+ D6 _: b% C2 Y! S5 c
  46.         } else if (hfdcan->Instance == FDCAN3) {- O6 {: L9 H2 A
  47.                 printf("fdcan3, ");% F$ ^% }* H0 V4 y) J( k0 N# W7 d
  48.         }; m6 r) I- j+ T! E; C
  49.     printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier, : Y( |* h2 E& E$ [) T
  50.                                   can_dlc2len(RxHeader1.DataLength), ) ]) k. k5 e% _: U# L' n
  51.                                   brs[RxHeader1.BitRateSwitch>>20 & 0x1],* i' v8 q& |+ e$ L  O, c
  52.                                   esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);: g. M# k5 m3 W4 b5 S( ^
  53.     for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {1 f2 L& S+ s) ]' z: p3 {0 ?
  54.       printf(" %02X", RxData1[cnt]);
    ( G, u3 R9 `9 X3 {$ l  }2 n( j
  55.     }
    / U8 Z! o& U8 ~# c9 m2 f
  56.     printf("\n\r");- l: Z3 [% F6 T5 v% ~! d7 c

  57. ( e" W; ]. ?6 W! |3 o; n' U- X
  58. 4 j& H$ P4 D4 @8 M" |
  59.     //if (hfdcan->Instance == FDCAN1) {
    ' n8 s3 u  V$ t9 v" K# O
  60.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);( q4 A6 ~2 k: G# R# y5 I) t+ e
  61.     //  //echo: |* [$ y7 V8 ?* G
  62.     //  RxHeader1.Identifier++;3 m/ U4 `- i1 n- [
  63.     //  fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);5 o+ m3 t1 K/ E' k$ u* }& c
  64.     //} else if(hfdcan->Instance == FDCAN2) {
    7 X0 b# K5 [" D9 f7 t7 h
  65.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    ) A  a4 `% b, Q
  66.     //  //echo  V) B* S6 E! Y  t2 [5 _- F, @
  67.     //  RxHeader2.Identifier++;
    / f" m+ m( L7 H; h( ~# X' a
  68.     //  fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);4 r7 w3 G8 d2 |7 D; N! V9 f
  69.     //} else if(hfdcan->Instance == FDCAN3) {
    - `, _9 Q' f( O" s3 J4 |4 x
  70.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);
    ) i$ J% S- [; J3 M
  71.     //  //echo- @0 l1 ~9 n( v7 B/ y
  72.     //  RxHeader3.Identifier++;
    ; z1 J5 ^9 |! G0 T
  73.     //  fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);3 w2 t8 y5 y  T2 L+ C2 P
  74.     //} else {+ Q) d' q2 h  E0 e' B- o: \
  75.     //  : ~& Y, |3 }$ K% r4 W
  76.     //}7 @: d  c7 r' f) y/ Q; K+ r0 x% t
  77.   }
    ' f: l# x, Z/ j2 t1 I
  78. }
复制代码
* ^8 U! r" c& l1 p2 ~; Z
注意注释中 RxHeader.DataLength => can_dlc 的对应关系.) s' a; Y+ Z% C8 T' w, T
, ^* n. Q& o# H% f4 l
示例如图:
: n. G) h- J/ ^& o" T5 j6 s' H0 y4 g* L& [+ _7 Q" j; n1 F
20210222190024669.png

/ H( e6 X* I* e8 v+ u0 l/ C' v1 {8 W- t
图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.1 T7 z' ]$ h3 N, r4 ^
) g- C1 R( _) F
printf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.0 }" W0 R9 m1 q- R$ E
$ ~5 N; L$ F" d. g- X* p
发送处理
; l# ?" r0 F& R" }1 D) w发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.
) k' |3 m: j, j8 D6 l
' d* R1 u1 K. B& I# [9 L9 J  f
  1. #include <string.h>
    2 r& d, D" X; j

  2.   b1 j5 T3 Q% y3 r9 p; s0 \
  3. FDCAN_TxHeaderTypeDef TxHeader1;
    . z4 j. [! n  U: y+ h$ p, V; l
  4. FDCAN_TxHeaderTypeDef TxHeader2;
    5 A4 F; Q5 O: r0 ]* g
  5. FDCAN_TxHeaderTypeDef TxHeader3;
      P, l! c* T) T; Q0 K; `7 e

  6. 5 i- h% t* X) @8 b4 R% I# O
  7. typedef struct {
    ( ~/ y  C* t2 z8 J! p
  8.   uint8_t flag;4 h2 Q" i, \: l
  9.   FDCAN_TxHeaderTypeDef TxHeader;
    8 q1 B5 C" s5 Z$ F3 g. g  L: _
  10.   uint8_t TxData[64];
    2 _- Q; V( I" ]6 \
  11. } FDCAN_SendFailTypeDef;% A0 \2 P7 \  E

  12. ! }  f1 n9 j/ M2 s( [9 o9 Q
  13. FDCAN_SendFailTypeDef fdcan1_send_fail = {0};  b/ ~* A/ A" x) m- [/ L
  14. FDCAN_SendFailTypeDef fdcan2_send_fail = {0};
    ! O0 j1 |. [6 k. q/ m* P
  15. FDCAN_SendFailTypeDef fdcan3_send_fail = {0};, h" \" Z- ~, B5 M
  16. ) @7 N2 \- g: Q: B+ d  c
  17. void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])/ g$ d! B  P% J# |- h5 L$ ^
  18. {, |% ?$ d9 z+ Z  Q8 y# \
  19.   TxHeader1.Identifier = can_id;7 g" ^9 f7 S* R1 n, C( Y" l! V
  20.   TxHeader1.IdType = FDCAN_EXTENDED_ID;. S" R1 B7 }* {+ V% Z4 v0 ?* A
  21.   if(can_id < 0x800) {  //exactly not right
    4 ~6 T* z3 q9 n
  22.     TxHeader1.IdType = FDCAN_STANDARD_ID;
    8 c3 l6 r3 a1 b% E1 V; S0 q, L
  23.   }
    0 j! e4 X+ u" u5 V* `2 o
  24.   TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
    ( Q- s7 d+ ~4 E# y, z
  25.   TxHeader1.DataLength = DataLength;: a7 z/ Z" m5 U7 H% z+ P. p
  26.   TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;2 `+ w4 I% p2 I, ^! c
  27.   TxHeader1.BitRateSwitch = FDCAN_BRS_ON;1 a+ y# e' M5 ^& o* q2 |" \7 H
  28.   TxHeader1.FDFormat = FDCAN_FD_CAN;
    ( m$ H* P2 C& ?, C# ]6 S
  29.   TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;1 o- n3 l/ M; i/ d
  30.   TxHeader1.MessageMarker = 0;        //marker++;        //Tx Event FIFO Use
    " u" ^& D5 _$ P( b' `: g/ B
  31.   if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {. P9 ~! ~  |( c* G4 }- c8 ~% M
  32.     fdcan1_send_fail.flag = 1;3 d/ x* E" M# o4 ?7 b) E( J% S
  33.     memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));/ W  I) ^* F; G. N
  34.     memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));4 @3 ~  q. Q0 s/ j( O& M
  35.   }
    $ ?+ D% o: C! P! m7 y' @
  36. }% [/ a3 |! O2 J( l( p5 i
  37. / ^* m- h4 e1 ]0 s1 b+ D/ T7 u
  38. int main(void); `3 [6 m6 D+ B- B3 B
  39. {
    % B0 R1 T( i+ X: u, V
  40.   .../ [9 O+ ?0 y; j2 a; o
  41.   /* USER CODE BEGIN 2 */- ~$ ]$ `2 q  `; a# V' w! J" m% _
  42.   fdcan1_config();- B( ^) q$ U& I& z( i
  43.   fdcan2_config();
    / L; q% p- y9 r2 F+ G$ c/ f
  44.   fdcan3_config();5 N1 K8 a8 u$ |: u0 G! D2 s
  45. 7 q9 x3 I0 s' M" k
  46.   for(uint8_t i = 0; i < 64; i++) {
    - f8 L; X) T% O) ~
  47.     TxData1<i> = i;</i>
    1 \/ a% {' l- D* ~
  48. <i>    TxData2 = i;</i>6 b. T- p# W( T/ l9 ~
  49. <i>    TxData3</i><i> = i;
    : m( o2 H6 A: U' V2 G8 X
  50.   }/ {" {; S2 p, t# p6 U& c3 \

  51. 4 }0 r! Q/ J( E! d
  52.   HAL_TIM_Base_Start_IT(&htim6);$ o( C6 j& `* R+ S' V$ P7 ]
  53.   </i>uint32_t count = 0;
    # O/ F2 r. h1 {1 L# d% M
  54.   uint32_t cnt_100us = 0;( T2 z0 J3 E) q' {0 v
  55.   uint32_t cnt_500us = 0;
    2 I5 L$ \+ ^4 l8 I. r
  56.   /* USER CODE END 2 */
    7 I1 k6 S$ }9 R
  57. , P) U) t2 D. P2 n: V
  58.   /* Infinite loop */: F) x1 N: \2 B) L7 _- r
  59.   /* USER CODE BEGIN WHILE */
    ' u5 p- f4 N; ~- |. E
  60.   while (1)
    / X+ Y' b3 K+ W: B5 I- k
  61.   {5 ]3 X  K* i, P/ O
  62.     /* USER CODE END WHILE */2 N6 W  ^- H" F+ o0 [

  63. . v1 }" \( `2 P7 e/ S' f
  64.     /* USER CODE BEGIN 3 */
    5 k: a' Z  X) w
  65.     if(tim6_flag && count < 1000) {
    * J4 v8 Y) ^' o- t3 h
  66.       tim6_flag = 0;4 r! k, y# L: \2 Z( N1 n
  67.       TxData1[0] = count >> 8 & 0xFF;0 L( o9 O8 L/ \, X
  68.       TxData1[1] = count & 0xFF;
    " }4 }, @/ j* R* F! T9 a
  69. * w9 }: l2 o1 o1 s0 T6 t% \
  70.       ++cnt_100us;
    ' B$ z+ w4 G5 c0 ^+ f" o# ?" U
  71.       cnt_500us = cnt_100us / 5;) r7 l" N) h+ l5 @8 ]- H
  72.       if(cnt_500us && (cnt_100us%5==0) ) {" k) K2 C  y5 F9 Y
  73.         switch(cnt_500us) {
    6 \3 i( T  Q2 ?6 P$ O1 N; p
  74.           case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1); 2 p3 D2 v) W3 T! e4 o1 J; x
  75.                   fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);
    2 F! b$ z! g3 I% C+ W# R
  76.                   fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;. I4 ^" b! K1 n8 u! U
  77.           case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;
    . a& v! T4 ~2 n/ y' `
  78.           case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;
    1 q3 ]5 T1 ?% z* n+ {. F  G2 j  Y' b
  79.           case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;
    , Y9 y6 Z& O2 I! m) A4 k8 q! s
  80.           case 7: /* next send */ break;
    6 p( O! Y6 w, c0 j+ A2 @8 ^
  81.           case 8: break;
    3 n3 ]) i/ W$ r# c# r- Q
  82.           case 20: ++count; cnt_100us = 0; break; //10ms
    ; O  h1 D3 r+ B/ d! R2 g1 ^; I
  83.         }6 e. P( h% S* P3 F4 O7 I
  84.       } else {  //fail retransmission once
    - F, s6 J: x* Z: b
  85.         if(fdcan1_send_fail.flag) {
    / z( `$ p: x0 z+ H4 A
  86.           fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier, : [4 k" I! T& l% q# h5 i
  87.                           fdcan1_send_fail.TxHeader.DataLength,
    8 c" P  R0 k5 ?: `- ]! w# R& w
  88.                           fdcan1_send_fail.TxData);
    ) _$ b" ~  D! t) o8 b& e8 V2 W( S
  89.           fdcan1_send_fail.flag = 0;
    ( T- N, k1 I# N8 x) j3 ?$ h
  90.         }. n0 C/ ^( z+ l3 H# [) o
  91.         if(fdcan2_send_fail.flag) {
    , |3 J9 c- n8 Z, j0 L# j7 T5 Z( [$ G
  92.           fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier, ( G8 M5 p1 F+ M
  93.                           fdcan2_send_fail.TxHeader.DataLength,
    ) s7 i7 T8 y& i+ `
  94.                           fdcan2_send_fail.TxData);
    + n( X% M* u# F0 `  G8 W
  95.           fdcan2_send_fail.flag = 0;
    ' T9 Z7 o5 Z4 g
  96.         }
    # ~, g: k! U8 d% C! P
  97.         if(fdcan3_send_fail.flag) {' y- ^/ U4 m. s0 x9 b7 c8 y
  98.           fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier, , F8 _# t% B( v/ ]! w' R" a" S
  99.                           fdcan3_send_fail.TxHeader.DataLength,
    + h' m- r2 J; y8 v
  100.                           fdcan3_send_fail.TxData);
    ) I9 ^! O- l! J3 `3 w& C: s# R
  101.           fdcan3_send_fail.flag = 0;
    ! \6 U* R4 i  I' a' C0 o7 e
  102.         }3 c9 Z4 L- v, o1 u2 }1 {! G
  103.       }
    1 Y5 k+ ^9 ?* l- a8 |7 K' s
  104.     }
    ( H  `: @" ]% B! L
  105.   }7 n6 s# V* e- D% K) h  J* a* j
  106.   /* USER CODE END 3 */  
    ( |- m! f2 B* a. N) @% `
  107. }
复制代码

7 f. D/ }& E# Dfdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.
2 t1 l* q( e8 r& H1 J) [- H( W: R: ]) Y% F4 u
发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.) H7 C- o: I& d5 V9 e

" G) r9 X6 {/ E, \这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.
* h( k) f3 C/ f' p& v
; A- u0 Q2 _, Y+ g. r# i因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧.
0 E! @* Y4 t+ ?; _/ v/ }
0 R& N# _" j" _- W# c+ t因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.5 C7 R9 ?) Q5 }

$ {: w* H! H: j" Z& N如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.
$ S: Z' t3 |; w( f! n4 ]$ k( S( o6 a+ n" v
一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.' h0 G8 Y/ J  ~% J5 r: \
) G. l9 u! l% {
程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.1 q- k# i2 @* [7 s
3 H. s- D& J) A
使用Xavier配合测试一下
4 T4 M) P- O- s. S, M把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:
$ D. B5 b* y% U. l/ G4 O
7 h. b& s& r! O6 d! z
  1. #!/bin/sh4 M6 c' h. e% M0 b: w; r, p7 [
  2. + s. N) B7 `" x, O( c
  3. sudo modprobe can
    . E( J( N1 s0 U& f) [$ H7 X# m# R
  4. sudo modprobe can_raw0 o6 G2 V! r3 ~1 a. s+ x  g
  5. sudo modprobe mttcan+ o  G3 U( |; g5 D; X
  6. % P/ t& {1 K$ }' a$ s
  7. sudo ip link set down can0
    2 S/ a! P! b- t+ B, O5 Q( W2 Q6 T
  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
    + n( g1 j; j3 Q' t
  9. sudo ip link set up can0
    + ~9 G" X" ^- p  k
  10. sudo ifconfig can0 txqueuelen 1000* b2 V) a- v8 P  `& P' G% A
  11. 2 E$ g" Q; p* Z8 Y
  12. sudo ip link set down can14 v% p1 }& w) l
  13. sudo ip link set can1 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100, X; P9 ]. ^3 h( l: `7 I- s
  14. sudo ip link set up can1. n2 m. l& @0 s
  15. sudo ifconfig can1 txqueuelen 1000
复制代码
Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.
* B) V( W5 N' w( v; X4 p$ b2 U& B$ o. g5 c8 p1 h
restart-ms 100设置总线Bus-Off时, 100ms后重启.
" s" W! J& Z  E! c( I
7 F) q% J+ T5 ?. ^设置完后查看设置状态 ip -details -statistics link show can1:
/ b, p% |2 x: N* t+ B
/ {3 |3 Y0 |5 K& g% G! U) }* O- p
  1. $ ip -details -statistics link show can1* i) V* l' N/ ]! O. r2 m- ~( ~
  2. 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000' b' u2 |9 S7 X5 n4 _
  3.     link/can  promiscuity 0
    $ h# h. N/ u. a; [# O
  4.     can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100 8 K% B' F; ?0 C# d' P
  5.           bitrate 498701 sample-point 0.792
    / }& M! p2 q+ K+ v! G/ [/ @
  6.           tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 13 O4 O  T. s9 l
  7.           mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1
    , n, F4 j# r  P" |; C
  8.           dbitrate 2021052 dsample-point 0.736 ( J6 }; s+ h$ j3 K, e
  9.           dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1
    0 O8 c: B# K* Z  x
  10.           mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1# }6 B7 g, u& m" W0 b$ _" r3 K9 a
  11.           clock 384000008 o# ^0 F0 u% |6 p) G
  12.           re-started bus-errors arbit-lost error-warn error-pass bus-off4 n3 k& ]8 Z- F% o. k2 h. {
  13.           0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    * S( i$ D$ q1 ]; {, ~, s* P9 K
  14.     RX: bytes  packets  errors  dropped overrun mcast   ) W* {2 p2 ?9 e7 j+ E( o
  15.     64578440   1013451  0       0       0       0       " w1 ]; E) R3 J1 m
  16.     TX: bytes  packets  errors  dropped carrier collsns # {% a! I  G! ~. @5 v& L; d# U
  17.     952448     15914    0       0       0       0   
复制代码
位速率和采样点的些许误差测试并无影响.1 w5 i% X% X+ y+ I$ b

5 O( U1 Z+ f1 N: `9 p: t1 I, u7 ^使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:
  E* G9 `$ X: X# K; M
' B/ n) E0 Z) m
  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
    5 M) a) i$ O0 C$ \2 q' 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 3F  ?4 H! y/ x, V8 O
  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
    0 Z1 a/ O1 v7 x& _" w7 N' G
  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: V$ X# s9 T2 ]5 c, r- |& G
  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; W6 ?: `% _  f/ J. O
  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 3F
    ; W7 x8 t' C7 P% B1 m! M# j* x
  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$ k  J4 a8 C$ c( z  y# m! N8 Y9 K5 z
  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# [; [' P( {4 @  U: C
  9. : a9 K* R8 T5 M! n+ z. j# s& w
  10. ... 3 G7 ]7 ]$ Y1 g' \1 [/ I

  11. ; S5 p+ v9 k" v1 a# b% C3 j
  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 3F
    , ^, g/ K9 O! a. Q& a) V/ E: z
  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 3F7 q5 ]- I# i% x! O: Q! n; p& a7 z; B
  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 3F
    ' C: G4 |. n) k+ \) K- @9 C
  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 3F& ?! m+ d1 w! u1 n+ _- y; D$ r& K
  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
    : U. |% s+ K( j- v% g2 e6 X
  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& ]5 d% p" \! e# ?& h
  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 3F
    - F: }  _' |! ~0 d& u6 b4 P' w
  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& W1 l* l) s0 L, T: N
  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
复制代码

; Q& D9 ^$ t: s, B这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.. ?8 n. T: k$ [( A+ E% D

; V( ~$ H4 U: n4 T1 JXavier发送脚本, ##后面的3表示开启BRS和ESI:9 y6 C9 ~. m# X/ T
5 z8 d! g* j( {9 ^* I- ^
  1. #!/bin/sh2 I; X- w4 f+ v* D( l( a+ N9 j
  2. ) V' G9 ]1 t0 U4 b( y' c
  3. while true; do
    ) r- B! O+ W, v- b* W# |
  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
    ' {+ v- F( i+ G4 F
  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
    ) s* q+ v9 y% @! Z* }. Y4 }+ i
  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  3 N, E( m2 I: S8 f2 A0 ]
  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
    0 p& l1 R  r, B/ t3 c2 z. a0 M
  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% J/ b  k3 Z3 Q) L# J( N# y
  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  + f$ m- s/ d5 T7 a# ^- _$ E
  10.     sleep 0.01- k! V0 D5 F- }0 w. F
  11. done
复制代码

* m# z! D! L: L可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
: |% s* K3 [' t: a6 R8 p7 m1 s$ ?
核心思想是:
1 L3 ]5 ^( z& v2 [
  M, d# s1 |- x5 aMode 设置为Classic Master或者Classic Slave, 而不是FD  ^1 k# ^9 p% J7 D+ f# l. l
仲裁段和数据段的通信速率都设置为500Kbit/s7 \8 @7 e5 r6 [) b3 u0 v
9 D  _' X% z& c4 }0 V( J8 \( `9 e
; X! o" _/ n' k$ d
$ [. C6 h, H3 o# l, d) p
赞 收藏 评论0 发布时间:2021-11-11 22:00

举报

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