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

基于STM32硬件的SPI时钟解析

[复制链接]
STMCU小助手 发布时间:2023-3-13 21:19
首先粘贴出我们CubeMX生成的时钟配置:: ?- y# x6 E( X. V. n3 n: a

  W4 x. K& q1 x3 }8 G- O! R5 k3 ~
20200601200857688.png # S( [4 H! M, M; c1 \7 \
* @9 o2 X8 r" c; h* [" U
然后启用SPI3的功能,这里因为博主的逻辑分析仪比较low,所以把SPI的波特率设置成最大分频,即256分频,此时CubeMX工具计算出来的时钟频率为1.5625MBits/s:
. v" {1 A* z8 _
6 h* u7 o$ N7 |7 ]% \
20200601201432573.png
" i! D! n7 Z# T( X" L: w
) l* }5 M9 B, P' a8 u
我们都知道,SPI3挂载在APB1总线上,受到总线的最大时钟120M的限制,由前面的时钟图可以知道,APB1总线时钟速度为100M,那么经过256分频应该是390.625KHz才对。1.5625M/390.625K=4,这里的4倍频,是CubeMX软件计算的问题,还是真的哪里有了4倍频?1 g0 S% f5 Q% z- l- l- Q" J  ^$ s
7 b0 [3 L$ A4 K4 M; x
2020060120163498.png . D1 Y1 b6 m) l2 ~
& T2 a4 R, w7 P/ [
先研究一下手册里关于APB1寄存器的相关说明:3 j) [# [: Q: V8 m" h$ E
20200601204249797.png
* X+ s/ ~6 `2 F' E  y
5 ]) V( S; Y: Q9 n, A# ]  ~: ^
其中SPI3的时钟包含了给spi_ker_ck 输入的内核时钟,以及 rcc_pclk1总线接口时钟。; t* n+ v7 K' [& }  g
9 _" C( `* n9 @) B9 _
20200601204341958.png 4 }8 ?1 H( e7 e5 S; a( b- P3 t
' ?. ^7 y, X; n: I/ L6 p' b  X5 r
先看一下SPI的结构图:
* ]% Z3 D& [) t1 O# U' E* u( B, S! R) G2 a; y: ~) b( u
20200601203120302.png
. z) X1 k0 `( ?1 z
) Z8 W/ X, Z/ m0 r8 }
对于SPI外设来说,有两个时钟域,一个输入到寄存器、另外一个输入到时钟发生器,从上面的图可以简单看出来,spi_pclk给SPI寄存器提供访问时钟,而spi_ker_ck则是给SPI从设备提供SCK信号输出。
# l( [% D5 p# ^再回到CubeMX的软件配置界面,发现这里新激活了一块:
+ {& x: U7 K9 Z; Y8 v
9 x" z" S8 C! \. j0 e
2020060120394618.png 0 I* t1 r* n0 c4 I
8 ?" C7 l/ q$ W4 ^
多了一个SPI时钟矩阵,难道这个就是spi_ker_ck?
. I3 v5 N- e5 j. B' _2 _: n假设这个最大再来分析一波,对于STM32的SPI协议来说,Data Size最小为4bit,最大为32bit;
1 w9 p0 {% C" }" i& x2 V: |当传输的数据位为最小4bit时:% G+ L: A- h" m# t6 `8 r$ h/ C
受到APB1总线速度的限制,spi_pclk最大也就120MHz,因为PLLQ最大也只能是480MHz,假设这个SPI Clock MUX就是spi_ker_ck,那么最大也就是480MHz,刚好接收完4个bit,寄存器的时钟脉冲也到了。
: q+ }( A! D  ?' r话不多说验证一波,根据CubeMX生成的系统时钟配置如下:
; G9 w: ^; M: C5 i
  1. /**1 V! J4 N% L/ k
  2.   * @brief  System Clock 配置5 A/ ~6 U7 N+ ~7 d0 H/ U
  3.   *         system Clock 配置如下:) k3 ~. Y" z# [
  4.     *            System Clock source  = PLL (HSE)( H0 I! S2 T2 Q7 e; M3 ]: a
  5.     *            SYSCLK(Hz)           = 400000000 (CPU Clock)
    # t3 A2 c3 n& ~8 E6 C% B5 E
  6.     *            HCLK(Hz)             = 200000000 (AXI and AHBs Clock)
    , o/ M# H* I  k1 O9 _" _! S# _6 s
  7.     *            AHB Prescaler        = 29 S7 a* L, T- Z( g9 H
  8.     *            D1 APB3 Prescaler    = 2 (APB3 Clock  100MHz)  ?! O" x0 p! ~4 m; [* t! A
  9.     *            D2 APB1 Prescaler    = 2 (APB1 Clock  100MHz)
    6 ?% G3 M0 U9 j6 H' |
  10.     *            D2 APB2 Prescaler    = 2 (APB2 Clock  100MHz)
    7 W0 L; X! \5 w$ ^8 @
  11.     *            D3 APB4 Prescaler    = 2 (APB4 Clock  100MHz)( Q3 d$ @0 e" X) B
  12.     *            HSE Frequency(Hz)    = 25000000. v, j8 j7 e  F: K. z: j
  13.     *            PLL_M                = 5
    " V9 K& h  b6 J; c  Y: m
  14.     *            PLL_N                = 160
    1 t6 N2 a* U" O) E
  15.     *            PLL_P                = 2
    $ i. K4 o6 D3 F3 }# y
  16.     *            PLL_Q                = 42 t4 G: \( P' w0 m9 P0 `# I* U9 {8 u
  17.     *            PLL_R                = 2, R8 _, A& j& `2 s
  18.     *            VDD(V)               = 3.3
    9 p) j" V% \# s8 {; i2 g+ y% @. }
  19.     *            Flash Latency(WS)    = 40 [: T( t! i' e
  20.   * @param  None. X; ~: @' o8 `- _& {: `
  21.   * @retval None: U& w7 S+ h' |, w
  22.   */
    4 G  W9 c) N& }$ e
  23. static void SystemClock_Config(void)
    . o: y! z! D9 C( [3 P. B. `
  24. {
    7 I, y! a4 h0 s" }0 g& {
  25.     RCC_ClkInitTypeDef RCC_ClkInitStruct;
    6 E" r% p9 H) d0 Y; L
  26.     RCC_OscInitTypeDef RCC_OscInitStruct;+ ~: K2 Q* c. A$ C- w9 R/ T
  27.     HAL_StatusTypeDef ret = HAL_OK;
    6 G; L, Z/ l: q% L/ u
  28. / z" V9 p+ `0 g! ?4 f) G( O
  29.     /*使能供电配置更新 */. k. o& h, u- j3 U; C. a. H
  30.     MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);
    + b# ^3 m& \: O$ ^: y% f# h$ p
  31. % v7 R4 B1 ]" D  g4 d! q3 d3 H; R
  32.     /* 当器件的时钟频率低于最大系统频率时,电压调节可以优化功耗," d1 g9 j- ]* o# n0 S
  33.        关于系统频率的电压调节值的更新可以参考产品数据手册。  */7 @1 P( I: @! x: \( f# `: S0 n
  34.     __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    3 Z& A! l, s$ U  g' y7 A$ S; [

  35. 4 H$ J) C0 Z$ n% B: C$ B
  36.     while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}2 v$ h& C2 H- T. k2 A& ?

  37. 5 c. f1 S' w/ E' I" |: T( r% [
  38.     /* 启用HSE振荡器并使用HSE作为源激活PLL */3 h% \! i) \# O+ ?  E6 s; O
  39.     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;1 r2 Y- V- N9 z% x$ _
  40.     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    5 s0 \5 l. |8 O$ {/ S5 C0 V5 |- _
  41.     RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    " q; E- l* K& ]/ A3 e
  42.     RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
    ) n# t  t) s+ _9 f
  43.     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    $ l7 S* o' Z5 w! x# Q# J
  44.     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;: b- b! K9 K" W( }) \

  45. + t. b( l: f" \% P% ~/ ?8 q, Q
  46.     RCC_OscInitStruct.PLL.PLLM = 1;- f4 N+ }, p+ q
  47.     RCC_OscInitStruct.PLL.PLLN = 100;
    % U0 f, V2 `, z) M5 R, e/ P
  48.     RCC_OscInitStruct.PLL.PLLP = 2;, \) y$ m( _( _4 C
  49.     RCC_OscInitStruct.PLL.PLLR = 2;; G# ^$ y- q% y( ~
  50.     RCC_OscInitStruct.PLL.PLLQ = 4;6 R& @8 q! {! l& o/ Q

  51. 1 q2 N) ]. B5 F+ N. S" W
  52.     RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;0 A9 K: |! n; G+ c5 U5 ~
  53.     RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;5 y/ s8 \4 `* n6 S9 R5 }+ v
  54.     ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
    + V9 A! N# {0 a$ I9 j1 C, E7 \
  55.     if (ret != HAL_OK)4 k7 y% ?4 _1 K. P+ K1 J1 n8 z
  56.     {1 F  U( n2 v) Q+ n: a
  57.         while (1) { ; }
    5 I/ E6 Y) v# O9 C9 ?* K
  58.     }
    ( s" A6 s* y2 f9 [# J

  59. " c1 M& S5 g9 P/ D/ P7 h- L( J
  60.     /* 选择PLL作为系统时钟源并配置总线时钟分频器 */
    6 i6 e& _4 @% Z" O% P  l& `
  61.     RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK  | \
    9 \5 q' ^7 C: V( {
  62.                                    RCC_CLOCKTYPE_HCLK    | \
    ) f4 V- H1 y9 l3 m7 V
  63.                                    RCC_CLOCKTYPE_D1PCLK1 | \
    # j  p7 t( r! T7 @6 {7 I  v
  64.                                    RCC_CLOCKTYPE_PCLK1   | \. g  F& ^2 w: M! V" |- |& f8 d
  65.                                    RCC_CLOCKTYPE_PCLK2   | \8 Z3 d# P, g8 b8 j2 \
  66.                                    RCC_CLOCKTYPE_D3PCLK1);) w* t9 V2 e' i
  67.     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    * p  c) ]2 J" j
  68.     RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
    4 }8 k) t, D" x" m
  69.     RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;. S5 V& I3 L9 q( b* n0 e
  70.     RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
    ; |: [, |; N/ }- \
  71.     RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
    & ~; g, L: `6 C+ _  {  ]
  72.     RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;/ Y( p' R" y/ X# Q* t* w
  73.     RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;5 c4 v4 d9 T8 c  b$ r3 a
  74.     ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);2 G4 z2 Q- m/ _
  75.     if (ret != HAL_OK)
    1 Z! e6 G7 C3 ^
  76.     {7 N' ^0 u% Z* k6 a
  77.         while (1) { ; }
      k2 V+ J5 b5 O$ I! i4 M. t9 i
  78.     }0 _$ Y. j5 h# U) d. A

  79. ( B* ~$ Z$ L6 s* \  z# g) |
  80.     RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    ' q' M+ [& L& L2 I, r& \
  81.     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_CKPER;( @6 p# t& c3 W1 Y! C. h4 C
  82.     PeriphClkInitStruct.CkperClockSelection = RCC_CLKPSOURCE_HSE;
    / p  Q# N  l8 s/ a" k) W. W
  83.     PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_CLKP;
    $ I, ^) T& _" j$ H; c
  84.     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    6 E* Z. t0 N* U  U! Y3 M4 l
  85.     {' p6 m* b7 S; [# q$ v
  86.         while (1) { ; }% H7 k: d1 b/ i/ X4 ?2 x! ^
  87.     }
    " s- {+ e+ b' ~3 r" S3 A( ^

  88. $ a0 I0 r- l3 q+ M1 `3 s
  89. }6 D) i- m4 }; T* R# U3 A/ D/ f2 @
复制代码

+ N7 e% x% s* A* C$ {/ m对应SPI3的配置函数如下:
9 G7 O% g$ e" k! |, O7 R
  1. SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄
    ! ?. X& [5 I$ O9 M1 g
  2. . @/ p8 ~+ R! V. E; r( i* I
  3. void SPI3_Init(void)1 H( M" K- K/ E( q. m/ I. p
  4. {
    & J, i& M, y" w$ z3 `6 O
  5.     SPI3_Handler.Instance = SPI3;( A7 ]( l+ V! v6 @
  6.     SPI3_Handler.Init.Mode = SPI_MODE_MASTER;2 U  Q  |2 z, p2 J
  7.     SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
    4 |% w" z% D4 D& g' r8 ]
  8.     SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;. K) u; l6 o4 a' R$ }; h8 G
  9.     SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
      M  f) M4 l: g/ B6 x- s- T
  10.     SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
    7 X1 L; \+ ~- G4 j
  11.     SPI3_Handler.Init.NSS = SPI_NSS_SOFT;7 g0 o( g' X+ V1 n3 u7 K% v1 F
  12.     SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;  z9 v" ^' @/ s# G" B3 J
  13.     SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;6 S) S! r/ C: k+ a
  14.     SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
    + M/ Q. H6 J8 t2 l1 ]( M) _
  15.     SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;) P  O6 j& f* }+ b& |/ e& E
  16.     SPI3_Handler.Init.CRCPolynomial = 7;
    7 z$ ?* I. w% X" n' j
  17.     SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;' x# H9 }$ ]& }6 i4 F
  18.     SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    # \$ l+ x5 S* s7 y  g6 q9 Q0 H! m
  19.     HAL_SPI_Init(&SPI3_Handler);9 \  }& r7 F+ h: v# ?
  20. ) m, ?+ s+ o0 `8 z
  21.     __HAL_SPI_ENABLE(&SPI3_Handler);               ( H# L+ Q3 Y$ {5 }& R  q) t7 C
  22. }3 R& F* {3 ~; R
  23. & Y9 U1 U4 H; y: e- x) g
  24. - x3 b2 B( ?, f; Q- t
  25. //SPI2 读写一个字节
    0 q. g- b4 V' e( F5 r
  26. //TxData:要写入的字节
    8 P8 }; K& o$ j3 `* Q! R
  27. //返回值:读取到的字节
    , N6 i& Y4 X9 X1 Q7 C- @5 o
  28. uint8_t SPI3_ReadWriteByte(uint8_t TxData)
    ( |2 K- g9 W6 x4 c  z
  29. {. F( q) @4 U/ ~5 [
  30.     uint8_t Rxdata;9 i2 _5 w% P* x8 n' F) H* j
  31.     HAL_SPI_TransmitReceive(&SPI3_Handler, &TxData, &Rxdata, 1, 1000);
    ' @/ q1 [; n9 I. H
  32.     return Rxdata;                      //返回收到的数据0 n2 }2 v& k: C/ Q7 q
  33. }
    ) V7 p- w& @' Y3 |
  34. " V( a. m* P3 `
  35. //读取芯片ID
    % w  \: k: w  U4 Z, Y& x+ A
  36. //返回值如下:                                  
    0 w' U2 E, R$ Z6 Q1 }
  37. //0XEF13,表示芯片型号为W25Q80  ' X* j5 O' c0 u, q
  38. //0XEF14,表示芯片型号为W25Q16    2 y8 Z4 ]7 }/ C
  39. //0XEF15,表示芯片型号为W25Q32  
    6 M" g, m4 Q: y2 g1 I
  40. //0XEF16,表示芯片型号为W25Q64 0 V) C( u% O/ |9 {
  41. //0XEF17,表示芯片型号为W25Q128           
    9 c, ~4 F4 f- W9 N1 q$ n- l  ]
  42. uint16_t W25QXX_ReadID(void)
    4 C/ \* ^2 ~8 F: B- n, _0 i
  43. {
    , r) a3 ^; W' q* m% l
  44.         uint16_t Temp = 0;          + b; R5 i7 C) _7 T
  45.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);            7 W# B, b7 w' L2 o0 y- _. S
  46.         SPI3_ReadWriteByte(0x90);//发送读取ID命令            
    : E: l. i! T/ w) z* q0 ^
  47.         SPI3_ReadWriteByte(0x00);             
    ( `2 ~% _. o- [& g) y( {+ U
  48.         SPI3_ReadWriteByte(0x00);               [% F; v$ |& o4 A% A  |- U
  49.         SPI3_ReadWriteByte(0x00);                                    
    1 b8 x6 k/ M: B2 ?0 P& G
  50.         Temp|=SPI3_ReadWriteByte(0xFF)<<8;  
    . C8 t/ Q4 g% Z! R: t  K! D, g
  51.         Temp|=SPI3_ReadWriteByte(0xFF);         
    6 S+ k8 s/ j. r: S7 A4 O5 a
  52.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  9 n' Y7 N8 [; P' c, a. i( a; h3 W% r" N
  53.         return Temp;
    ! d. y% j8 G/ a! J+ z8 K6 G8 C
  54. }   3 F8 ^3 G. |3 y/ e

  55. + g/ h- J# y" b8 B
  56. void W25QXX_Init(void)
    6 i) a9 Z0 r/ t) l
  57. {8 L5 }4 j5 Q7 J
  58.         MX_GPIO_Init();
    . X$ r/ u  ?$ D; u) _" }
  59.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
    & n. L, @# p4 f1 j: u  ]
  60.         SPI3_Init();2 }$ w8 ~6 V( \0 m. i
  61.         uint16_t W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.  * U: t- j# u3 K) x- w
  62.         printf("W25QXX ID:0x%4x\r\n",W25QXX_TYPE);+ `" ]& \( r6 {/ s
  63. }
    - f* N& L  O, K" p2 i- U+ P" Q
  64. ) m4 r4 ^. V; d3 p- T% r* Z8 x
  65. void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle). r. u8 S+ N1 P" f7 N
  66. {
    # z5 @2 s' E! {3 T! O  w% Y1 O9 E
  67. + j9 i2 e5 t" h8 u0 r) C1 x
  68.   GPIO_InitTypeDef GPIO_InitStruct = {0};7 L4 [. d% C8 a+ g0 E4 j' Y
  69.    if(spiHandle->Instance==SPI3)" B0 u0 E) a1 t& F+ `  u: b
  70.   {7 W  h* B9 g+ O! Q
  71.     __HAL_RCC_SPI3_CLK_ENABLE();
    / D& B; e3 c8 {7 x* K7 y6 g5 X
  72.     __HAL_RCC_GPIOB_CLK_ENABLE();6 {& b* V/ U$ _
  73.     GPIO_InitStruct.Pin = GPIO_PIN_2;8 i% N$ Y4 ]2 Q5 j
  74.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;9 z( M% G* G! z
  75.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    % f3 i- a0 _/ A6 ?5 Y! m% N7 E
  76.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    - D" z' X2 w2 `0 ^( N/ {
  77.     GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;" f3 w- i9 V6 j9 l& _$ e7 R) M- m
  78.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    8 y6 \% t: `8 P5 O7 n$ q8 F! \3 @
  79. 3 |9 _+ I7 h( E2 m3 B/ A/ j
  80.     GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
    - P) s* O& D% Y6 D, _$ @+ T
  81.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    7 b, J* g# o' u: P
  82.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    * e7 B1 x" e, i: ^) h2 x
  83.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    " u5 A2 _5 s9 B) s# ?; R" {
  84.     GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;4 S# l4 C$ u1 U, j0 K4 I, m( o  i
  85.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    3 [% n6 F. T! h3 S9 s
  86.   }( h! ?( ^# w6 e% p$ g2 I+ x
  87. }
    ; {* \, C+ l5 D2 B* l3 ]/ G; D. C5 E
复制代码

- D( u: j' y* n. A( p6 o6 n' |' \$ i先直接调用函数W25QXX_Init,得到输出:' t; m# k6 S! M# B% R
' A9 Q  K; A" {% x' n+ i/ E. k
20200601211725431.png
! g# ]1 T' O1 \9 t% G

$ d/ p6 Q; m2 A& H连接逻辑分析仪:
1 j* c* k6 `6 |/ f& r$ c' ^
  g( C, k+ i/ X" O3 x4 v
20200601211809725.png . w1 @/ j0 ~' @) Z8 h

, G& c- \, X1 v& S+ J% O+ Q复位一次抓包:4 H1 B7 ?# d, s, l& a; {
$ o$ w# @# H0 g7 ]# T
20200601211911530.png
9 q) R3 I8 p4 h9 k% m

( ]" t8 y) F$ t$ [/ S8 n对照着我们读ID的程序:
; T* d5 P6 i! R" h8 i
  1. uint16_t W25QXX_ReadID(void)) S' x3 G" s( Y7 E
  2. {! @0 e6 g$ V& t- |
  3.         uint16_t Temp = 0;          
    + y% J; F0 w( ?! K4 q4 ~8 a' E
  4.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);            & l  ]/ n( H+ N3 Q6 L9 Y
  5.         SPI3_ReadWriteByte(0x90);//发送读取ID命令            * U! k0 M/ l& i- ?: {! i
  6.         SPI3_ReadWriteByte(0x00);             
    - M. c* t; s- \" Z' h
  7.         SPI3_ReadWriteByte(0x00);             # R/ h" N/ L2 N1 d
  8.         SPI3_ReadWriteByte(0x00);                                    
    * U' b# c" g; _" U5 X
  9.         Temp|=SPI3_ReadWriteByte(0xFF)<<8;  
    , n+ z! y2 R* `/ X% I7 r5 U4 u
  10.         Temp|=SPI3_ReadWriteByte(0xFF);         
    ' c: L3 i: }/ Z2 N% D
  11.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  
    $ _) j% J8 G6 e1 ^" s  W4 E$ b
  12.         return Temp;
    2 E) t* R' _4 }  w/ q
  13. }   * \  V. v- w* M0 T. a) }5 _8 t5 R
复制代码

6 d& T% N$ f  g4 z- Q其中0x90=144,0xEF=239,0x14=20可以看出,读写过程是一个全双工的过程。
# Z1 }* `7 ], t) p1 a9 L, y. Q% A" q: y
20200601212445693.png
8 t; k! h* j$ u

" u) l+ c( r* K( p: C放大来看,左边有个ERROR是因为我是抓的片选信号的下降沿,而在上电初始化IO口的时候默认拉低,随后手动拉高了。
9 Z  T9 w7 b  t8 ?而右边的数据,时钟周期是1.25us,即800KHz,虽然逻辑分析仪比较垃圾,但是800KHz和签名算出来的1.5625MBits/s的波特率,好像还是差了个二倍关系呀,emm……
9 ?' S3 K6 {( P4 I) G心中掠过千万种不合实际的想法:比如SPI可以根据时钟极性配置成上升沿和下降沿各采集一次?还是全双工的波特率要x2?但串口人家也没x2呀……% B- y, e# ]0 L9 h* T) `/ V( O! G

9 O9 o8 c5 r$ H再次想着是不是逻辑分析仪的问题,准备把SCK速率调低,不过最大也就256分频了,再调就只能改PLL的DIV1Q了,说改就改,突然发现,写的代码里居然和时钟树不一样……(因为这里偷懒,直接把SPI的配置放在了一个常用的工程里,时钟配置直接用就没改,平时也没注意PLLQ……). N+ i" A2 y8 m. c# A# I0 I$ r5 v
  A0 [( z' m* h7 C# a* @
20200601214012266.png
2 B. A3 y: W1 ]% x9 E! F
$ Q" R! D5 c7 z8 p
所以这里的实际计算的波特率应该是1.5625/2=781.25KHz,和上图里的800KHz接近。
& q1 L* K: Z( H  C( y2 G0 b- K. X# ?

% _: E/ O  E+ F! ^  k1 y总结两点:5 ]+ E; O4 w1 g% X) |
HAL_SPI_TransmitReceive的传输是全双工的,如果硬件是单双工的收(发送端悬空),SPI3_ReadWriteByte可以传入任意参数;如果硬件是单双工的发,那么返回值可以不要。
8 Y; c7 E& o( R- X% h2 G  g. GSPI的有两个速率,APB1的速率只与处理器访问APB1总线上的SPI寄存器有关,不影响通信;而SPI的SCK速率由单独的时钟矩阵选择输入源,在经过SPI外设的分配器产生波特率。. {6 S' f! ?) P
希望这篇博文能够帮助大家更好的理解SPI协议。
3 w" e  _5 p1 \/ b* Z8 t————————————————+ f( B# D0 n' B! {$ d# `
版权声明:小盼你最萌哒- w" D1 y, ]( e* `7 _) U
如有侵权请联系删除
5 n; F: [* ?$ M1 m/ ~) `' p# ?3 I1 o- o8 |6 B* e

, I* d/ X3 D8 b
: ^, Z, g# W+ V4 J3 ]
收藏 评论0 发布时间:2023-3-13 21:19

举报

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