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

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

[复制链接]
STMCU小助手 发布时间:2021-11-11 22:00
本篇用起来, 连接关系如下:' `1 A% Y' G. G
. O, ^$ y0 K/ A8 J/ H; G9 e

20210222185812381.png


9 o3 t" X" ~9 y
& S' r6 S+ F1 b. b1 ICAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.7 M" Q; H% |/ h; J
& l  k& h: H% j# V! X, l
STM32工程搭建
( c% J$ I) b3 rSTM32CubeMX配置步骤如下:$ d$ x" }: R+ E  H( B# q7 b5 s
8 T: w8 [2 l: B+ r" M/ n% t
MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx  h3 m) l! f( Y5 d/ X( _  A) K  f% ~
2 s0 w  S2 `: G& P( G
调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire' {  T% O. ?5 u2 _  y, d
7 N: @3 i  z$ \9 q* R
Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
/ ?6 H$ l9 [, @4 `- m
" z6 u2 J3 K* P- aClock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):$ `; D: x. ~6 x7 [* }* ^: l

20210222185828575.png

; s. H' }, h9 w' F5 U

20210222195952515.png

& A) M5 Z- N& d. m2 z
2 j" ~# R. a& |/ Y
开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:- j; m6 r' z3 |* a
7 q) O4 A+ H" Y8 T7 Q! Y" o

20210222185846781.png

1 G# s2 i) i3 h& h& W) q

. e- |; o4 Z4 w, W3 C/ }3 O9 E* g

20210222185905935.png

1 t0 l: K! @- I
4 a5 T, q9 R+ \( B1 l' g
LPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:, d8 M( E5 A7 _- _& V0 o! j

- j. s" k" H+ @. q0 X; R" C

20210222185926920.png


  G0 `& }7 {* l2 B& k' V9 K/ U7 |) s# j! x
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:6 h, I% F1 K5 y' F6 I8 e1 h
2 d1 m1 c$ }" T) M1 p0 ^7 L4 Z

20210222185949803.png

9 O% h+ n2 N6 j) p3 x5 J( q7 Z
; O9 J7 a7 B4 H7 i

20210222190005173.png


4 z# ~6 w# S7 h! X2 w' p# s3 L  A+ H1 H7 O' E: }+ I& c
FDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:
8 {8 p9 Z9 P8 e6 z7 H1 e% E5 O8 m5 M- h

20210222190054536.png


: q3 k$ U7 o& _7 O7 T, i& T, T# H# X0 i8 Q( Y: t
Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点.' V. c9 l2 c) U4 R
- @( M# S5 A6 }( ^, N! Q4 b7 s0 M
Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral
( n0 S- f, G' K4 [* k/ W/ q7 f; C8 X( B! Q2 V- w. A, B1 b( A
点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.7 p6 |4 W/ j$ Q" f# X- B* G' U
/ |) T0 N7 d/ ?  u. {! K* H% ?
Keil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:# ^+ y+ Q; d2 C: {; I- r

+ X4 u( b; `0 v& f1 k* @Flash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.8 |  C$ B# a3 G; i3 E3 L; k( H
Pack选项卡, 去掉默认的Enable勾选) R6 y' L7 o& [* L6 O2 y
到此配置结束. 下面是手动添加的代码详解
0 z* z9 T1 C( u8 a% P  j+ g% K1 M( t) r2 Q4 Z8 A
串口配置
7 U! W- [. j# g5 q% Z& k为 LPUART1 添加printf支持:
9 M/ C1 ^* e+ o' f) r/ ^& I
' V, Z1 J, r, j4 H) E
  1. #include <stdio.h>
    # M  p/ v- B  q( ]

  2. 1 @" ^2 ?- H- n
  3. #ifdef __GNUC__* k0 f+ \% d# d! _! b3 B: W
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)* M/ R- t  e' V' X$ r6 I  U/ _
  5. #else3 ^; h' h: B5 E  H8 ]9 ^' _9 ]
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    " x1 H/ z& d' @: O; C3 p
  7. #endif /* __GNUC__ */
    - I0 d  V7 ^- e+ j

  8. ! v: g! ^/ u3 V' Y+ k
  9. PUTCHAR_PROTOTYPE- X2 N  d1 p0 R% j* L" i% U5 P
  10. {
    / a- H1 V) G% ~% M' a  `, u* r
  11.   HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
    ' l& [7 L* K3 t) @1 c! u
  12.   return ch;
复制代码
0 y( d+ c( l8 [; W
100us定时器
$ W% T0 [4 K4 N/ u5 }因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.$ L/ J9 H" }" i" `

9 J" P8 C+ i, a( g
  1. /* USER CODE BEGIN 2 */
    : H: d" k1 K  Q' O. H
  2. HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.
    $ C; m3 J& n6 d
  3. /* USER CODE END 2 */" O- s& [' L$ }5 b3 s! A
  4. 6 |2 u9 _, k0 e8 C  s( A$ p( g3 x
  5. uint8_t tim6_flag = 0;
    7 b: {3 [8 _. ?; G
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) . d/ P: a" k) i# P0 n/ U) l& y9 T
  7. {) V) r7 y- L' G4 n7 a( v; T
  8.     if(htim->Instance == TIM6) {; g9 i+ v/ m5 a8 Y  k
  9.         tim6_flag = 1;
    * \) A" ~" V/ |, L
  10.     }$ D& A, ~+ s9 U5 \! f& m
  11. }
复制代码
: T- D3 J0 ]4 E/ b/ V' n
FDCAN配置
% ]; [4 {6 L  g% T# l主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.
6 U6 K5 v0 @* R7 w/ A7 i9 z3 v0 o$ ]+ }/ Q! t: M
  1. FDCAN_FilterTypeDef sFilterConfig1;
    ! `' S& k  B$ E2 n' n% K
  2. 3 l  H  d. u3 b9 O- H; H+ p: v3 p+ I
  3. void fdcan1_config(void)
      b$ r" w  h: s0 C; ^9 Y3 z9 b
  4. {
    8 t$ g! Q9 U% R+ C3 }7 O; L
  5.   sFilterConfig1.IdType = FDCAN_STANDARD_ID;
    - {: ?6 n' ?1 P; @: ^& H
  6.   sFilterConfig1.FilterIndex = 0;4 y0 o4 k4 K0 c1 A
  7.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
    $ k% @: E$ F% }  `- h4 {* K) Q
  8.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;6 d  y3 E4 d+ T
  9.   sFilterConfig1.FilterID1 = 0x00;8 S/ Y1 ~! Q+ ]) P
  10.   sFilterConfig1.FilterID2 = 0x7FF;
    * e" Y' e! M8 T- \5 u- \. R
  11.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK): Q5 k; w7 P- W! V6 u1 m
  12.   {
    ! d4 g; q% x4 I
  13.     Error_Handler();
    / X( l: h8 C$ S; d+ M
  14.   }
    2 {! K& n+ ^! y" E8 P2 r

  15. 8 K1 y( J- U1 l0 w& @" ?
  16.   sFilterConfig1.IdType = FDCAN_EXTENDED_ID;  j. i  r0 h; a5 b- w- n" d: Q# u! t
  17.   sFilterConfig1.FilterIndex = 0;* L" _  _% _6 v7 L7 C$ t
  18.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;% l9 V. N# h* P" P
  19.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;5 ]) H6 X9 Y6 `5 _: E
  20.   sFilterConfig1.FilterID1 = 0x00;6 r9 C/ m& G7 ^' i
  21.   sFilterConfig1.FilterID2 = 0x1FFFFFFF;
    ) y# L- s2 m  X' k
  22.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)
    * j( v7 K5 n- a" d; q) V* I
  23.   {& O, X5 A2 A! w4 s' M  j4 C1 }+ k% @
  24.     Error_Handler();% K3 v7 t' }! }- `4 w3 z
  25.   }
    + b! b+ U- G- c! }
  26. , b9 c+ M4 t+ s3 F; g: b( M
  27.   /* Configure global filter on both FDCAN instances:# j2 M  M7 k( |+ w! B4 P- I3 ~
  28.   Filter all remote frames with STD and EXT ID, ~( l* Z- o5 c5 b9 m- D" u& {
  29.   Reject non matching frames with STD ID and EXT ID */8 I8 v2 X. ~7 s- ?1 U) e" A
  30.   if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)7 T3 z) X2 O$ {9 b& q
  31.   {
    % j+ ]: g& j" D. G
  32.     Error_Handler();9 d) I( H- l0 X( c* s8 A
  33.   }4 q6 A( q0 l4 g2 G8 m% E) H

  34. # E; u% l6 O4 ~- I7 f' U: b
  35.   /* Activate Rx FIFO 0 new message notification on both FDCAN instances */
    3 c1 |/ i5 v6 S$ F) k
  36.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
    % P  A& C+ `- T
  37.   {
    4 u& V' X. }3 P7 I. m& Z  n" S
  38.     Error_Handler();. P3 M* B) m; x3 g/ z7 O5 x/ a
  39.   }1 F( w- ~8 l9 W/ o% u' W

  40. ( _- P0 [6 K$ Z; \+ T( T
  41.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)& ]5 V5 Q! l1 f5 o& g
  42.   {3 g' e1 W5 Z' l7 `9 v# N. g& }
  43.     Error_Handler();
    : ]" I' w. ?9 ~8 y
  44.   }( Y3 S% f3 \* h
  45.   b! C" S. ^7 ^! l
  46.   /* Configure and enable Tx Delay Compensation, required for BRS mode.$ S* C* n" X% p/ M
  47.         TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
    & k0 l) C( [9 d; S, O0 b
  48.         TdcFilter default recommended value: 0 *// E; Y- y3 Q$ y0 G( ]& f
  49.   HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);- Z0 Q" V9 `/ y) O2 B
  50.   HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);
    / {9 Z" o7 v9 b8 a
  51. % J+ E; z( C1 F% G: \
  52.   HAL_FDCAN_Start(&hfdcan1);8 f# s* n7 O4 ]* @; S, P9 l$ E( r
  53. }
复制代码
5 j! j9 H" z- I1 j0 J
这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:, Q( i. V1 J5 V3 t8 k' h
  1.   sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
    0 w" A# q2 B/ K7 U9 b
  2.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    % G7 K. Z2 b! W
  3.   sFilterConfig1.FilterID1 = 0;+ y8 Q: M4 n( C. q: o9 ?, l
  4.   sFilterConfig1.FilterID2 = 0;
复制代码
( i6 @9 e# V. v: f% U! `
用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.
6 J! U' G* O* m5 }, J8 w8 g* j+ O( ^( j) Y; a/ o# R
有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:
4 T; d4 A& l- e" N4 v, [' a  m: M3 T6 c3 f
# g* {. x1 |# Y' j9 L! u
  1. #define SRAMCAN_FLE_NBR                  ( 8U)         /* Max. Filter List Extended Number      */
复制代码
# C% K& \% }3 ?% N: y9 Q  O, I+ G
FDCAN2, FDCAN3的配置和FDCAN1类似.5 x- Z7 u/ `# y+ K4 W5 o
/ S& x; T% {8 w) }0 P5 u# L
Bus-Off处理2 j( a& Z* V% s1 W
如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:7 K% e- D& b3 ?- ^

& o% Z  d; z' Z, Y( j0 z: y
  1. void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)2 n# f4 u% U+ Q! j8 Q( C! u6 H
  2. {
    4 U3 Q( D+ B2 Y9 `8 l
  3.   //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);: Y* L" a3 I7 `  }
  4.   if(hfdcan->Instance == FDCAN1) {* k; `4 l6 ]- R, v: a
  5.     MX_FDCAN1_Init();
    # _2 o6 \- I2 m
  6.     fdcan1_config();
    7 u4 }8 g0 g$ F1 s& t0 @! N
  7.   } else if(hfdcan->Instance == FDCAN2) {- ?. r$ L6 F  W  @
  8.     MX_FDCAN2_Init();
    2 ], s4 S/ l$ S, G9 i% v2 j
  9.     fdcan2_config();4 q% F0 s+ P! I" s
  10.   } else if(hfdcan->Instance == FDCAN3) {
    $ ~3 I+ U  z0 W, c) @
  11.     MX_FDCAN3_Init();
    1 C9 A% D( `) Z
  12.     fdcan3_config();
    4 i: r; h4 I$ k& x1 j
  13.   } else {
    : U1 T! ?+ k  S
  14.   }4 w5 |3 [  H" h) m( o- l
  15. }
复制代码

" f0 F8 N! C, n; C) K: J新消息接收处理
+ @+ S5 l4 {  n! r! W: `2 ~7 v直接把接收的消息通过2M波特率的串口打印出来.4 b: I) P. E7 F3 S$ u# i$ H
9 m" q9 n$ o6 p8 m( e- Z
  1. FDCAN_RxHeaderTypeDef RxHeader1;
    6 q3 m* _7 T4 l# Y/ X
  2. FDCAN_RxHeaderTypeDef RxHeader2;- \- I" F2 o3 _& v5 ^, G8 Z9 E1 `
  3. FDCAN_RxHeaderTypeDef RxHeader3;
      Y4 }) Z  @6 V) u5 j

  4. 1 G1 w: f% ^, G
  5. //RxHeader1.DataLength => can_dlc
    1 [; M  U2 L+ ^
  6. //0x00000 => 0 4 V# |8 P: U) j+ U* i1 m' a
  7. //0x10000 => 1
    . [4 @) ]! U7 R  L& G4 M
  8. //0x20000 => 2 7 o( U+ s8 Y6 Z& s
  9. //0x30000 => 3
    ( v! r- t" y. ~( g0 q
  10. //0x40000 => 4
    # I0 G! D4 W, d9 X* n2 V/ s! M/ Z
  11. //0x50000 => 5
    + [  E& S2 o9 r/ B% H3 C
  12. //0x60000 => 6
    & v5 Y* [8 i) U2 z  ~
  13. //0x70000 => 7 - ]9 [+ p6 @  o. r3 v; W
  14. //0x80000 => 8 8 z2 ]0 Z+ b: y) t4 q* F
  15. //0x90000 => 129 r8 {, C3 E: u5 ^/ y# j
  16. //0xA0000 => 16( Q9 F, G2 m3 R' ~" Y
  17. //0xB0000 => 20
    * ~8 n4 a" C4 Q& B* Z1 F
  18. //0xC0000 => 24
      A, U5 s% \+ C" g( p
  19. //0xD0000 => 32' @0 ^( K6 G  I7 S3 m  ~6 h
  20. //0xE0000 => 48
    : W. T; t2 X3 e3 q, ~% ]
  21. //0xF0000 => 64
    3 x) _/ z  ^, S# I+ w1 a
  22. uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
    ! Y0 J: u# p5 ~4 I  a' H" |
  23. uint8_t can_dlc2len(uint32_t RxHeader_DataLength)
    ' E8 h/ b& Z' \
  24. {  T! W- R) a' _# ?5 R( f' g: k
  25.   return dlc2len[RxHeader_DataLength>>16];8 w" ~: S- ~% F' g* p
  26. }
    3 h! i& d8 c  G. ^9 M; e. B

  27. 5 T  T# K4 |6 W/ m4 t* X+ x4 g0 O
  28. uint8_t cnt = 0;
    : d. ]4 \6 D9 u( E+ f
  29. uint8_t brs[] = {'-', 'B'};6 l1 T) j* y# `
  30. uint8_t esi[] = {'-', 'E'};/ |1 O/ K/ ]3 P9 H9 D
  31. void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)( J* Z# }3 i' g/ H, }/ t+ @
  32. {
    0 @$ @: J- S" p4 N9 _8 e' G7 a, s
  33.   if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {+ O2 g* e! H$ U
  34.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);3 W+ b& C; ?8 g
  35.     //RxHeader2.Identifier++;
    ! a' c. U1 |- Q# k, W( H6 O- O
  36.     //fdcan2_transmit(RxHeader2.Identifier, RxData2);
    : v2 @* \: G$ f4 N' P2 G

  37. : T/ [6 d" t2 K3 g( p9 x% ?8 D  s
  38.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    ( W( A5 l! i" f2 v
  39.     //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));
    * l. K6 h7 F5 n  h6 _

  40. 9 c- U2 y& ~9 i; [6 W- m6 _2 j
  41.     HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    & z" t1 Z6 a1 N+ C
  42.     if (hfdcan->Instance == FDCAN1) {9 ^- g* T0 r% d. f; F" P
  43.                 printf("fdcan1, ");* o) ?4 Z/ Q( G5 ?1 Q: e) Q
  44.         } else if (hfdcan->Instance == FDCAN2) { " v6 o; i( g* u9 x
  45.                 printf("fdcan2, ");6 q0 \" _3 t# _0 H  ]+ e! R+ r
  46.         } else if (hfdcan->Instance == FDCAN3) {9 j# p$ b- ~0 m3 P! k/ b) {2 E9 x
  47.                 printf("fdcan3, ");
    : u, L/ H6 v2 i- L3 X' r: a- N: ?
  48.         }
    ) P6 b. m5 y& c* P/ |
  49.     printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier,
    4 [; \4 Z7 n! I$ Y( W/ K
  50.                                   can_dlc2len(RxHeader1.DataLength), . Q. C+ L( w. Q
  51.                                   brs[RxHeader1.BitRateSwitch>>20 & 0x1],- B' R$ d- G0 k+ X+ i( O* J7 Q
  52.                                   esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);
    / H, D; i" Y4 M9 L1 [
  53.     for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {. s2 l& i  x3 O/ R
  54.       printf(" %02X", RxData1[cnt]);
    % c( \7 `2 |' l
  55.     }4 A# J% c6 J4 p; f
  56.     printf("\n\r");' E1 I+ ?% ^3 {' D" z' w* c
  57. # G0 ]! h  @; X' h, i
  58. * |2 t+ N+ J9 F$ E  P
  59.     //if (hfdcan->Instance == FDCAN1) {( K. L$ b# t5 Y) d
  60.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    $ r* T4 t# Y0 t. J) D# x
  61.     //  //echo
    % y- K; d- }" r# N- j
  62.     //  RxHeader1.Identifier++;0 ]) Y. T9 A+ F" n; y5 c$ ]# `
  63.     //  fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);# ?' J! O9 n2 Q
  64.     //} else if(hfdcan->Instance == FDCAN2) {
    ! \# ^$ A7 y  H/ F* I
  65.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);' X. C# p' q6 _; k* s. @
  66.     //  //echo
    1 y  X0 [3 }0 P6 s7 H
  67.     //  RxHeader2.Identifier++;
    " b' Y+ w( l  r$ E
  68.     //  fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);
    3 \3 Q) V( v2 G
  69.     //} else if(hfdcan->Instance == FDCAN3) {
    ; V' u  E( r) X
  70.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);
    & R' m! C! ^2 M2 _
  71.     //  //echo7 {' J$ h  o( E: r: ]9 v2 X  c/ ?0 d
  72.     //  RxHeader3.Identifier++;
    . B% k$ y" r9 j* Q9 H
  73.     //  fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);1 G* h: L9 h* D& j; H2 h0 k: m
  74.     //} else {$ U3 y" Q5 G% ~! u4 y
  75.     //  
    0 c* T, w, M7 }/ q* k+ R
  76.     //}
    ; C% _' l) H& Q% X0 B
  77.   }
    / }5 A* j5 q5 E7 u5 E
  78. }
复制代码

* S8 e2 e- ?. Y5 R注意注释中 RxHeader.DataLength => can_dlc 的对应关系.
; y( o% K0 \) ~: W; j+ ^, x! ~/ R! a! C3 E! q8 f2 X
示例如图:
: f0 y) h9 f+ q0 P7 |3 v) Y1 o+ Q! J+ n4 }( h' D3 S7 t! k3 Y
20210222190024669.png

9 }/ u  K% G4 _
+ q4 I! s, }; Y0 ^2 M/ X9 {图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.
/ \+ P/ g* f/ j1 R# I" Q& I) n) q" r* z- j3 I5 d+ o- p
printf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.
# H) o- i* r* v/ D* v; x6 i8 c8 ]8 h# Y0 ^% ~* t$ P- ?
发送处理
. o# x: M, O1 q发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.: M/ T" r" D5 w; I! G4 J' f" V
( q4 ?: ]  u; J0 I2 b- ~5 m
  1. #include <string.h>5 Q6 {0 I. B7 V. w& E$ x. u: z

  2. 3 C: |% q: V9 K/ {2 [# z* K
  3. FDCAN_TxHeaderTypeDef TxHeader1;% o5 N- N: m* V+ P6 Z. V8 f7 I
  4. FDCAN_TxHeaderTypeDef TxHeader2;
    : Q; W1 P4 T+ k0 r+ y2 `" c4 W
  5. FDCAN_TxHeaderTypeDef TxHeader3;
    1 [3 s- V% N/ d$ k
  6. ! l- r* I; H, B/ e
  7. typedef struct {
    * m: u' @, }% d. A# g. {; s
  8.   uint8_t flag;
    8 c$ _) O+ `# O! M8 l: E
  9.   FDCAN_TxHeaderTypeDef TxHeader;
    - i) f# ?1 o3 p( p$ r# t
  10.   uint8_t TxData[64];/ a- J% n8 S7 |
  11. } FDCAN_SendFailTypeDef;
    * I% e5 J) q5 E7 X

  12. + P% p# N' q( e7 k* V
  13. FDCAN_SendFailTypeDef fdcan1_send_fail = {0};! s7 I# y- Y* X
  14. FDCAN_SendFailTypeDef fdcan2_send_fail = {0};& r6 n0 r# k  S4 y
  15. FDCAN_SendFailTypeDef fdcan3_send_fail = {0};6 w7 ~9 w& _( h7 d( N2 s* z

  16. 0 R  V2 E& k. Y& T9 r
  17. void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[]), L$ U- S0 b5 R0 j5 U0 A
  18. {
    ' n4 k. H) u4 z/ p0 K# D
  19.   TxHeader1.Identifier = can_id;
    & U7 v1 N% G; E+ p
  20.   TxHeader1.IdType = FDCAN_EXTENDED_ID;
    4 y4 m* U% Z1 W' g$ y& X# P% g
  21.   if(can_id < 0x800) {  //exactly not right
    8 D* `  s* \( p# I$ n
  22.     TxHeader1.IdType = FDCAN_STANDARD_ID;6 c' |: e. E* g1 \4 a% a9 ]
  23.   }
    & I  K  c5 E3 x& t+ \" |" _! j
  24.   TxHeader1.TxFrameType = FDCAN_DATA_FRAME;- w! `9 _' H. N+ p& G1 m
  25.   TxHeader1.DataLength = DataLength;
    ; v/ Y3 _- E" W0 Y  A$ f
  26.   TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;. Y5 o4 m5 l' F4 w( K' K# A! s2 }- d
  27.   TxHeader1.BitRateSwitch = FDCAN_BRS_ON;
    ( G+ O. R7 X/ ]3 Z  T, V5 P/ R
  28.   TxHeader1.FDFormat = FDCAN_FD_CAN;
    + f, H  F+ W' ]1 n, C
  29.   TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;: B6 O$ S+ y3 J' G3 r+ v7 S
  30.   TxHeader1.MessageMarker = 0;        //marker++;        //Tx Event FIFO Use, v8 c' U" R3 d& x+ x8 r: Y- S
  31.   if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {
    1 @; O8 w" \' }  d
  32.     fdcan1_send_fail.flag = 1;+ X* ]- x6 y. h; u
  33.     memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));
    ' K2 v( g+ C5 Q1 k* r# c- ~) A
  34.     memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));
    ) Z3 z' {! h8 b% a) q7 u5 U# J
  35.   }
    0 A2 r$ X! I; O" v1 p* C5 \
  36. }
    * e3 E, P) ^3 L/ y3 T

  37. # m. T0 G/ W" F; {4 u6 E
  38. int main(void)& I4 t4 r0 z, J
  39. {* f& ?3 T3 q' F. o& r! d0 `2 z* ^
  40.   ..." L5 ~" s" c7 N; z  r. X6 ]7 p
  41.   /* USER CODE BEGIN 2 */
    6 [+ ~' h8 X. v# [- k. j. p9 o
  42.   fdcan1_config();1 E3 Q, N( X6 x' Y4 F  e
  43.   fdcan2_config();
    8 A$ N9 ^* i( t' C
  44.   fdcan3_config();2 o8 l1 ?. a* {+ T! O- |

  45. 2 U; l; K0 A0 B! z' R2 V
  46.   for(uint8_t i = 0; i < 64; i++) {! _  T+ U# S+ k5 s6 L3 O1 ]! w
  47.     TxData1<i> = i;</i>7 s% _4 b" p" {! X) ~; d* K
  48. <i>    TxData2 = i;</i>0 \0 Z6 Z# {1 B0 @+ \1 x
  49. <i>    TxData3</i><i> = i;
      q4 h$ z. v& k
  50.   }
    6 ?. z. X$ A: J7 j* N  s
  51. 7 u+ z( [( W: O0 ~8 [+ U
  52.   HAL_TIM_Base_Start_IT(&htim6);
    . h( f0 ?, x0 n: f' B8 K# J: K" T7 y
  53.   </i>uint32_t count = 0;+ p$ T9 K: r  i/ t
  54.   uint32_t cnt_100us = 0;3 C* ~. m) P7 H* {. I- r$ o9 b
  55.   uint32_t cnt_500us = 0;  v' C* ^, J6 b4 i9 X8 s) F  H" i: b$ D" |
  56.   /* USER CODE END 2 */4 x# G* A+ _' z; X
  57. ) v' F1 M* e0 C( Y
  58.   /* Infinite loop */* j7 f- U' ^" w- I1 C
  59.   /* USER CODE BEGIN WHILE */0 U: w/ K- A# w/ {* m* j
  60.   while (1)# H( g! X! U( r* w$ X' }# G, X5 U
  61.   {% _1 V0 O8 ^% U+ M" y6 P; h
  62.     /* USER CODE END WHILE */
    ( }2 A" ~" ~& C8 t# r2 I# R
  63. ( \! |1 O/ }/ |7 |5 K0 ^
  64.     /* USER CODE BEGIN 3 */
    - Q1 g3 j  K6 w( n. p5 }0 w
  65.     if(tim6_flag && count < 1000) {# _- p5 ?4 e5 y- F' e1 H
  66.       tim6_flag = 0;/ _" |* A0 P0 I/ M7 I
  67.       TxData1[0] = count >> 8 & 0xFF;
    2 D9 ]' `& j4 [/ y( W' U; k
  68.       TxData1[1] = count & 0xFF;* Z( @' F- \+ H( R- O& Z7 y
  69. - t/ r. s# u( O0 p$ q
  70.       ++cnt_100us;
    ( _4 w9 Q8 f$ k" ~+ J0 V1 z
  71.       cnt_500us = cnt_100us / 5;
    3 h2 [* V3 k8 y, |7 b
  72.       if(cnt_500us && (cnt_100us%5==0) ) {
    7 k$ Z' {  |2 Y4 ~& h2 |6 P
  73.         switch(cnt_500us) {. _. c0 n3 s. U$ j6 X
  74.           case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1); 9 U! V9 F) e0 ]- \7 P- `* a
  75.                   fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);/ Y: S6 J6 q6 u: ^& ^
  76.                   fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;
    9 m. g2 k- g3 A1 L' K
  77.           case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;
    ) @- ]2 n! y3 D* t6 B% D. D- j2 _
  78.           case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;" B( L* T7 I! z! Q. n. X
  79.           case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;2 i4 s# w6 y% `8 W
  80.           case 7: /* next send */ break;9 j; r; c: D5 ~' @# A
  81.           case 8: break;: ~4 _2 F$ `+ [9 U/ n
  82.           case 20: ++count; cnt_100us = 0; break; //10ms1 i/ {; [/ \" A
  83.         }) _  \8 e$ |& z! j  S& C
  84.       } else {  //fail retransmission once
    ! c0 T- u% R1 }" |0 `
  85.         if(fdcan1_send_fail.flag) {) |2 F% F. d8 Z0 r" Z
  86.           fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier, 2 X, r* a! o( c; K! x
  87.                           fdcan1_send_fail.TxHeader.DataLength,8 q% b3 Q8 b. ~- a& O2 R
  88.                           fdcan1_send_fail.TxData);+ r6 w( L6 f. g$ f+ O
  89.           fdcan1_send_fail.flag = 0;
    " j- y% ?  x# Q* o5 n  g5 Y# @
  90.         }
    / a# ?) V. \2 i" F; X
  91.         if(fdcan2_send_fail.flag) {% @: w1 _: H. _/ V$ v- \. P3 \, _; H3 d
  92.           fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier,
    . f, X2 g2 I$ I  a7 W
  93.                           fdcan2_send_fail.TxHeader.DataLength,2 ], ^9 I: ~6 n  m, {4 F
  94.                           fdcan2_send_fail.TxData);. f7 @: z" a: G0 E" `! `7 o
  95.           fdcan2_send_fail.flag = 0;
    ' a* O* {4 v$ q& r5 c: A
  96.         }$ g" Q4 e' Q! N$ j. c( Y
  97.         if(fdcan3_send_fail.flag) {, i1 S7 K# G( @7 F+ j8 ^
  98.           fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier, 6 Y' P( ?& K  B2 S6 C. [1 b
  99.                           fdcan3_send_fail.TxHeader.DataLength,) Y) ^) L1 B+ d
  100.                           fdcan3_send_fail.TxData);
    . @2 H% a4 F8 m: t, t
  101.           fdcan3_send_fail.flag = 0;/ {3 s$ P- d! ~( x9 Z
  102.         }
    3 t" D, J: Z( k
  103.       }
    8 X+ d9 ~$ Z$ T0 ?2 A: P
  104.     }
    " y' G9 `8 x. u- ^; e5 G. @
  105.   }2 P+ |9 ~0 v) K: F; Q/ P( o
  106.   /* USER CODE END 3 */  0 d5 K$ W/ l2 U' V" t, X
  107. }
复制代码
* J, F2 Z" z4 a. T0 M
fdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.
2 D, U6 S. P& t* i% Q3 q
  G. H  n* s2 K7 Z2 E% G发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.# s! E8 v6 ?: g4 Y3 {8 n$ r2 |
$ a" m. j& j0 V. p  @% i+ T
这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.% C5 E- \2 m) ~5 q# [; r

" t7 S3 U. W; \$ V5 ?. _因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧.+ A# k3 k) s( D- B0 q- f% x
" H/ V# K9 s9 ^0 T
因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.+ v4 K. H: f: c: s. f0 k6 |
/ Z5 X# R! n6 g0 l
如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.
$ e2 I/ Q: ~1 X2 C) c8 H
5 L( }% ^, I1 c  v一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.
% e3 v' a& A5 g: b- p6 F: b  W8 e: F& `8 @8 O& q& V# r0 M
程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.
  n% }: E, V% |7 N6 a
/ y, A" g; K* l* y- L使用Xavier配合测试一下
# R- `0 W1 H2 ]/ z9 O0 K. o把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:
1 s/ ^5 d2 Z9 W( w
3 a! N# Y9 C* J8 _' o
  1. #!/bin/sh: v4 c# ~! ?% S' {& s

  2. $ U$ |, f% d% w) b0 }! P% D, F/ I0 m
  3. sudo modprobe can
    , C4 D; F1 x$ p& F/ g
  4. sudo modprobe can_raw& \7 F( z4 I+ i- l
  5. sudo modprobe mttcan
    7 Y( J& `; Q' @/ v7 `/ X
  6. ) k0 P) }' C+ B0 h! n5 N8 Q5 h1 p; P
  7. sudo ip link set down can02 r3 L7 K2 b$ d' M; p
  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; ^7 q# U* E! {4 S( A- E4 P  T6 ~, G- X( B
  9. sudo ip link set up can0 ; O( O; b) U3 H% C5 m+ n
  10. sudo ifconfig can0 txqueuelen 10004 f2 M1 `% S# S' x' K
  11. 7 @  x/ a; }1 z7 f; M# k
  12. sudo ip link set down can1
    $ t1 h: t1 K# n9 \- U
  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
    ( B" Q: C1 X3 B9 ^( b/ J1 M
  14. sudo ip link set up can1
    # y/ l6 q5 d! b; P8 w
  15. sudo ifconfig can1 txqueuelen 1000
复制代码
Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.. }/ O7 f2 Z1 s/ f$ m: \

3 m2 s( k" K5 Lrestart-ms 100设置总线Bus-Off时, 100ms后重启.
0 a( m* n6 a4 }
: V( U2 b9 j# M2 {设置完后查看设置状态 ip -details -statistics link show can1:6 D) p0 ?+ y" O5 k

7 ?# p, Y# E; X* c& Z
  1. $ ip -details -statistics link show can1
    2 `# Y; c" d! x1 d. W
  2. 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
      m, I* x" d$ h+ S2 {5 H+ X
  3.     link/can  promiscuity 0 ( ~0 S2 f$ f5 S, [
  4.     can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100
    * s( B! N2 g. k$ b) z; S( }
  5.           bitrate 498701 sample-point 0.792
    - H7 U: |" Q+ W/ e7 A/ t) N
  6.           tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 16 s3 |7 P: C4 V. ]
  7.           mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1; M8 c( d8 p. L' m3 w0 j! J5 p* }
  8.           dbitrate 2021052 dsample-point 0.736
    $ l8 S' @& z. R
  9.           dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1
    7 q$ S2 g" \/ E! E* j7 j
  10.           mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1: F2 a* s( G0 x8 Q$ U. ]+ ]
  11.           clock 38400000
    5 z7 [$ O- l; p
  12.           re-started bus-errors arbit-lost error-warn error-pass bus-off. B/ f$ C" P( Z9 y' h. T
  13.           0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    , R3 r; X( \4 N
  14.     RX: bytes  packets  errors  dropped overrun mcast   * q% F9 T9 U( ]& e; O2 D
  15.     64578440   1013451  0       0       0       0       2 a; A% H! b# }
  16.     TX: bytes  packets  errors  dropped carrier collsns
    2 R9 q& o$ r7 k5 s
  17.     952448     15914    0       0       0       0   
复制代码
位速率和采样点的些许误差测试并无影响.; N! y" T2 \! ^3 _+ l
" S! ~1 Y6 O9 w  Z, N+ K: Z( b
使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:1 _% S" i1 j; ?$ x- u; F+ y+ m$ O

8 }5 }* |, @, 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; i2 k; R- @& c8 x; l3 W
  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
    3 B; m% f  Y4 h7 u: i) y" i2 `
  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 3F3 G9 j5 |! s7 K9 z( W" V- F3 z, V* 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 3F6 ^7 C8 M7 u; {$ ^5 F6 t# k
  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/ A7 f% |, V% _3 ^7 _; N3 E1 m
  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
    . J7 O: `* X8 l7 |) P
  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
    0 w- O5 x  b; N  z5 T) k" T+ Q
  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: k( }4 m+ ^5 C7 G7 r" r

  9. 1 g: q" [5 {  B% X$ y
  10. ... . N+ s; x2 x; K" }: e9 i/ O

  11. & d; r& K- h% k* z) w, \1 h
  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- t/ R/ g8 Z: ]3 \) I& M9 c$ H
  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
    / H8 v# Z% g* H, L9 S& o0 v
  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
    4 ?/ S1 Y0 e( `. O, ^  S! w5 W" a
  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! V7 |* c$ `: k, ~2 p7 n$ }8 m  R; _
  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/ [# O' x0 @) W8 ^9 M
  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' J' c6 X/ g% V% H7 A" d
  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 3F1 ?8 A5 C; M2 Y  U! l2 S1 |
  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
    ) N9 ^+ f9 L9 P) ?. X3 `% A5 }' E
  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
复制代码

  O0 |  o, U7 [, j% m/ c3 c+ [这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.$ [7 i2 x/ _7 k& S9 z. |

6 p: e' r- V) m3 C5 _0 h! jXavier发送脚本, ##后面的3表示开启BRS和ESI:+ n, Z( W, ]( O8 \7 R

5 }! k) c# E# p
  1. #!/bin/sh) T( k3 ^( `: ?3 L4 F

  2. / d# Q- D* e, z
  3. while true; do
    5 d5 V- u. c, U! Y$ f
  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.160 S  `0 o5 S% H
  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
    7 u2 y; o1 w6 f* s* u
  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  8 Z/ E! m+ V) G- 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.168 \0 [8 C2 r0 r+ T+ A
  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
    % a' q- |9 T7 T9 R, d3 B
  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  9 }4 i- Y1 P9 R& E- C
  10.     sleep 0.01
      D" D# d& G2 u
  11. done
复制代码
5 P+ f$ T2 J0 a% C6 H7 q
可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
: N( J, p* R$ M, R. c  o, ^/ B% \& n0 {8 [" C5 X
核心思想是:, L4 C7 Q7 N$ p8 Y
( T/ `4 x6 ~% L. K( B
Mode 设置为Classic Master或者Classic Slave, 而不是FD6 O: p) \  i7 k! i) Q( f( N
仲裁段和数据段的通信速率都设置为500Kbit/s% Q: y* S2 |: k7 @" D* X
- `: G/ k9 s) `) J* S. G- a* V5 {6 W

2 n9 p. l" Z! Y- e; O
% L) P$ m# z7 ?4 i
收藏 评论0 发布时间:2021-11-11 22:00

举报

0个回答

所属标签

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