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

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

[复制链接]
STMCU小助手 发布时间:2021-11-11 22:00
本篇用起来, 连接关系如下:
% w4 U, z6 m3 h0 K
/ I. R* J8 r" d3 j) N+ u& l

20210222185812381.png

' _) X7 D. r6 }# f# v. N

: o8 c6 |0 r* W8 S3 h% g4 s) q2 vCAN收发器均选用支持2M及以上CANFD的收发器, LPUART到PC用STLINK连接.
. J; J7 c. }8 o  p$ h( S) z  L$ A+ ]$ H5 P/ ]  c% a
STM32工程搭建
& z0 _. F* i; n* z- [* hSTM32CubeMX配置步骤如下:
$ ~& ]% X: W9 S' F7 r: X" S% D) \
- a. l4 V& ^2 N4 \MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
7 j% `% |' Z' ]2 f8 N$ q
4 X% `) C$ c; Q. m( h调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
# S+ y6 \7 P4 p4 t4 O8 n
- u7 h7 i9 u  M( M% _- rPinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
, C2 g) T6 P% q& C4 C4 _1 o2 C; E& x1 ]
Clock Configuration(我板子上用的外部12M晶振, 主频配置成160MHz, FDCAN的时钟来自PCLK1=160MHz):
3 W& L; k: l$ _2 \7 r

20210222185828575.png


  ?% x% m4 j1 f

20210222195952515.png


* I# _! _! K, z- y
& Y% c7 T% F( b  u1 |开启100us定时器中断: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为160-1, Counter Period设置为100-1 -> 勾选TIM6中断:
1 T3 p3 ?8 y  i: Q: m5 I8 \5 q
- g& d0 T9 e+ J

20210222185846781.png


5 s+ L5 g0 O% A* b$ b- h! ?0 ~$ M7 R% g5 Y4 i" q

20210222185905935.png

9 \, P: X0 O: V* I; ^
' W" P: k" `5 Y. [2 Z: g6 Z; C
LPUART1配置: Pinout & Configuration -> Connectivity -> LPUART1 -> Mode选择异步Asynchronous, 关闭 Overrun 和 DMA on RX Error, 波特率配置为2M-8-N-1:9 _9 E; ?# f1 X
% \; i$ p7 v: f4 X; U

20210222185926920.png

- U0 m! E( x: c8 {/ n: x: [7 d

9 `# P  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:
7 E2 s# H2 T9 R2 Z
( o+ g; _8 j# T' C1 W8 P6 y

20210222185949803.png


; N9 ^! L( w6 J* T7 J% N# U$ l$ z% m  H8 k8 s5 J& v

20210222190005173.png


$ N% Q* O" j9 s2 F4 x! E# K+ _
$ Y- R) g  u$ D2 C3 R" W8 nFDCAN2, FDCAN3的设置同FDCAN1, 注意引脚要从默认改为板子上用的, 最终引脚位置为:- |. P5 |' H6 K

0 _- r" i- ~; ~" P

20210222190054536.png

. x6 \, G' ~+ ?0 h
+ g4 B% v9 p9 \4 h
Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x1000, Minimum Stack Size改为0x1000. 或者更大一点.
  o. Y; V" f* o2 S- ?" O0 ]  Z/ |: Y4 }. s
Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral; H, F0 f) |- b9 g

6 b# `  o  m& ]/ V! m+ u点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.
! z- U5 u$ ~, G
# z  \& p8 M6 W8 {. [+ ?; |; ZKeil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置Debug为ST-link Debugger, 点击Setting:
# g& r, m8 h3 g0 ~; D9 v' Q& p$ H
Flash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.
; _) @2 c* k5 M0 r" QPack选项卡, 去掉默认的Enable勾选
5 r/ Q" }& t$ q+ a! s; t: _到此配置结束. 下面是手动添加的代码详解+ _3 Q8 d4 l2 Q% k/ n5 E9 J2 N: U
$ M& e# s( w1 h: N8 x$ O* k1 }
串口配置, y+ j7 n. `% C: y) i0 g3 H) q
为 LPUART1 添加printf支持:0 z% ~3 L/ g0 J

% a2 b; u2 c% Q
  1. #include <stdio.h>! m+ p; \' ^; U- T
  2. 3 S- C) f0 n8 Z- k8 q" H, a
  3. #ifdef __GNUC__
    ! B% T* U% X& g" v2 {
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    2 z/ p2 e/ r( h! r
  5. #else# T7 x1 o. f, u. g# b* w) N
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f): X' ~9 ?$ H- |8 L
  7. #endif /* __GNUC__ */& z/ L6 S0 w+ g9 k8 e1 o

  8. . i7 P2 b0 e9 L& r8 z# B
  9. PUTCHAR_PROTOTYPE9 X/ N0 q: T% e* T! l+ K) Z2 d  V
  10. {6 ~  b  g: A/ S+ e( H2 }$ s
  11.   HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xFFFF);
    5 d. N, @9 W/ g
  12.   return ch;
复制代码

& y% n! |: h1 W100us定时器: z% H0 _/ Y: a' Z# y7 c" ^
因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多2490+约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 100us后有一次重传的机会, 这就是100us定时器的由来.
# S" s( h3 p4 ?/ d9 k7 G+ m! \$ ]' w5 E- @0 [1 K
  1. /* USER CODE BEGIN 2 */: D: S) Y/ }+ v0 |. ?! B, r+ Q" R
  2. HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.
    & ?! V3 X7 s8 S! P0 b6 s7 @
  3. /* USER CODE END 2 */
    0 c( b; b  E* @( ]5 s

  4. ' O1 u9 m% P; v5 o% [$ c5 |
  5. uint8_t tim6_flag = 0;
    $ f# y7 f8 A: O( t2 _
  6. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    - x3 B1 |! Y6 L- ?9 a
  7. {
    2 A9 h4 _; a5 i+ s" n, s1 j  Y; Q
  8.     if(htim->Instance == TIM6) {
    % t' U* {/ ]5 M: B! u
  9.         tim6_flag = 1;
    # @! F/ l4 R8 Y+ l1 A
  10.     }
    * X! d6 W3 V3 B& \# ?$ Z  j, O, [
  11. }
复制代码

  K% e$ M0 C2 J. C3 lFDCAN配置9 V/ H+ F1 h$ X9 B$ V$ G7 M7 u) _
主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.+ O/ w2 Y) ]3 q& h" v

! P" z% r& U$ L: f; N& ]
  1. FDCAN_FilterTypeDef sFilterConfig1;9 H8 q7 Z  I1 W' D5 N+ m5 L) B

  2. # M$ W% }" l9 g/ X& z7 c& F
  3. void fdcan1_config(void)0 M# {9 I3 j2 v1 o4 P
  4. {4 s  i& \  u/ `- {: x0 E
  5.   sFilterConfig1.IdType = FDCAN_STANDARD_ID;8 }3 x5 M) u5 Y# i" a& g$ W
  6.   sFilterConfig1.FilterIndex = 0;
    7 a, K  _! F7 |! S# ^/ [
  7.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
    . u1 @6 J6 {+ t$ t# y) }" {& T6 Y1 z( l
  8.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    , R+ v* p* b5 C3 x8 t7 x% }) g, Y
  9.   sFilterConfig1.FilterID1 = 0x00;
    # D. J9 i$ c# b& O
  10.   sFilterConfig1.FilterID2 = 0x7FF;8 B4 b. Z9 b4 v7 e8 d8 I
  11.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)% R* M/ ~, T/ s, Q8 W+ X6 `
  12.   {: v% d) j% P% O3 K  J
  13.     Error_Handler();
    + N% x* P/ f- E; w4 A
  14.   }
    9 X# J: V% e& T2 H/ a& [
  15. + d  v- h( c: R* ?0 t
  16.   sFilterConfig1.IdType = FDCAN_EXTENDED_ID;% d! X4 Z7 s! P% a7 N5 R! f0 V7 L
  17.   sFilterConfig1.FilterIndex = 0;$ @2 X, F, L- d( `- z9 M% S
  18.   sFilterConfig1.FilterType = FDCAN_FILTER_RANGE;
    $ ]' i5 _! j9 P: y0 B! i
  19.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    2 e% ?5 G% n( n, X2 |* V& D) [! T
  20.   sFilterConfig1.FilterID1 = 0x00;
    ( T, p0 }$ N6 d6 b9 T& w
  21.   sFilterConfig1.FilterID2 = 0x1FFFFFFF;
    " A" T! `, u+ i9 s. F, ?. k
  22.   if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1) != HAL_OK)# \4 t. T& J% ^
  23.   {
    8 O0 B4 U$ R6 u6 Y3 Z
  24.     Error_Handler();
    0 J! E- @+ C$ _  S1 f
  25.   }: Z  G9 J3 ?1 m! E( C! V) C9 r

  26. , o4 W, j2 F& f% _) A7 `0 F3 ]
  27.   /* Configure global filter on both FDCAN instances:
    5 t# ?! b. Z+ u/ J/ A
  28.   Filter all remote frames with STD and EXT ID, v! ]0 e9 l+ ^
  29.   Reject non matching frames with STD ID and EXT ID */9 U3 _# F  u# v5 a( J, z0 L
  30.   if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)! P. m$ X4 F. H. |
  31.   {% U) P; a6 [0 D) }$ ^
  32.     Error_Handler();; C! @; g6 b& [  y& s2 Q: O
  33.   }; X. n% M& K9 a1 A- f

  34. ; [7 w) l& e' }* K4 b4 X
  35.   /* Activate Rx FIFO 0 new message notification on both FDCAN instances */
    9 m3 g2 @6 W  {- B0 a, R# K
  36.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
    7 t, a; I$ i4 `# v
  37.   {1 p- J& Z" f. ]! y
  38.     Error_Handler();' ]# H. E# E5 a) U5 O
  39.   }
    1 Y3 N' S# V; x2 {" L) l" m

  40. / U7 z, m/ |4 T3 Q- g( K; L3 v/ `
  41.   if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
    5 J, ~9 w# _; v  l, g$ r9 d/ _! v
  42.   {& D& E: r3 d% }9 Y) Y9 L
  43.     Error_Handler();
      N$ w' [1 H4 v7 C- }) h6 Q
  44.   }( O/ ]! }) ]8 J% }" D  w6 Q. h. E5 f
  45. $ E3 o( S- y) j9 q" c- d
  46.   /* Configure and enable Tx Delay Compensation, required for BRS mode.5 T& A+ y/ \* T4 p
  47.         TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
    * b' x: x* w9 T, T2 W( t
  48.         TdcFilter default recommended value: 0 */
    - X' H* _5 r& v" E
  49.   HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
    5 p' m- ?0 V" k6 ?6 d; n- c* ?
  50.   HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);3 Y  y8 `: V$ f. `) h+ b2 R. H

  51. ; D% i2 ?8 w9 y! ?; s+ Y
  52.   HAL_FDCAN_Start(&hfdcan1);
    / v2 q6 N8 l& _3 I
  53. }
复制代码
7 G# D5 H6 H( h/ |" V; o
这里设置了用一个标准帧滤波器设置了标准帧的全接收, 也可以用掩码的方式设置全接收:
2 |1 x) n- Y1 Z+ L$ \( P, [
  1.   sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
    " o2 |; l0 l: ?+ D! q
  2.   sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
    : E2 k$ d: X2 Y( ]0 G6 S
  3.   sFilterConfig1.FilterID1 = 0;" x' \( }3 A% x9 s" \
  4.   sFilterConfig1.FilterID2 = 0;
复制代码
' h3 @5 n" G( Z0 X' b) {1 `
用一个扩展帧滤波器设置了扩展帧的全接收, 消息扔到RXFIFO0中, 设置了RXFIFO0的新消息来的中断, 也可以扔到RXFIFO1中.
" y3 S  ?' U7 z! ~% x, |+ E: J5 q6 O6 v2 H% q
有别于STM32H7, STM32G474在STM32CubeMX软件中能设置的最大标准帧滤波器是28个, 扩展帧滤波器是8个, 这里程序中只各用了一个(index = 0), 如果想用更多, 不知可否手动更改stm32g4xx_hal_fdcan.c中213行这个值, 如把扩展帧滤波器数量从8改为28, 有兴趣试试:4 ]1 P: n. x) z( W' `1 y

5 h; |. W7 z! ?3 t8 |
  1. #define SRAMCAN_FLE_NBR                  ( 8U)         /* Max. Filter List Extended Number      */
复制代码

& j1 C( V# S1 @) C/ e  E' w% k( d% iFDCAN2, FDCAN3的配置和FDCAN1类似.4 @2 P4 ]% c8 C

4 k; ~; u7 j. `8 Z$ ^Bus-Off处理4 e! `" b8 A% q" u3 I4 m! C
如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:' u; Z! @$ @2 m" F) e) F

$ p+ M) j- {& u2 u" {
  1. void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
    % x# t1 Q/ c6 }. ^- e: X8 J
  2. {
    & c, y, X8 ?& o  s
  3.   //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);2 s' S/ o6 K+ f+ p; c" F
  4.   if(hfdcan->Instance == FDCAN1) {
    ) w/ T: k# |$ y9 u% x
  5.     MX_FDCAN1_Init();
    ( {( P) S& r6 ^+ V8 _, A- b' f
  6.     fdcan1_config();
    # P; O+ B. G; B& K; {
  7.   } else if(hfdcan->Instance == FDCAN2) {
    & q2 R- N' t, i: b! Q
  8.     MX_FDCAN2_Init();. n. e1 n6 Q6 X1 V
  9.     fdcan2_config();; q" A+ O) s4 n# n9 a: x4 Y1 w5 L
  10.   } else if(hfdcan->Instance == FDCAN3) {/ m  C( j# b+ ^5 g
  11.     MX_FDCAN3_Init();- K8 N" Y2 E/ J$ G7 G5 Y; w' Q% P
  12.     fdcan3_config();* |$ u% ^) L; O* r( Z  g' G, ]
  13.   } else {1 B: Q# Y0 @# F" j
  14.   }7 u4 m+ R! c/ d+ p# @: a
  15. }
复制代码
& ]( N& K1 Z' \9 B; ?/ X
新消息接收处理
' f% |; O! M' J2 r直接把接收的消息通过2M波特率的串口打印出来.# K$ c- j/ l' k# X6 I+ U
% |* e7 i* Z/ w1 \/ K6 `) J
  1. FDCAN_RxHeaderTypeDef RxHeader1;3 w: f7 J; S  T& S8 s6 k/ I, o& k
  2. FDCAN_RxHeaderTypeDef RxHeader2;
    8 r+ E& t6 J. @  p
  3. FDCAN_RxHeaderTypeDef RxHeader3;$ Y, A) _6 |" Z: H$ `1 Q
  4. 8 H, T6 d# n1 U! d" D0 i) L
  5. //RxHeader1.DataLength => can_dlc
    " [# G8 \* F" y$ V- a- W7 m) ^. p
  6. //0x00000 => 0 " Y2 E, L+ h* V0 v
  7. //0x10000 => 1
    6 ]7 o$ W% E# C3 b
  8. //0x20000 => 2
    ' |7 ]( O5 g$ Q* U
  9. //0x30000 => 3
    7 n: H) j4 x+ l$ G
  10. //0x40000 => 4
    0 {' Q, Z& C8 E" E
  11. //0x50000 => 5 * C1 X; u$ |( o0 ^. A1 L
  12. //0x60000 => 6
    7 b: u! j2 d; X+ g8 N
  13. //0x70000 => 7 7 _. n5 H. [8 T* i" F
  14. //0x80000 => 8
    5 U; ?  @0 V5 ^) g2 k% c
  15. //0x90000 => 12, O1 `; V- q. n" h  E' o$ R
  16. //0xA0000 => 162 U' |; N5 S1 N3 b/ U( D5 H/ @
  17. //0xB0000 => 20
    ; y! K  a- p8 a7 v
  18. //0xC0000 => 24
    ( K3 H! |9 g: h4 B- Z
  19. //0xD0000 => 321 D/ N  v: \0 j+ Q5 N! T7 J
  20. //0xE0000 => 48
    5 d- c* ^  g3 |( g
  21. //0xF0000 => 64# A' S4 k/ D+ b- u1 G
  22. uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
    - Z4 f( Z4 d* S! J+ c9 I
  23. uint8_t can_dlc2len(uint32_t RxHeader_DataLength)& \# I1 w& \; z# j: H9 O3 o
  24. {
    3 L% ?  r$ h3 I3 p( |: y1 m3 T
  25.   return dlc2len[RxHeader_DataLength>>16];) m% J# y7 \2 _1 ?
  26. }
    # H* Z- t' z" K  F' M9 X
  27. ' h& _: n: G# [% T2 Z
  28. uint8_t cnt = 0;
    $ U, m+ A" h$ y5 q# A, ~: A& \! o
  29. uint8_t brs[] = {'-', 'B'};
    3 m1 W4 g) A  E
  30. uint8_t esi[] = {'-', 'E'};/ E, K' I+ X( e
  31. void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)- {% k4 B7 G2 P, h4 b- A3 N
  32. {4 V( @& f. `/ y8 p  \3 k2 A
  33.   if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {+ n& j* E: [( p2 a5 a
  34.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);
    ' U) u* _- h1 p" H) I: H
  35.     //RxHeader2.Identifier++;
    7 J: j" u: k0 j
  36.     //fdcan2_transmit(RxHeader2.Identifier, RxData2);. n1 b7 Q% f! v5 l' P& c* ?+ p* A
  37. 4 d: P( h1 z8 W5 e& L% Q% ]
  38.     //HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);' G. [0 G& @: G* y+ b  C2 K" P
  39.     //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));& O! X) t( B$ E/ |  }. T
  40. 4 `4 S- P& F" T: F' H
  41.     HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    6 k- \& P- t$ B
  42.     if (hfdcan->Instance == FDCAN1) {
    8 H: c# i3 O  _1 q2 T
  43.                 printf("fdcan1, ");( O% G2 D7 U- O" K' B/ z
  44.         } else if (hfdcan->Instance == FDCAN2) { * S, c: H2 {! b( f
  45.                 printf("fdcan2, ");! z7 s) o' [/ C! `# w
  46.         } else if (hfdcan->Instance == FDCAN3) {
    6 X/ X- P: K; v0 [% z! R6 [6 B7 e
  47.                 printf("fdcan3, ");
    : M/ D- {# D5 W5 B' r
  48.         }
    ( q' ?" M' t- m
  49.     printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier, $ H! L- J) h9 I6 U- d$ I
  50.                                   can_dlc2len(RxHeader1.DataLength), . H, v% f. u+ r2 X( D' ?
  51.                                   brs[RxHeader1.BitRateSwitch>>20 & 0x1],
    7 Q5 W! I4 z- q
  52.                                   esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);
    1 R* s3 y3 D  n6 V, z; @
  53.     for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {
    , i; f% y3 `7 T
  54.       printf(" %02X", RxData1[cnt]);, K: ?2 b  D: e# t+ W
  55.     }9 {& a, v. n9 H2 E
  56.     printf("\n\r");! \& G3 L+ Z% u" Y4 P
  57. 7 i7 F# G) c; [" c9 t0 u
  58. . {5 @3 s7 [  m( w, u
  59.     //if (hfdcan->Instance == FDCAN1) {
    , ?" t/ f" Q9 W# ^9 n
  60.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    ) X* e2 S0 W+ m) n7 e- N
  61.     //  //echo
      r$ v5 H9 ~' b5 y2 P
  62.     //  RxHeader1.Identifier++;
    / B! {, G& Y4 l5 L# L/ G# r; B
  63.     //  fdcan1_transmit(RxHeader1.Identifier, RxHeader1.DataLength, RxData1);1 j5 l; ^% f4 o2 f
  64.     //} else if(hfdcan->Instance == FDCAN2) {$ c: s' }* K) B( x: J# J
  65.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader2, RxData2);7 Y( `* I0 [% T, |- f2 a
  66.     //  //echo3 m2 }, C* B9 n! I. h5 \1 g
  67.     //  RxHeader2.Identifier++;  N/ \' [# F1 f& o# z. k% M# \. [
  68.     //  fdcan2_transmit(RxHeader2.Identifier, RxHeader2.DataLength, RxData2);
    ) o) I7 b3 [' _/ ^
  69.     //} else if(hfdcan->Instance == FDCAN3) {) X# u  N! o! \( i; J6 Q8 Z
  70.     //  HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader3, RxData3);
      w! [/ r* n% ~. v: u
  71.     //  //echo
    4 T+ R# P+ I+ K. }
  72.     //  RxHeader3.Identifier++;
    + [8 R) x9 n9 l; x$ ]- |6 A* Z5 P' J
  73.     //  fdcan3_transmit(RxHeader3.Identifier, RxHeader3.DataLength, RxData3);
    # t' w- @! a" a: x; n8 I
  74.     //} else {/ K: S# x& B( j8 W2 E
  75.     //  
      T$ v6 i7 A8 f
  76.     //}
    / k' s- o. [5 W- t9 o3 l8 `
  77.   }
    , e- k$ Z9 A' o, B. }
  78. }
复制代码
3 m( U& q1 g% K5 j1 [4 ^
注意注释中 RxHeader.DataLength => can_dlc 的对应关系.
8 n/ a! ~" V/ J! S% t" E) d+ V5 u# f7 t: W" d, t; ?
示例如图:
+ `) k" f5 p. _! v4 j, S# g; Q1 T
) l. ^2 H# K. p* n+ ?
20210222190024669.png

' \( `0 B2 Q5 h2 V2 U+ r6 q. W! r) u) F' D9 M: D5 N
图中消息来自fdcan2, can_id为0x18FF0005, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.
" @& N. e5 M0 v4 X
0 U2 F. Q$ e( Y# x; |0 aprintf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.
' U# a7 D: r) O. g, q8 D* D: l: W6 j
发送处理
6 B8 Y* N! C3 g8 H* o8 s发送开启了BRS和ESI, 如果发送失败, 就延时100us后重发一次.
% e. N- |! Q% z; l' @$ p6 G& [/ G1 j! N$ K
  1. #include <string.h>: E" G+ k5 e! w0 w& R! g. J$ j
  2. 8 k; n% c/ {; b2 Z% ]5 R7 U8 D
  3. FDCAN_TxHeaderTypeDef TxHeader1;0 R+ J- E/ l/ ]# E
  4. FDCAN_TxHeaderTypeDef TxHeader2;2 A9 A8 O% w! P  V* c; d6 K
  5. FDCAN_TxHeaderTypeDef TxHeader3;
    , o! ?6 ?- o; \% |3 I- C
  6. - \# _* D7 i4 u8 `3 c1 i4 c9 b) d
  7. typedef struct {
    # J" S# t7 N( H8 m( z4 t9 V( k
  8.   uint8_t flag;
    # z; Z+ d1 l( |1 Q
  9.   FDCAN_TxHeaderTypeDef TxHeader;7 C- W5 k* o4 O( T& |. G
  10.   uint8_t TxData[64];
    % z5 t% `. u% b, u1 C  D/ P9 A6 O9 j% j
  11. } FDCAN_SendFailTypeDef;
    + ^" a( c& @. p/ ]
  12. ' X4 h- p. ]$ A# D
  13. FDCAN_SendFailTypeDef fdcan1_send_fail = {0};& w4 e5 I0 E/ z' U
  14. FDCAN_SendFailTypeDef fdcan2_send_fail = {0};
    7 ^' T: A) W+ ?( q
  15. FDCAN_SendFailTypeDef fdcan3_send_fail = {0};* Q$ n8 g/ G" ^8 n7 y

  16. ) w4 I2 o/ e3 A0 n
  17. void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
    ) o2 |: o1 `; \% R/ r
  18. {
    8 H5 s8 ?1 `$ q# l  k0 `1 }; |9 k
  19.   TxHeader1.Identifier = can_id;
    % ~5 o! r' g+ u: D( z+ f  A5 W5 g
  20.   TxHeader1.IdType = FDCAN_EXTENDED_ID;
    * n* r6 f4 t( P- z1 s3 t
  21.   if(can_id < 0x800) {  //exactly not right
      r% q( W# z% \8 b) D: Q
  22.     TxHeader1.IdType = FDCAN_STANDARD_ID;
    1 E. M! z1 F8 E% I  r) p2 u# [
  23.   }1 u: Q" V$ y% L& r- ^  Y7 A
  24.   TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
    6 N( R% J& [' a8 P7 U5 \1 s) V
  25.   TxHeader1.DataLength = DataLength;
    1 i6 y- T* x* g0 ?
  26.   TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;: o5 C  W8 w' a6 c' T7 W* A+ {
  27.   TxHeader1.BitRateSwitch = FDCAN_BRS_ON;, |6 t. ]7 P* q& K
  28.   TxHeader1.FDFormat = FDCAN_FD_CAN;# B+ U; [$ Q+ i; Y7 _* ~
  29.   TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
    8 ?. N6 n  H  I! L
  30.   TxHeader1.MessageMarker = 0;        //marker++;        //Tx Event FIFO Use: \0 G2 o# m2 {7 C
  31.   if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {1 c4 {6 U  u5 @& x) U1 y; f+ C
  32.     fdcan1_send_fail.flag = 1;8 Q8 H2 f$ r3 ^) S3 ^. Q% O) x" w. x
  33.     memcpy(&fdcan1_send_fail.TxHeader, &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));
      V: Q, E5 o" H0 i# t- V
  34.     memcpy(fdcan1_send_fail.TxData, tx_data, can_dlc2len(DataLength));8 P, `, y" ~9 p" b, ]7 X
  35.   }
    ) c" q$ v$ v2 j8 b$ n: O7 h; B
  36. }! b) |: J$ D5 o: R1 d; X

  37. 7 l5 z+ G% D+ j1 ~" L
  38. int main(void)! R7 [2 H+ U% |8 ^
  39. {
    ; d1 s, X6 C" u' A2 _
  40.   ...
    7 [, b6 D! Y+ A6 u
  41.   /* USER CODE BEGIN 2 */; \4 J$ Y2 Q5 N1 Y" s" D& b0 L) q* p
  42.   fdcan1_config();; E# C1 x: O% p+ F" n0 a9 |
  43.   fdcan2_config();
    . j7 n) g9 C$ Q9 N4 H& k
  44.   fdcan3_config();0 ?5 t4 M/ e$ R/ J' D5 v7 {$ K

  45. ) y" C) X/ u* ^$ K1 O
  46.   for(uint8_t i = 0; i < 64; i++) {
    ) N' e! v& P& M1 |; @: e7 C
  47.     TxData1<i> = i;</i>
    # `/ b* t" x; c; Y% |/ w3 o
  48. <i>    TxData2 = i;</i>
    2 S. _0 H8 ?( [
  49. <i>    TxData3</i><i> = i;
    ; C4 p  m" T! o6 J
  50.   }/ G: b. H) P  z4 y3 y+ Y, K8 j
  51. 7 v& z+ v1 R, u
  52.   HAL_TIM_Base_Start_IT(&htim6);4 D9 p" [# `  A% C6 Z: Q. _
  53.   </i>uint32_t count = 0;
    + l/ S, E( k. J% M. q
  54.   uint32_t cnt_100us = 0;
    / j! u# \6 b* h' s
  55.   uint32_t cnt_500us = 0;/ t' o5 L, s8 M. v$ Q( V$ }
  56.   /* USER CODE END 2 */
    6 ]+ E9 U; z3 p* h" z/ @0 z& B) r* {
  57. 4 x  |- N+ D, Z# |* H" I6 G9 r# c
  58.   /* Infinite loop */
    , ^6 P1 b' G9 E9 ~& \0 J
  59.   /* USER CODE BEGIN WHILE */, }" ]6 A$ g  g$ ]- h6 y
  60.   while (1): O  _0 v6 }0 G* }
  61.   {
    : D) j$ A7 o) Q8 f6 z  ]3 w
  62.     /* USER CODE END WHILE */
    " N+ G9 `" g; R' x& e, N
  63. 5 r6 Z, h! W% r' w, P/ Z. h
  64.     /* USER CODE BEGIN 3 */0 w$ \7 c7 a! h
  65.     if(tim6_flag && count < 1000) {
    : K) E7 ]2 o1 j% A; I! {2 h/ W
  66.       tim6_flag = 0;
    8 L' l* T, a' e* h  v) r
  67.       TxData1[0] = count >> 8 & 0xFF;2 J8 n  B0 A' o9 e4 n& `+ a& K
  68.       TxData1[1] = count & 0xFF;$ ]! A+ o" ]' G
  69. 3 R: R+ [& T! k3 C/ o
  70.       ++cnt_100us;
    ; |& B0 J, R: a  \5 b
  71.       cnt_500us = cnt_100us / 5;& K* i8 k. \# k/ i$ I7 q5 r
  72.       if(cnt_500us && (cnt_100us%5==0) ) {
    . h6 ?! j, L) r) _# z* @) j
  73.         switch(cnt_500us) {+ ~1 v! H+ J9 h
  74.           case 1: fdcan1_transmit(0x123, FDCAN_DLC_BYTES_64, TxData1);
    ! V0 N( @' _7 F: S4 d
  75.                   fdcan1_transmit(0x124, FDCAN_DLC_BYTES_64, TxData1);# [/ w# S+ h. p* P  A/ m
  76.                   fdcan1_transmit(0x125, FDCAN_DLC_BYTES_64, TxData1); break;8 f: d( N& B$ X$ Z4 M
  77.           case 4: fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1); break;0 X9 d3 x: `- Q( y. O
  78.           case 5: fdcan1_transmit(0x12345679, FDCAN_DLC_BYTES_64, TxData1); break;
    % u; x; l$ |5 k$ ?2 }; n
  79.           case 6: fdcan1_transmit(0x1234567A, FDCAN_DLC_BYTES_64, TxData1); break;
    $ Q7 y$ R" e# p2 F0 Z
  80.           case 7: /* next send */ break;0 w+ ], l' M# s8 f
  81.           case 8: break;4 s2 H  i* ~5 q% x4 B
  82.           case 20: ++count; cnt_100us = 0; break; //10ms
    & Z9 o$ b2 Q6 i
  83.         }9 D' n0 z6 |# O/ _
  84.       } else {  //fail retransmission once
    $ b3 h' o* ^( u+ o! H! e* h
  85.         if(fdcan1_send_fail.flag) {+ a; n" O3 P6 G  m7 f: d
  86.           fdcan1_transmit(fdcan1_send_fail.TxHeader.Identifier,
      B1 k1 a: z$ I& G
  87.                           fdcan1_send_fail.TxHeader.DataLength,9 ?, ~4 N) a2 b9 F( m+ q
  88.                           fdcan1_send_fail.TxData);
    % Q/ R# [( l. r0 j- U: j% V9 t
  89.           fdcan1_send_fail.flag = 0;  D& P+ C! }# P* }
  90.         }
    0 u5 N$ O) J  ^6 ~' D
  91.         if(fdcan2_send_fail.flag) {
    % V6 J! k+ j& A- _4 j. G4 T
  92.           fdcan2_transmit(fdcan2_send_fail.TxHeader.Identifier,
    9 n2 B+ S6 H+ e) w& O7 S
  93.                           fdcan2_send_fail.TxHeader.DataLength,7 I$ P( d* K- m
  94.                           fdcan2_send_fail.TxData);
    2 c9 H: p% Z7 ~' y
  95.           fdcan2_send_fail.flag = 0;  g/ [6 L- K% u% j" f( z9 c
  96.         }0 O# }* h8 A9 w. }
  97.         if(fdcan3_send_fail.flag) {
    # X* J! H" h# t" m
  98.           fdcan3_transmit(fdcan3_send_fail.TxHeader.Identifier, / Y9 b5 @! C5 f$ l
  99.                           fdcan3_send_fail.TxHeader.DataLength,
    6 e  x! t5 U! A
  100.                           fdcan3_send_fail.TxData);
    + J# m; Q( L2 Z( \
  101.           fdcan3_send_fail.flag = 0;7 \) O- B* V! M8 m
  102.         }) g+ ^# H, _0 R6 B' _/ M
  103.       }
    * Z7 }+ C8 J* o) U9 J7 g
  104.     }/ R8 d3 ]+ Y& ~$ Q* b
  105.   }3 i) J! u+ Q/ `2 }  {
  106.   /* USER CODE END 3 */  
    5 b& P1 r- P: w6 U' O3 |
  107. }
复制代码
; C* P- |9 d+ a) V6 `- U3 u
fdcan2, fdcan3和fdcan1的发送类似, 3个发送函数可以合并成一个, 这里没有合并.
4 T) j. R/ F9 e
* @6 W+ J8 T% J7 v  }发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.9 ?4 R. ]2 N( h- w; S! G. B, n
- x- ^# K% Y, H' F/ e
这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.
3 b  b) p4 z2 y; G" A0 O6 t( O1 p% c3 K: t
因为发送最多可以缓存3帧, 所以可以一口气发送3帧, 如case 1处, 也可以一帧一帧发送, 如case 4, case 5, case 6. 这里是1.5ms/3帧或者500us/帧.
: R9 N4 f- S( i' r
7 T8 f; X7 d/ K6 ?因为总线中还有其他节点发送之类的, 有可能发送失败, 这里留了一次发送失败后延时100us重传的机会, 具体情况根据现场可另行调整.+ C" Y' \" D$ v' }2 c2 I! k

# \) o, e) p) t/ ]9 W0 Y& S& J如果fdcan1, fdcan2, fdcan3没有在一个网络中, 可以一口气 fdcan1发送3帧 + fdcan2发送3帧 + fdcan3发送3帧.3 O" B; {  |2 C+ C; f
& L6 T- F  t4 z: w: B# W
一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.& Z- s' d8 ^( I- ~
- I; h4 ^7 a5 A: d
程序中发送1000*6=6000帧后停止发送, 10ms发6帧, 所以10s后数据就发完了.
. k* _- s4 l+ W  `4 }. @% z6 Z( M6 f% i
使用Xavier配合测试一下
" ~/ w  ^( a& g& @把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:
4 D" S) p9 H' P( O) D' {3 J" M3 G' k8 e0 _5 H3 `
  1. #!/bin/sh
    ) q' [* U; j8 w& Y; L
  2. ; `$ {' V% I2 J5 h4 z) n" T+ P
  3. sudo modprobe can8 g0 i2 w! D1 q) j: n: l7 f' p
  4. sudo modprobe can_raw. Z% r' T4 a0 ^6 d9 @' a; o
  5. sudo modprobe mttcan: `2 A0 U4 A/ {4 `$ u" }" C& m
  6. 2 Q+ a) |. P2 J& a( A
  7. sudo ip link set down can09 r2 V* N% `/ Y" \
  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
    ! |( d5 B" U& h5 M6 |) e& n6 I
  9. sudo ip link set up can0 & B" o5 T6 [9 l+ q& a) M2 a
  10. sudo ifconfig can0 txqueuelen 1000
    + Y$ v+ ]# ~6 E3 X' F

  11. 5 J; Z  i' d4 ?: ~
  12. sudo ip link set down can11 d4 d) R; y) w9 W+ D1 f
  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
    4 Z; }: p( I* P$ ~2 M
  14. sudo ip link set up can16 S1 t- b. ~6 N( F! a+ G5 o
  15. sudo ifconfig can1 txqueuelen 1000
复制代码
Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.
1 U& ]3 D+ Z& F" p, M: P4 Z& z% ], E+ q" V: f$ |7 n$ c8 ]
restart-ms 100设置总线Bus-Off时, 100ms后重启.
' \( q3 r' X2 c* _5 T
* A5 s/ M0 B* q& q4 u$ y. }设置完后查看设置状态 ip -details -statistics link show can1:
( H8 O# W( w. I( P% l0 G( B, l$ w/ y" P6 k
  1. $ ip -details -statistics link show can1
    9 b4 ], v; v  e4 s, _0 @9 p& ^! Q5 [7 A- I
  2. 6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000' \( p, z) K" U: O; Y, j2 S: B/ h
  3.     link/can  promiscuity 0
    ( P: C7 L* z$ n2 O5 U: F
  4.     can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100
    1 u/ y9 H7 @6 c+ t* Y
  5.           bitrate 498701 sample-point 0.792 3 M: T, S3 Y! [0 {/ H  M
  6.           tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 1
    / h$ n7 Z! E% g" V; g
  7.           mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 10 E" f* k$ l+ [5 Z* i4 d) l  w5 U
  8.           dbitrate 2021052 dsample-point 0.736 " I; K4 X* ]- \, P0 U0 e3 c
  9.           dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1# t. l$ |9 q2 k/ e
  10.           mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 16 t- U$ J% k9 u2 a3 C. D
  11.           clock 38400000
    . x  k$ n0 R- o# L( W6 e
  12.           re-started bus-errors arbit-lost error-warn error-pass bus-off+ S. U( t  B3 L: D" I( |: Q
  13.           0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 : I1 B% @8 j* r
  14.     RX: bytes  packets  errors  dropped overrun mcast   
    0 ^8 a( n! w# Z2 P' ~! J
  15.     64578440   1013451  0       0       0       0       & M$ [6 G- \; `  ?, ~: P8 v
  16.     TX: bytes  packets  errors  dropped carrier collsns 4 L- M+ \7 M; z
  17.     952448     15914    0       0       0       0   
复制代码
位速率和采样点的些许误差测试并无影响.
% L5 ~* Z! w4 M5 i& a
2 J& u9 Z: {1 Z" ]5 L使用 candump -ta -x can1 >24.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的6000帧数据全部存到24.dat文件中了, 共计6000行, 这里截取首尾部分显示:; w" u4 ?4 N- C1 b) j
# }' T7 \* j$ |( k, X. }
  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 3F0 _( K  R" S1 u# ]1 [0 \( c# y
  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 3F8 V* U, \( |/ ]& |* N
  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
    6 `+ X" h; H4 t7 k; O$ }# h
  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( s) }: {  v$ [* D) \
  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* x" V* g: r7 f5 e7 b) F
  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 3F5 u) \8 t* \' O) x' H" _2 q8 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
    4 t  S: q/ h7 d2 i/ l
  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- M% Z& ^' F0 i5 r/ q  S

  9. * o* M% D* A& M: I% v4 F* u, t
  10. ... % U3 M3 Y' s7 W+ h
  11. 6 s$ |& R, @, F0 b1 N9 A8 {& }
  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 3F3 W, ]/ M* x9 j/ }: r
  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 3F8 a9 b% b% j) ~( Q) C' U
  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
    , s3 t9 i9 T2 s0 B7 G
  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
    ( q5 v! a9 E$ p5 T! F- T" w
  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 3F3 F+ g6 @4 F8 r0 V5 C/ G
  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
    9 b9 o6 s  x7 _& A" M9 G
  18. (1613988969.097116)  can1  RX B E  12345678  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F0 S4 X2 s. ]# X" R+ }: 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 3F  l, j: S; X+ y9 p: _; g3 ?
  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
复制代码
3 I) V/ }- t) c1 ^
这里前三行的格式问题, ESI的404行之前是-, 404行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.
! w% j& t7 w0 v# z: ]4 j+ R8 v& O; a
Xavier发送脚本, ##后面的3表示开启BRS和ESI:
7 f# f/ g& {* y- \- `$ v% X, |6 M) W( `1 a' d- D
  1. #!/bin/sh
    % B  {8 d, \+ X0 r( H) {( f& X
  2.   x1 A* T( h; t! m9 e
  3. while true; do
    + y( S9 S. I! o* a+ E2 {; o
  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
    : M7 Q8 z2 x. }
  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.161 x/ B6 A( @/ t0 M
  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 p+ G! z1 q$ i
  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$ ^& d' j0 o9 ?7 l( j
  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.169 c% j4 T6 i( R/ h
  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  
    : Q& h" v2 p! I/ V% `. Q
  10.     sleep 0.01) ?6 f) n! }) G( `
  11. done
复制代码

" u  b2 L7 S9 _" N可以在LPUART1串口中看到收到的数据, 如上面 新消息接收处理 小节配图.
3 I/ t& \0 m7 B7 W$ B# u, _% b8 p6 L9 p. B+ `
核心思想是:
& z( v3 r" h" m, \9 z; l3 D& a% N. B) t( g4 T) ~; K& S
Mode 设置为Classic Master或者Classic Slave, 而不是FD
3 B) ?' ?' {, W5 h. x  k; Q! L6 J仲裁段和数据段的通信速率都设置为500Kbit/s
1 ~; B2 s9 ?" S/ k
( p& G% z+ g  u: R1 t& Y. }/ C3 w* N
- i4 D2 \/ `# w- Y2 I2 I5 k9 J) F0 r0 i0 C4 B% `
收藏 评论0 发布时间:2021-11-11 22:00

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版