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

【经验分享】STM32的SPI外设片选只有一个怎么破?

[复制链接]
STMCU小助手 发布时间:2022-6-23 21:00

之前用STM32的SPI需要控制很多外部芯片,可是一个SPI的外设只有一个片选,要实现独立片选一主多从,怎么实现呢?

! C3 Y- B& x9 |* I8 i( ]( a0 Q

SPI总线拓扑

一般地,SPI总线按照下图方式进行连接,一主多从。


" d9 ^" M: W! p- [6 g/ M
' q- ]" P# S- `& s. s# r
D20@Z{HTNK{J0FJJ1[EQZ26.png

$ `0 `+ k& Y; _+ D7 |6 K6 \

如上图:

  • 每个从设备都有独立的片选引脚,主机同一时间段内,与一个从设备进行通信,也即选中一个从设备。
  • MOSI/MISO/SCLK并联在一起
  • MISO须是三态门,当从设备未选中时,该脚须设置为高阻态,而不能是输出态,否则会影响总线
  • 对于MOSI/SCLK,虽然并联在一起,但是由于仅一个输出,多输入。
    2 I% @; r9 ^6 N* N* A8 S  V0 z% Q4 J

    . {, r! ]# S4 f3 h

但是你看STM32的SPI外设,一个SPI仅有一个NSS信号,以STM32F407的SPI2为例:

  R- `+ h7 S  X) \% [" S

那么要实现前面说的一主多从,怎么办呢?有朋友说,直接用GPIO去模拟不就可以了。

不错,SPI总线要用GPIO模拟还是很容易的,但是这样做波特率做不高,需要占用CPU时间,效率比较低!而用SPI外设控制器,底层bit流的收发由外设控制器实现,用GPIO模拟则需要CPU参与。

% A& U/ r- ~3 T) V; Z8 q) c

怎么破呢?菊花链拓扑% d% K- F7 _" F, i4 U
* K7 d" |8 ~* n. s5 f* B

5 V  H( Z6 p: \8 M0 V! x6 |9 y ]$)3V2VSM`}FB4IQGA%D@UH.png
: R) Z& j! D4 `2 T4 ^, |* \3 F/ B# N* e; [5 x1 p3 f" H

这种方案,省引脚。但是要移位控制,相对独立片选效率还是低不少。


% M: ]5 i2 n' k8 O1 f

独立片选拓扑

SPI外设的MOSI、MISO、SCK还是照用不误,但是片选我们不用,设置成通用输出模式,再用其他的GPIO片选从芯片即可。

上代码看看:

  1. <font face="Tahoma"><font size="3">void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi). D, Y% G5 e5 i6 d' }
  2. {
    - X$ x5 e5 z4 ^. F" k4 u$ {* V6 J
  3.   GPIO_InitTypeDef GPIO_InitStruct = {<font color="rgb(184, 215, 163)">0</font>};
    ) f, d- }0 W3 q
  4.   <font color="rgb(86, 156, 214)">if</font>(hspi->Instance==SPI1)
    9 c8 h+ \) _8 T% D4 Q4 q( a  m7 _
  5.   {
    / B9 @5 a: r7 X* _) P
  6.     __HAL_RCC_SPI1_CLK_ENABLE();
    , X7 z7 O+ g( x  }
  7.     __HAL_RCC_GPIOA_CLK_ENABLE();: r8 j0 o) C& B% }
  8.     <font color="rgb(87, 166, 74)"><i>/**SPI1 GPIO Configuration) m( s/ N; n4 U7 l
  9.     PA5     ------> SPI1_SCK3 Y7 u  @# u8 d0 w9 [9 O$ i
  10.     PA6     ------> SPI1_MISO
    9 l) J& P: k- s# L) B6 ^
  11.     PA7     ------> SPI1_MOSI) Y( e/ |& s& {( N+ @6 }
  12.     PA15     ------> SPI1_NSS 但是这里不用
    + T. s3 g3 x  b8 f) D  l5 ]$ o+ Y
  13.     */</i></font>
    . G! y+ F/ C6 U" z3 F8 M
  14.     GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;2 x) M  y# P- B: }4 y' s
  15.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;2 y- B7 ~5 A1 t" x: v7 ?  p0 V
  16.     GPIO_InitStruct.Pull = GPIO_NOPULL;9 a5 `, @" _$ r+ e: b
  17.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;9 D5 Y+ {! b/ s. v3 L
  18.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    & C7 G# h+ ?- z7 u
  19.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    : ^5 D6 Q6 L- k/ V2 \* [* R; r( O
  20. 6 ?7 c2 M3 q4 N) z" W
  21.    /*__HAL_RCC_GPIOC_CLK_ENABLE();
    4 E7 f& s9 T2 O! _' {5 K* Y8 t3 ?; O* M
  22.     GPIO_InitStruct.Pin = GPIO_PIN_1;
    + n# W" {/ v! H( t( Z
  23.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;  E  T# d$ P6 g# N) N7 @
  24.     GPIO_InitStruct.Pull = GPIO_NOPULL;) s) V2 }' i* N4 Q
  25.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    * [; A# b0 a, v' @  @
  26.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;6 b- |5 A5 g' q+ u: Q* @3 r6 z9 U
  27.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/
    . R! z2 \2 j9 m; K1 G& u2 {
  28.   }' B# T8 O  F; g$ Z
  29. }) {7 q2 k4 E+ N7 I+ n$ f4 L1 T* l8 L
  30. </font></font><p style="line-height: 26px;"><font color="black"><font face="Tahoma"><font size="3">初始化SPI外设</font></font></font></p><font face="Tahoma"><font size="3"><font color="rgb(155, 155, 155)">#define SPI_CS1                        GPIO_PIN_1</font>% `. B% b: K& W. p" _7 p/ _. |
  31. <font color="rgb(155, 155, 155)">#define SPI_CS1_PORT                   GPIOC</font>
    0 E/ L0 k/ _1 R7 p, W
  32. <font color="rgb(155, 155, 155)">#define SPI_CS2                        GPIO_PIN_2</font>
    - M4 B+ ]2 G  i/ K6 i$ |) d
  33. <font color="rgb(155, 155, 155)">#define SPI_CS2_PORT                   GPIOC</font>9 V& h" k9 U9 ^& W- R
  34. <font color="rgb(155, 155, 155)">#define SPI_CS3                        GPIO_PIN_3</font>
    ; T4 Y) @' p( i( v1 R
  35. <font color="rgb(155, 155, 155)">#define SPI_CS3_PORT                   GPIOC</font>
    6 a' M+ I# N* a+ e
  36. static void init_spi(SPI_HandleTypeDef * spi_handle)
    * i& O3 a1 n1 j
  37. {, K1 P8 X& U$ R8 A9 _
  38.   <font color="rgb(87, 166, 74)"><i>/* SPI1 parameter configuration*/</i></font>
    * j) R- O5 C4 ~. \. \  q. K
  39.   spi_handle->Instance = SPI1;
    0 ^* q7 h: a$ e
  40.   spi_handle->Init.Mode = SPI_MODE_MASTER;  b3 q% v4 z! h
  41.   spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
    ) x$ C7 t/ J) `
  42.   spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
    9 v, K! Z( L! N# K
  43.   spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
    . y, a+ b) Y0 v9 |, _9 P
  44.   spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;
    ! X/ [4 s4 G$ A0 z0 X% F6 E, a
  45.   spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;/ X9 d3 o/ k- \
  46.   spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    1 |" ^7 v" p! T7 u+ D% z
  47.   spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
    # L0 f' V0 X# g  V9 B
  48.   spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;, y6 |$ E6 m# M/ }8 }3 W
  49.   spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    % m4 Q) j' W+ O  j) {3 c
  50.   spi_handle->Init.CRCPolynomial = <font color="rgb(184, 215, 163)">10</font>;& u- k3 z$ P" M$ P  F* k0 j. K
  51.   ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);' _9 W6 q# t* W3 l. ^

  52. 4 S( I, P6 V1 A% [+ v* R, N
  53. GPIO_InitTypeDef  GPIO_InitStructure;5 g7 b- J  K% t6 x8 H/ V
  54. 6 L- p5 U" X+ B/ Q; k  U
  55. __HAL_RCC_GPIOC_CLK_ENABLE();0 ^- b% k! }/ f' q1 U% o
  56. ' m" \6 p; o5 q% g1 v+ ^3 l
  57. GPIO_InitStructure.Pin = SPI_CS1;# o. b& v1 g$ ], ?
  58. GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    6 t8 q- `. i3 Q/ N
  59. GPIO_InitStructure.Pull = GPIO_NOPULL;0 l5 u& L( v! X6 [
  60. GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;! w$ R8 [6 R9 Y" _, ]
  61. HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure);
    4 A7 b3 n2 d# |& x' l; Y
  62.   
    ; b$ S" J$ R! }& O  d$ G/ a; v0 L
  63. GPIO_InitStructure.Pin = SPI_CS2;6 A9 Z1 q9 E. H5 w, [
  64. HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);  
    ) Z- J" h& X9 D& i- l, {
  65. ' m! j) l8 \% i' W% f% S  T* p  q
  66. GPIO_InitStructure.Pin = SPI_CS3;
    ( F2 j, h0 a; R' G" w1 C. Q. D2 N! @
  67. HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure);   
    7 f+ l3 B' J* {$ N8 H7 P$ y2 p  a7 V
  68. }
    - S6 x( u% ^& e0 z
  69. </font></font><p style="line-height: 26px;"><font color="black"><font face="Tahoma"><font size="3">从而原来SPI的收发函数前后加上片选信号即可:</font></font></font></p><font face="Tahoma"><font size="3"><font color="rgb(86, 156, 214)">typedef</font> <font color="rgb(86, 156, 214)">enum</font> 7 K) j( a. m% l: g* X% b8 }
  70. {  
    " {0 [4 T& S& O$ k/ h2 Y8 ]
  71. SPI_CH_1=<font color="rgb(184, 215, 163)">0</font>,) G% P2 E6 L& R
  72. SPI_CH_2,
    # m+ [1 ^; C, I+ @7 B0 I, h
  73. SPI_CH_3,3 v( H+ Y" |$ u0 o# s. I3 N
  74. SPI_CH_LAST,
    9 w' X% T" ^1 q3 V
  75. } SPI_CH;' t6 f% [  s8 u3 a0 \# w
  76. static HAL_StatusTypeDef SPI_Select(SPI_CH ch)
      k- v  X0 I( @5 p
  77. {
    # x" Q  w8 j% ]. A6 w
  78.    <font color="rgb(86, 156, 214)">switch</font> (ch)4 }3 v4 U$ }1 l' k1 A
  79.    {
    - D: s5 b: T) d9 Q1 S9 A
  80.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:* ~5 q" J9 }! Z" \
  81.        HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);
    , n, j% Z# b; j5 `. H
  82.        <font color="rgb(86, 156, 214)">break</font>;; I4 [1 Q) i4 d% x% ^
  83.       
    * R2 W2 h) d3 t  `' A, @" F0 W
  84.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
    5 Z* B5 x( L6 [2 h! E$ t( o
  85.        HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);$ V; Q" `% z. j( [2 K; s6 T+ k
  86.        <font color="rgb(86, 156, 214)">break</font>;
    & C2 I. f; f- |3 C0 D1 ]2 k
  87.        * l2 A  K' |, M4 k5 z
  88.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:! a7 O9 f( U7 Q" y1 p
  89.        HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);
    5 X* |5 r0 Z5 K
  90.        <font color="rgb(86, 156, 214)">break</font>;      
    : K+ N+ b1 M$ G7 s' }6 ]
  91.      9 Q( o  R$ y! U0 E: b/ o( D
  92.      <font color="rgb(86, 156, 214)">default</font>:
    6 w/ j6 L8 ?: y) t) t+ B
  93.        <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;9 Q( s* N; F, f( n; M
  94.    }  . `& a; D; F6 E/ o
  95.    <font color="rgb(86, 156, 214)">return</font> HAL_OK;
    1 h& e6 N' q( x( e
  96. }
    * P" j8 x% M+ S
  97. static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)5 P; a7 N' J, I1 B( i$ ^
  98. {# u: ~1 e$ |' {. e( z6 E: O* a- d
  99.    <font color="rgb(86, 156, 214)">switch</font> (ch)
    # V, J% R  G  a
  100.    {) U7 f! i) [5 }1 y+ X% T+ L
  101.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:
    : c7 G: H' e) ~' V- B- E
  102.        HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);
    " i6 {! w4 [+ ?8 ], _, N. \
  103.        <font color="rgb(86, 156, 214)">break</font>;1 @% Q2 a0 k- H+ ~" i, `4 H" x
  104.        ' R" L! d  V2 d0 N: j: I
  105.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:4 |) r! {* I" P- \( U, ]
  106.        HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);
    4 Y! G1 j9 E: t, z% r/ |; f* L4 n
  107.        <font color="rgb(86, 156, 214)">break</font>;* C# U( ?8 N) t1 W) L
  108.       
    $ q/ _; x" ?0 ~4 J3 p! @& [
  109.      <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
    & N. B9 W" ^7 ^7 \6 x, }
  110.        HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);
    - |9 K( |2 M7 ^6 X1 Z
  111.        <font color="rgb(86, 156, 214)">break</font>;      
    & R9 Q+ B! a4 q, S0 g( Z
  112.      $ c# @- p; x. V$ \; ^4 n
  113.      <font color="rgb(86, 156, 214)">default</font>:( ]2 w* }) W' _3 N- r* d" U
  114.        <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
    1 g/ j% _, [% a+ F8 d
  115.    }
      I6 W# Z! l' C8 {- r4 x2 T5 h
  116.    <font color="rgb(86, 156, 214)">return</font> HAL_OK;
    2 A' a; M9 i1 h% u, a4 w7 X
  117. }
    5 X. H1 ]& s% S  y& {1 t" h" e
  118. 0 ^) d# B/ {: Q* }3 o8 t/ D. r
  119. HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,7 c6 I6 d3 [+ x! ~5 N. x% b
  120.                     SPI_HandleTypeDef *hspi,
    ! l7 @& A1 {, M
  121.                     uint8_t *pTxData,
    , C; P  B& @; @$ z5 v6 X" c
  122.                     uint8_t *pRxData,
    7 o( C- C2 V6 _, v) Z$ R: {1 [  [9 V
  123.                     uint16_t Size,/ e4 c- \% Q5 A6 [
  124.                     uint32_t Timeout): G! G% Q" u/ J8 {# W
  125. {
    - |" c0 R2 V* H4 {
  126.    HAL_StatusTypeDef ret; # w: _. e1 T& g" t+ n
  127.    <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST), M' k* S$ q% m/ |) j6 f* w
  128.      <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;  
    / X$ L9 p! t* Y  X
  129.    
    & l/ Z6 K  K% x) J3 a0 f" g$ b
  130.    SPI_Select(ch);& C7 x1 z* @0 Y2 T
  131.    ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);: g  b2 e) K0 Z" D& }
  132.    SPI_DeSelect(ch);6 ?1 f  n/ |9 _7 k+ }+ z
  133.    
    + n% ?6 l. v' {1 k
  134.    <font color="rgb(86, 156, 214)">return</font> ret;
    $ L* g0 x1 D& O, [
  135. }
    ; e- ~1 v' |# a3 g+ r4 e% r% F& w! Z

  136. 5 ], x2 Z5 S/ z" N& ^
  137. HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,0 n5 l& o" L7 q; m% L+ A$ h
  138.                  SPI_HandleTypeDef *hspi,
    # X: v" C( M! V$ \8 `
  139.                  uint8_t *pData,
    2 K( P( }% T. L& F- n4 I
  140.                  uint16_t Size,
    $ `6 t  }& o2 Z* o& N3 B
  141.                  uint32_t Timeout)
    . j3 U# d9 J8 J
  142. {1 s) O0 ]) Y1 H# J# K
  143.    HAL_StatusTypeDef ret; 4 G4 P* L$ @: I8 ?
  144.    <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)0 c2 r( d" S+ {. C# W: j
  145.      <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;  
    ; L9 a/ w" A, |8 Q9 h' j
  146.     : K) T- e2 B* u3 ^9 D6 d
  147.    SPI_Select(ch);
    9 ]' x! a( M; x: H3 L
  148.    ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);: p9 v) ?1 W) ]/ s7 h, i; v
  149.    SPI_DeSelect(ch);; _: P( v: l6 S8 k% x
  150.    
    3 @4 L; L# T$ ~0 W
  151.    <font color="rgb(86, 156, 214)">return</font> ret;  
    ' h. L; r4 k/ k4 W9 [
  152. }</font></font>
复制代码

7 S. r" W# ^5 K( a: P% {

如此一来,一个SPI外设就可以控制多个从芯片了。你如果有兴趣,不妨照这个思路试试看


  r) M% t' l- [4 T( N8 E' Q( U5 J* [2 u, {, Y  l" l
收藏 评论0 发布时间:2022-6-23 21:00

举报

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