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

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

[复制链接]
STMCU小助手 发布时间:2021-12-8 22:00
前景提要+ w  x# w7 y+ J
CANFD基础知识可参考前篇:
0 x2 d% @% S* U# C% yJetson Xavier/XavierNX/TX2 CANFD 配置使用  W; N) g/ k3 v% |% X
STM32 CANFD 基础知识
6 O( I# x" T- k$ L$ W+ E- P本篇用起来, 连接关系如下:/ S) _/ D( e$ ]% L
- h) h8 B& N. N+ z8 z9 J# V) m
20210222185812381.png

# n& z4 U7 @7 _- B5 M. P$ d0 u2 F" V) w3 _! l, O. O
CAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.  i$ _; k& D: J& h+ H3 a; s  {

' C9 P& T1 i7 d+ j) q5 NSTM32工程搭建' }/ f2 c+ r9 b% o/ x
STM32CubeMX配置步骤如下:0 e6 S4 V$ @6 i' B" s8 V2 `3 d

2 @9 D* O* V: v) K8 oMCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
6 O* R5 p" ^# k/ U: g+ A" c% v7 b1 s( u( e. I2 f( f* C
调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire9 `5 c3 O1 R0 ]  D$ Q) [, w/ r! _

+ H1 Q) j0 _- n$ V0 @* DPinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
: T+ `2 {6 }! |8 [( }/ E* x! {. \5 a* y" s+ w- b1 L, S2 h
Clock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):7 D8 ^& R; V" G, t8 ~$ A* p& N+ A
20210222185828575.png
4 z- S6 J7 R3 p; O
; `; T4 U+ u4 S" U0 S
开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:
# ?7 K( s, v6 \1 X$ l& U( V8 G, H- `# L( I+ R
20210222185846781.png

# P1 C: E# ?" G  v' R# W; i$ k' w, ~  _$ ~: O) Q# F
20210222185905935.png
2 f' [4 m' x- G& B
: L2 ]5 n- J$ e
LPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:
  Y1 H+ K, p5 T/ J! O) k
7 }: W1 }4 c# D; `; c
20210222185926920.png
: ^( i, s3 j7 ]& I+ D: t
" E3 o4 J( C6 k0 O) t
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:
, E& o( }. ^* H6 |# [: e9 q
9 A1 h7 T; F, O$ ~
20210222185949803.png

) L& A% Q5 e& v4 m, Z; `% F: c" f' B& S% H, _
20210222190005173.png
; d/ U( `3 L8 B4 g& Z

+ w# P1 N3 I0 {& \- I/ xFDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:7 q& B% K5 f" T2 {0 ^+ J

1 ?6 z! _6 r9 C, t
20210222190054536.png
+ ?) L! b# d- T% f( Y  A

, u- e7 Y/ m, w3 k' f1 KProject Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点., O, p# Q9 L% b7 t# P* l; g3 V

7 l: q( j; s$ \" {/ [0 r! DProject Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral
; n6 n9 a+ T3 Z
: a# [4 T' S* R- h点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.4 j1 k4 b3 X5 ^8 e0 J. Q8 A

4 u' ?' K/ g$ Y  EKeil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:
+ [: }' `8 t. d: h- J, c% ^7 I  ?2 z7 Y
Flash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行./ V+ ^. _% @3 w% A
Pack选项卡, 去掉默认的Enable勾选
- X! ?+ N+ N$ [5 m到此配置结束. 下面是手动添加的代码详解
5 n* b' B8 U' T! D" b7 e5 F2 B
- u) y2 \4 E9 x  V. ?( h3 s. R串口配置
# q6 x5 B; I5 }为 LPUART1 添加printf支持:# g5 O7 |* P7 x$ }" t# g

4 A( o" K' l( C8 @
  1. #include <stdio.h>" c2 f9 e# T( ^/ U6 N

  2. + j: b& y  [/ ]$ \; N: K# a' {
  3. #ifdef __GNUC__2 W$ |2 i5 P5 ?5 N
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    : n$ b8 W. ]7 j" t5 c3 T! Y, G; I
  5. #else! o+ d% o# `" H8 e% C- X
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)# g* E5 s/ H1 x9 M4 C3 f
  7. #endif /* __GNUC__ */3 M, Q; U9 e- O/ K
  8. / J7 U9 y$ I7 E
  9. PUTCHAR_PROTOTYPE; V. L5 Q$ S' n6 s& t: q. N  b
  10. {
    - `5 Q8 o* p8 r1 U8 @4 x9 B9 e( X' J' ]
  11.   HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);( f1 ]1 [! [6 L8 r- Y$ A# q4 J& l
  12.   return ch;
    + }* h+ O$ ^' a1 H" e* o9 Z2 ~
  13. }
复制代码
* k; x$ |) {. Z
100us定时器' ^' H- s+ d) m+ i
因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.
  A" T! [7 X8 Y: {, r' @& w
7 m( ?/ N, u5 |: c6 q
  1. /* USER CODE BEGIN 2 */& Z5 K9 s( r  Q  V; e
  2. HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.% W. Y5 P. S8 I8 l1 b- O2 Y
  3. /* USER CODE END 2 */. S0 _! }' x' _. i" R1 `; N

  4. * r6 ]* q' I$ o, N2 s. i. B5 \2 m2 r
  5. uint8_t tim6_flag = 0;
    . X. T1 q; [- [; z/ w, n
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    * R9 e* r9 N( X: ~5 w
  7. {
    , u3 H! n, P& R! W5 j+ F% _
  8.     if(htim->Instance == TIM6) {; D4 w- Z4 P" C# }4 Q5 E
  9.         tim6_flag = 1;
    - Q: H  E1 ^" [/ K+ L4 ?
  10.     }, n- F9 L  t* n6 q) s
  11. }
复制代码
1 K  Y) p5 D2 ~$ y' X
FDCAN配置
3 b  L) G! N% V, B# V% w$ a主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.
* n+ m. B# T5 W. L1 Y. ?) b: f; j; B: e3 i
  1. FDCAN_FilterTypeDef sFilterConfig1;9 ~, E4 M+ [# [+ C4 ]! }' z1 c

  2. " {: C1 S& Z! k5 a* ]6 R7 u
  3. void fdcan1_config(void), n# P1 n- u: j/ w& }% o! D& u+ O
  4. {
      v- A5 ?  o$ }  H* _6 M
  5.   sFilterConfig1.IdType = FDCAN_STANDARD_ID;
    8 L# @& i. e2 H% w1 Q" d
  6.   sFilterConfig1.FilterIndex = 0;% P" L) j* |5 ~3 s+ }& Y% E
  7.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;8 ]# A5 b2 ]  j5 X' H4 N
  8.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;$ \  k+ I) t& [
  9.   sFilterConfig1.FilterID1 = 0x00;
    / A8 l4 y5 J) I
  10.   sFilterConfig1.FilterID2 = 0x7FF;) z) S1 H& i+ z0 r
  11.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)
    3 g' @  ~$ b( A! L* U9 x- G
  12.   {
    % e6 }; D$ B6 a# D) x
  13.     Error_Handler();/ ]: H6 S) c' p! k
  14.   }. s! w4 E7 Y( M. ^) B, c3 u+ ?

  15. 8 T  D  L1 @7 R+ ~5 J. ~
  16.   sFilterConfig1.IdType = FDCAN_EXTENDED_ID;
    ( M2 ]( D: Q$ g/ @
  17.   sFilterConfig1.FilterIndex = 0;* x* l3 o# q% X. b! f
  18.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;- r- ^6 q  J  Q9 v1 q
  19.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;9 s0 a3 v& g5 v; E" E, S$ n! K% v) r: N
  20.   sFilterConfig1.FilterID1 = 0x00;
    / L! g9 q6 d& I' }+ S, L
  21.   sFilterConfig1.FilterID2 = 0x1FFFFFFF;
    1 F  ?! [4 u2 o
  22.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)& d6 c0 j# _+ N
  23.   {
    7 r6 u- Q! T3 r2 S4 U! N
  24.     Error_Handler();
    4 k9 h7 S$ x3 [5 J) s
  25.   }
    # W. g( v3 }# U: S

  26. " f3 L% N  m# L& p/ s9 _
  27.   /* Configure global filter on both FDCAN instances:& D5 j4 \  s  `
  28.   Filter all remote frames with STD and EXT ID$ @7 V: J& d* Y' x/ i6 |
  29.   Reject non matching frames with STD ID and EXT ID */: |$ |& j- l  X9 g: a7 P. e
  30.   if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
    ! B2 {' ^. I' T* b
  31.   {
    9 V6 q! u; ?* |! D
  32.     Error_Handler();
    - B0 I4 z2 c# L9 L6 D: U
  33.   }( X4 ]; ?" h3 A% k

  34. ' S/ F, a( n" [- C) J( m, n
  35.   /* Activate Rx FIFO 0 new message notification on both FDCAN instances */  [0 g  k; |; B% L, O
  36.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
    ) O6 H7 ?: Q5 G6 B
  37.   {
    : s: M. J) f2 I1 E
  38.     Error_Handler();/ p$ v. y, Y+ z& c; @7 z# N) |, S
  39.   }% E( E& j2 k2 K" o! x: j9 i

  40. % r2 `! s) d) O# U2 R$ Z+ U) y
  41.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)6 A+ g( {( M0 }; R' H7 a
  42.   {3 j- @. l. D  Z$ w
  43.     Error_Handler();
    ' r+ N* i7 t% q; W; `4 z) O
  44.   }
    + T& Z3 N' f0 f! |8 z

  45. - V) D' z7 |1 f/ x% F
  46.   /* Configure and enable Tx Delay Compensation, required for BRS mode.& S+ y* N" ~2 w1 u2 w" O
  47.         TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
    + Z2 {- ]0 [. k/ y
  48.         TdcFilter default recommended value: 0 */
    9 X% F2 d9 E6 j
  49.   HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
    7 e% o$ i9 J* A+ r- V4 k7 s
  50.   HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);9 j+ r! T! F. D- a" I
  51. 7 k- t- ^. T( h$ I, P
  52.   HAL_FDCAN_Start(&hfdcan1);# G! n& Q- o$ O3 o( g
  53. }
复制代码

# Q: T0 z7 l$ x4 y, K9 r这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:
2 Y6 T4 z( h! C' \1 `
  1.   sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
    + n' _4 F8 m8 V' k$ E( G; _
  2.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;8 M! j) I0 o; Z9 F' b
  3.   sFilterConfig1.FilterID1 = 0;
    " |; c% f/ z; Q' V5 m! q3 p1 ~
  4.   sFilterConfig1.FilterID2 = 0;
复制代码
用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.+ d/ z% y' L! {& d# `! D3 c! R

7 l7 R: R; k4 k2 U有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:5 m8 {$ }- ?, `" M/ ?3 y, @  Y
  1. #define SRAMCAN_FLE_NBR                  ( 8U)         /* Max. Filter List Extended Number      */
复制代码

) E. M8 c/ D, J1 S* C4 uFDCAN2, FDCAN3的配置和FDCAN1类似.8 y! c* g3 Q2 a) S9 T& l1 P

7 y+ }' V  V- d0 P/ i$ PBus-Off处理3 P8 y5 d+ w% v/ g% m% m$ g
如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:
" ]2 |9 H6 H" Z$ }" T6 n8 P: z6 M4 w: j7 Z
  1. void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
    : d0 _* _: F* [$ W* w4 p+ O9 D8 F, H
  2. {
    , V8 R! }7 B: {! R, E
  3.   //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);
    : u4 v8 j6 a7 L9 J3 J" i4 n
  4.   if(hfdcan->Instance == FDCAN1) {
    ! Q: [. p7 J/ _
  5.     MX_FDCAN1_Init();
    # P  G3 ?: Q: M9 u
  6.     fdcan1_config();  ^9 {, z# M# N5 A
  7.   } else if(hfdcan->Instance == FDCAN2) {$ a# _# N/ P8 O8 c; a( I
  8.     MX_FDCAN2_Init();
    + G- G! O( K, l! y) ^, C
  9.     fdcan2_config();& W' v6 _( K& T
  10.   } else if(hfdcan->Instance == FDCAN3) {- w. {1 L0 Y8 c
  11.     MX_FDCAN3_Init();+ q% q7 y! H8 [1 ~$ T( R) c' G0 T9 q: ^
  12.     fdcan3_config();. M5 @! h( ~) R7 n  a
  13.   } else {
    0 u6 s/ c; O: t+ l% f; E
  14.   }9 G2 p" N4 m% e8 d- C2 }% ~
  15. }
复制代码
6 R- v, n' s, Y" ~8 z3 N  Q/ m
新消息接收处理

$ e; K9 C2 _: y5 _2 N; u直接把接收的消息通过2M波特率的串口打印出来.
0 f* N5 q3 O0 @+ m) C% n7 ?
  1. FDCAN_RxHeaderTypeDef RxHeader1;
    4 |6 z0 l6 T! }& T
  2. FDCAN_RxHeaderTypeDef RxHeader2;! ^9 e' T$ W: x- C$ o' S
  3. FDCAN_RxHeaderTypeDef RxHeader3;: y7 I: I8 L, j5 V0 T
  4.   l7 y$ N  p( T+ |! @1 `* C
  5. //RxHeader1.DataLength => can_dlc* `& d4 K' K( c0 ]6 o# l
  6. //0x00000 => 0
    1 W. O/ J1 |& v2 Q, X
  7. //0x10000 => 1
    % ^( ~" j  ^9 i3 y1 F
  8. //0x20000 => 2 8 U* A# u, }8 z& Y4 b9 }
  9. //0x30000 => 3
    , U9 c7 H% }: T6 F- ]  n% U
  10. //0x40000 => 4
    2 h1 _! Z# e) A; s% E; `
  11. //0x50000 => 5 & c/ l- V! D. o5 E3 }7 A" L
  12. //0x60000 => 6
    : ?+ @! W" o6 f. f2 k
  13. //0x70000 => 7
    1 Y$ R( \% A1 e  T8 B5 s/ K' Y9 {
  14. //0x80000 => 8   A$ a$ r- |$ I+ t6 s* ?) f# @) [
  15. //0x90000 => 12, Y6 _  u7 t1 n$ P
  16. //0xA0000 => 16
    - L# ?2 h$ V9 z6 p. B: @# {1 l
  17. //0xB0000 => 20
    0 k  d3 `$ t2 l( i) Z6 K) J& Z
  18. //0xC0000 => 249 C4 X, p9 O4 ~/ |% x: b
  19. //0xD0000 => 32
    7 n4 {" q/ x. y; Q- C% d, e
  20. //0xE0000 => 48
    % x1 Q& i5 `+ [; X; h, i
  21. //0xF0000 => 64# G0 ?' c8 B9 N# f! ~; A$ y
  22. uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
    * Z4 D9 g* r0 q* ]
  23. uint8_t can_dlc2len(uint32_t RxHeader_DataLength)# R; _5 L! n3 i
  24. {) R! L& i8 t' b" [
  25.   return dlc2len[RxHeader_DataLength>>16];8 X* E0 u" ~9 U9 _8 t( c
  26. }
    ' W  |0 z3 e$ c  \& A

  27. ! U1 P  ?3 j+ u* V
  28. uint8_t cnt = 0;
      r3 g! C: k8 ^- C5 U* K2 r
  29. uint8_t brs[] = {'-', 'B'};
    ' x7 A$ h4 @6 A3 k( @$ L$ p5 W
  30. uint8_t esi[] = {'-', 'E'};
    # L; ^, O8 [3 |: ?% x4 ^7 w5 t
  31. void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
    2 _2 I- F. x$ ~. i. ?: u3 T
  32. {6 {3 t4 B+ a( h3 @; _
  33.   if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {1 d/ U8 s* N3 x+ G
  34.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    ' P" ^4 |% ^8 b9 v
  35.     //RxHeader2.Identifier++;" y- M- {5 V, r5 D& p$ b& D
  36.     //fdcan2_transmit(RxHeader2.Identifier, RxData2);
    . B8 ~" w" o$ |  F3 }
  37. 2 e* M7 m8 B/ V9 h& F+ T  S& J- [
  38.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    , q1 E2 n& A) d( u
  39.     //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));
    6 D5 E& O: G9 I* a7 ~+ X4 }. S) L; Q+ y

  40. 7 J- P  s. C9 M; I% H
  41.     HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);# m5 m4 r2 M5 s' X' y5 m( j
  42.     if (hfdcan->Instance == FDCAN1) {# U2 [- r4 K1 y$ C1 m' w4 _
  43.                 printf("fdcan1, ");
    - `0 A+ M' s0 W" _* A
  44.         } else if (hfdcan->Instance == FDCAN2) {
    ; O4 H$ _# S* u: P) k9 w3 F* O
  45.                 printf("fdcan2, ");! t2 U" ^' @4 d0 f
  46.         } else if (hfdcan->Instance == FDCAN3) {% B* j7 {" M7 q
  47.                 printf("fdcan3, ");
    % y- X: t" N5 n# b( R; m& K
  48.         }0 y" v. c. ^- u* y; V
  49.     printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier, $ {& `# M: S# J5 N) L
  50.                                   can_dlc2len(RxHeader1.DataLength), " {: q: N9 e3 a1 i) g$ i6 A
  51.                                   brs[RxHeader1.BitRateSwitch>>20 & 0x1],- P3 `7 ?: E- v+ `% M: W* x, y
  52.                                   esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);, c4 C1 B% _5 d, \
  53.     for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {
    & s+ @9 Y8 H. O9 y
  54.       printf(" %02X", RxData1[cnt]);7 }8 g  x) Q$ L* {3 x  V
  55.     }
    - @: z/ Z. P9 m" M# K
  56.     printf("\n\r");: B/ T1 V+ R  t4 x% u* [

  57. * o: ?: N, m4 w) I
  58. % j% {/ b. h3 X: p
  59.     //if (hfdcan->Instance == FDCAN1) {% g$ ^3 t* P$ Q9 Y+ A% K3 h$ o- t
  60.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);$ O7 m- f* p% x9 _& a
  61.     //  //echo
    # q( f' a. p+ [4 F- ]0 L
  62.     //  RxHeader1.Identifier++;; g1 Q7 v+ t' ~6 [9 @8 a! B
  63.     //  fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);5 c% c7 w. Q# z
  64.     //} else if(hfdcan->Instance == FDCAN2) {
    - \. b7 @. H$ y
  65.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    4 p& n2 j, d2 Y5 {4 k8 I3 q
  66.     //  //echo
    4 z# N  V5 \8 w$ s& q* L' |. H
  67.     //  RxHeader2.Identifier++;1 `- W9 K. j& _; S  C) D+ t2 i
  68.     //  fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);0 g$ P- |0 g3 i; i' H6 ~% d" x/ r
  69.     //} else if(hfdcan->Instance == FDCAN3) {
    : w* [8 Q+ K" x. X
  70.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);# T$ c6 P$ W- F- r
  71.     //  //echo# j3 q9 o8 W$ `6 j# _1 W
  72.     //  RxHeader3.Identifier++;
    2 c2 A5 _& N  u
  73.     //  fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);
    - f# V, W% Q* s3 l  [
  74.     //} else {
    2 D" m1 H5 Z. T8 n  E8 @. \
  75.     //  & C  D) f8 p  m! s! [8 ]% t
  76.     //}% u; \' u  [4 f1 f% d8 j  p- y
  77.   }
    ! v! T# W$ x# h; }& g# `
  78. }
复制代码

" t6 J/ G4 R+ q& Z  U7 H注意注释中 RxHeader.DataLength => can_dlc 的对应关系.
: a# E, g2 N4 j1 K. N5 L, Y9 w3 p3 x( E/ W5 R
示例如图:
( P7 C) V% t4 y* ~% w' P2 M- m* ^
; B8 K+ x1 f8 K! L8 F
20210222190024669.png
' @, `6 e4 w8 z# w0 c) F$ ^: X

! [7 q) Z/ ?+ f' G+ k1 L图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.( }% w+ w) B- M( W% H$ Z) g

0 _; k2 ^3 W, F& @: j  G$ Fprintf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.) d/ r4 ?4 a/ S. u, W

8 H4 V5 a$ E  |. u! i. [发送处理
" q& c' w! R3 F( C. |发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.
5 b$ c' h" z, J3 ]* O& K; u" e3 d- m
6 O+ w& J% \$ o" l$ g2 |2 e0 P8 I
  1. #include <string.h>
    . s/ `5 o/ l" A6 Z7 v$ q
  2. : ?3 U0 G# N. b- I: r/ h
  3. FDCAN_TxHeaderTypeDef TxHeader1;* M. t9 W. d" r
  4. FDCAN_TxHeaderTypeDef TxHeader2;
    / Z5 d1 T& i! h% _
  5. FDCAN_TxHeaderTypeDef TxHeader3;
    3 ?  v# @" k1 u# y
  6. 7 Y7 G% M, Q9 u
  7. typedef struct {
    1 p6 J; \" ^9 Z0 {% Q! \+ O, ]
  8.   uint8_t flag;
      p/ {3 M* X3 U% x9 G
  9.   FDCAN_TxHeaderTypeDef TxHeader;
    , ^. B( w' d: ~. x" M
  10.   uint8_t TxData[64];" B2 `1 X6 M% I4 n: k
  11. } FDCAN_SendFailTypeDef;; I/ K8 F3 }9 a8 L/ j1 x& k
  12. 8 F: z( z3 U" k- T4 B
  13. FDCAN_SendFailTypeDef fdcan1_send_fail = {0};
    ; ]! Y- Q  B, \6 X0 b" u) ~
  14. FDCAN_SendFailTypeDef fdcan2_send_fail = {0};
    ! G+ R5 \4 Y, i: M1 e+ g9 ?( E
  15. FDCAN_SendFailTypeDef fdcan3_send_fail = {0};9 _! g# [* ]7 y( s  `/ C

  16. 9 y7 y# ?5 E& L0 X3 Q* B+ h& M( m
  17. void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
    6 E' Y4 X# M) u
  18. {1 v% t* P% h& R0 h) [+ p: N
  19.   TxHeader1.Identifier = can_id;. [1 f7 z% T( k5 D1 F% E( a6 ^" h
  20.   TxHeader1.IdType = FDCAN_EXTENDED_ID;
    ' ?" C; S( p# D5 `
  21.   if(can_id < 0x800) {  //exactly not right
    # j6 U, f) O8 S( A; i
  22.     TxHeader1.IdType = FDCAN_STANDARD_ID;7 S3 a/ u. K! @3 a) g7 }/ |
  23.   }
    / L+ u- V3 V$ J5 Z: d2 r
  24.   TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
    8 }$ J  d3 M8 C5 U; r: Y! V/ m' z7 C
  25.   TxHeader1.DataLength = DataLength;8 t& r8 F/ ^' z$ v
  26.   TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;- B" Y6 Q7 M+ y, V- _6 w# d
  27.   TxHeader1.BitRateSwitch = FDCAN_BRS_ON;8 D1 A3 J3 _. z- I" J- V
  28.   TxHeader1.FDFormat = FDCAN_FD_CAN;: P& A' D- ~! ^/ h0 X: p' N
  29.   TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;2 j) m/ o) G& {3 J' T
  30.   TxHeader1.MessageMarker = 0;        //marker++;        //Tx Event FIFO Use
    3 g+ L3 {1 e1 ~3 b
  31.   if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {2 g6 ?  {' b' e# ?
  32.     fdcan1_send_fail.flag = 1;5 p, _. X4 |3 a! I
  33.     memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));; Q9 m( i2 E2 Y2 ]6 g4 ~
  34.     memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));, Y( S. r6 b2 T; `6 h' O
  35.   }
    " d+ C* u9 r3 s+ p5 n
  36. }7 E1 @* @6 }0 ], `! S( ?2 g" V/ ^* {0 T( L

  37. 6 K" [4 G8 N6 a% M
  38. int main(void)
    # ]5 m! V( U- p1 z) j
  39. {
    # H" B7 y) b5 c9 [# n
  40.   ...7 p' f/ n6 q3 h. \9 Y
  41.   /* USER CODE BEGIN 2 */
    - d4 E: U2 t: z! q: v3 ~( J
  42.   fdcan1_config();
    ( {. m" n2 t) b4 @
  43.   fdcan2_config();
    ; S1 e- R, p3 p- }
  44.   fdcan3_config();$ p: d& e$ ~% T0 g+ O
  45. , [2 H2 Q; z( g3 g& `9 s- A
  46.   for(uint8_t i = 0; i < 64; i++) {1 ~% ?0 A& ^) h; E* F7 R9 e$ t
  47.     TxData1<i> = i;6 P9 S( @' {: \; a0 S8 a6 ~
  48.     </i>TxData2 = i;
    , e' e  P4 I  {. [# ]1 U( c$ _
  49.     TxData3 = i;4 [) o+ X' Q* c. A- ]/ U( v( W' X
  50.   }* a+ t5 \7 z  F; K& i* }4 m
  51. ( }( o( W' Q8 H6 z+ }/ R% B) f
  52.   HAL_TIM_Base_Start_IT(&htim6);+ u. N0 T5 j) r8 B
  53.   uint32_t count = 0;
    / t- Z  o/ @0 A! q- N& T
  54.   uint32_t cnt_100us = 0;' \- b( b4 I$ x- P; k, m1 K  i
  55.   uint32_t cnt_500us = 0;0 n: Z: l5 k, `3 {1 v; t% [
  56.   /* USER CODE END 2 */$ I: D( V4 ~' `2 z4 J

  57. % [+ m) w3 \3 ^' s  r
  58.   /* Infinite loop */# c' f; I+ f4 O4 m/ A
  59.   /* USER CODE BEGIN WHILE */, S9 m$ r- U4 N+ m, I7 ?$ F0 _+ n
  60.   while (1)$ e4 r, Z. Q: t! g  ^2 X7 E
  61.   {
    6 a3 ]7 m7 D7 `- X' f
  62.     /* USER CODE END WHILE */
    % p$ c5 J7 t8 v; @

  63. ; \' ], E% _# i/ N
  64.     /* USER CODE BEGIN 3 */$ x% R. J' W' _. Z8 `6 a$ N% P
  65.     if(tim6_flag && count < 1000) {
    : M  v2 l- X) P' Q" K! G
  66.       tim6_flag = 0;
    ( u9 y+ S7 i# B% @9 i! y
  67.       TxData1[0] = count >> 8 & 0xFF;$ Y- d# e  b. X- n  n
  68.       TxData1[1] = count & 0xFF;
    8 j! K/ G, s" m3 r

  69. 0 F0 s- p  U- t- N% d4 B% T
  70.       ++cnt_100us;
    # e/ J) l  L- ^+ ?8 `* |' s; m
  71.       cnt_500us = cnt_100us / 5;
    7 O  p1 C' }8 o; H/ o( t' o9 c
  72.       if(cnt_500us && (cnt_100us%5==0) ) {& \% Q- d6 [. E4 Z; e
  73.         switch(cnt_500us) {
    $ r+ G1 t: u- F
  74.           case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1); 9 V% Q0 k9 y2 j: o) V
  75.                   fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);
    ! _% t& E8 X9 p
  76.                   fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;) p- @9 N/ S3 S/ }- H4 U
  77.           case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;" @7 B) {) r9 Y0 @
  78.           case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;
    % k" K: ~3 ^3 S5 M: D5 F5 d
  79.           case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;; G. G8 S4 ]# \/ ]+ p  U7 }! O
  80.           case 7: /* next send */ break;
    $ O, D( \6 e: a6 A& n" ~1 C
  81.           case 8: break;
    2 j9 W7 [$ H1 I. O# I+ f+ K
  82.           case 20: ++count; cnt_100us = 0; break; //10ms/ G6 q7 K) ]0 M  h( f
  83.         }8 R: M. o1 h- v( R, W2 q
  84.       } else {  //fail retransmission once' _4 o3 b4 i% a) _4 O% z2 n
  85.         if(fdcan1_send_fail.flag) {
    0 }! [, M) s5 I/ P4 }
  86.           fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier,
    ; d' t# X- l' O4 M# H, f. B
  87.                           fdcan1_send_fail.TxHeader.DataLength,7 T9 X. m7 c7 a2 l+ z" X
  88.                           fdcan1_send_fail.TxData);
    ' d0 n% t2 P$ K
  89.           fdcan1_send_fail.flag = 0;
    ( w5 ]* J) b& o8 Y
  90.         }
    ( |+ w2 j2 b1 z' C* o
  91.         if(fdcan2_send_fail.flag) {
    * Q6 }2 S0 F7 h  `) R" J( u
  92.           fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier, : h9 n' E+ m! y( i8 f2 o
  93.                           fdcan2_send_fail.TxHeader.DataLength,7 y/ n6 ~) H* e( @$ ?) K# C" I
  94.                           fdcan2_send_fail.TxData);
    ! y5 h, `/ v: J. [5 E
  95.           fdcan2_send_fail.flag = 0;
    - D8 T+ \) ]4 j
  96.         }% d  e( R5 o+ ?( N) \0 O  _
  97.         if(fdcan3_send_fail.flag) {1 n0 ^$ m! G- g: Z: D: Q* M3 p+ q
  98.           fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier, 0 ?; s' J$ C' Q" h* g
  99.                           fdcan3_send_fail.TxHeader.DataLength,/ T+ A0 U4 e! t
  100.                           fdcan3_send_fail.TxData);- o$ b$ @9 h3 H9 {& L' y
  101.           fdcan3_send_fail.flag = 0;6 k; c9 v" K. E% \8 y
  102.         }
    . Q! S: Z; a1 u2 z& o4 k1 M7 e
  103.       }: ~7 ?+ l  @# c
  104.     }
    7 ?0 o' }4 Q  U' d
  105.   }! k- A8 r# P" j" c( f  X5 B2 ~" Y
  106.   /* USER CODE END 3 */  2 ~0 V! y' Z0 j! S6 u0 `  y
  107. }
复制代码

5 u9 G( i& _. f/ w; O7 A) a8 d4 t3 ofdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.& T0 m8 V& K1 f) r7 B

/ L( C+ r- d' b/ q7 G7 _发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.
$ n+ C: U( z3 \: ^0 ^- v  O8 y
# }% {/ i9 G: S8 s7 T) n这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.
3 \3 |$ n: L0 L2 B
0 ^5 b) ^9 p4 J- c: M$ g因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧.
; i) b6 H9 `% {9 b& q/ F! a; ]8 D. ~! h! _; O, ^$ l! O4 F
因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.
' y, N7 L* r9 s; W$ P4 J# c; n8 Z% [) c: l/ ]
如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.& y) v# l9 {9 B6 D; m$ E
1 |% D" M2 |$ ^" m
一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.
! V& N+ y4 {3 W9 z1 y
4 n$ A4 ?, t% G5 c1 {程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.% ]* C1 j% l7 v6 {; k; M- {; {
* Z9 u) {. c' _+ l) M3 x, }
使用Xavier配合测试一下
* G* g: l1 f' K. o把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:
, ]% @( U# Y! u1 b- e1 e6 Q( v5 h, J" ~
  1. #!/bin/sh
    7 F* k$ r5 k# G+ E+ c/ w  F* N
  2. 4 a! B: N6 F+ j- F' _; T+ N9 M
  3. sudo modprobe can
    . a& i2 e* T6 H2 N9 z6 a8 O8 m
  4. sudo modprobe can_raw
    , K: |. ^. I2 x, h$ K
  5. sudo modprobe mttcan/ p7 c7 y5 ]* t. n  L, b

  6. 8 t$ P# D0 T+ G
  7. sudo ip link set down can0$ p. R. D9 b  [' h
  8. sudo ip link set can0 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 1002 Q5 ?4 c! Q, h1 |# W6 [* k
  9. sudo ip link set up can0
    & `  |6 U6 `" t; y) E5 I( z  ~9 K
  10. sudo ifconfig can0 txqueuelen 1000
    4 `4 r" C1 K, l4 q: ?
  11. 2 \: T. F5 N( Q; }; R2 a6 p
  12. sudo ip link set down can1
    , Y4 u2 e; M. K& x) z( ^
  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
    $ M- J: y7 d0 P) Z
  14. sudo ip link set up can1- ?! L- r" T( J" V# A5 o  }; m
  15. sudo ifconfig can1 txqueuelen 1000
复制代码

5 m/ S) G/ u, Q  X# b( ^Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.5 y4 a1 F5 h. }8 K. f) F
* j* P" \1 t8 E+ A& F7 ~6 @
restart-ms 100设置总线Bus-Off时, 100ms后重启.
/ k$ i6 {* D; j- b
. O5 K6 R4 j3 B3 ~/ V: B设置完后查看设置状态 ip -details -statistics link show can1:6 {) F5 D) B" \$ ~" D8 g4 G
  U, i. R9 `! R; h% ^( A- Y
  1. $ ip -details -statistics link show can1/ }$ e/ }) J/ Z& C
  2. 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    . h' E  q- x$ h( D  U
  3.     link/can  promiscuity 0 * E# L) \& m8 b8 F+ y
  4.     can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100 & g  a" z0 }* C5 n
  5.           bitrate 498701 sample-point 0.792
    : k& E$ f) h& N% n$ u) |. o& P
  6.           tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 1+ o- ^0 [. x/ u1 j# U2 M1 {
  7.           mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1, P0 w" P1 T8 k5 u1 f5 X
  8.           dbitrate 2021052 dsample-point 0.736
    ( ?9 B5 ?; q+ n2 q8 t+ L' g
  9.           dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1
    # L/ Q2 e5 G! ?# E
  10.           mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1
      q+ @+ G0 f2 M. U7 G9 B4 }* j
  11.           clock 38400000
    : _9 Q8 X5 ^8 |' ?7 m; E8 o6 o
  12.           re-started bus-errors arbit-lost error-warn error-pass bus-off# I/ W' t$ }( ~7 ~
  13.           0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 - p8 Y* e( t" J  u1 t
  14.     RX: bytes  packets  errors  dropped overrun mcast   , Z: n5 r' u% Q6 h! A; T: U
  15.     64578440   1013451  0       0       0       0      
    - S( r7 n* `( G; ~+ p" S: ]
  16.     TX: bytes  packets  errors  dropped carrier collsns
    5 p7 W! ?; y! ~
  17.     952448     15914    0       0       0       0   
复制代码

/ a8 k* w9 o* D' Q% w位速率和采样点的些许误差测试并无影响.
( p3 ?% _+ ~) y) {  T' A$ t4 y
) F- R% W: A7 I$ N0 s使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:
& L) ?$ D  k+ W5 G+ Y# z; H/ [* K! l4 f2 \- t4 n6 o
  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  G9 A* c0 g8 V" o+ }
  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, [9 Y3 x  K) b! G% z7 K
  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
    3 `% s6 |9 B: E/ `+ Q' x, c
  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+ i( U, h, N8 M( @, Q, Z) I, C8 x; ?
  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 3F6 Z8 M* O$ {4 s% \7 h4 x+ I
  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, L: |% m) n% h/ E) b
  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 3F4 l- E$ d) u4 z1 a* ]
  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
    % T+ v, z- _/ @1 c* m

  9. & s8 `/ |1 W& X) T* S: H/ J% c
  10. ...
    " J4 V6 R! K! [' y5 W! T& S
  11. $ C2 z  P0 v2 \* J( c9 G# o
  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$ ^/ |* W! j6 b! d" s) I9 f
  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 ~; d' \- b) \" J* `5 F+ s
  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% @! b5 D8 E8 h/ F5 `# ~
  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: I% n6 w+ N' [/ k$ b, }/ h# s( s
  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) L! A1 ^) X: O# P
  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
    - c' ]# t  X: \3 w
  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
    4 B+ h( h. f/ ?' Y! r# S" q& p
  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 3F4 _$ x* ]* F. U) V0 n4 a
  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
复制代码
' v9 V5 n# |- d" U. y) m
这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.
% {; I- P* @0 d5 G3 r
$ G% a4 P3 V' g3 Y; }; NXavier发送脚本, ##后面的3表示开启BRS和ESI:
/ |3 t" J8 D: p3 Y* k5 u7 _& N& W+ Y0 P+ f: C- }; y5 [
  1. #!/bin/sh8 o  @% \- ~7 k$ x; G: v& M+ A* q" b
  2. 3 c' g% T; j% M* U2 ~" E6 _
  3. while true; do! y- y- f0 i  X9 f1 u( J
  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.167 T: r  A: z5 L8 k% w
  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.163 J" ~% i. z0 [+ h
  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  ' W  Q/ A% v6 T
  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.164 N' [$ Z/ I( V% c6 v
  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.164 D6 D8 K' h0 V4 E
  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  1 S# ^. e/ \' W3 ^, z# x
  10.     sleep 0.01. ^# E* i5 p- [
  11. done
复制代码

. S* U6 x, q2 F2 \$ w% j5 j可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
8 O: _! z$ |/ p/ _% i
0 x8 A/ d9 E) P1 T& M. G0 D" w( U! s3 ~) b3 j

* h  q& P' V! x5 Y
收藏 评论0 发布时间:2021-12-8 22:00

举报

0个回答

所属标签

相似分享

官网相关资源

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