之前用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
$ `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
: 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片选从芯片即可。 上代码看看: - <font face="Tahoma"><font size="3">void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi). D, Y% G5 e5 i6 d' }
- {
- X$ x5 e5 z4 ^. F" k4 u$ {* V6 J - GPIO_InitTypeDef GPIO_InitStruct = {<font color="rgb(184, 215, 163)">0</font>};
) f, d- }0 W3 q - <font color="rgb(86, 156, 214)">if</font>(hspi->Instance==SPI1)
9 c8 h+ \) _8 T% D4 Q4 q( a m7 _ - {
/ B9 @5 a: r7 X* _) P - __HAL_RCC_SPI1_CLK_ENABLE();
, X7 z7 O+ g( x } - __HAL_RCC_GPIOA_CLK_ENABLE();: r8 j0 o) C& B% }
- <font color="rgb(87, 166, 74)"><i>/**SPI1 GPIO Configuration) m( s/ N; n4 U7 l
- PA5 ------> SPI1_SCK3 Y7 u @# u8 d0 w9 [9 O$ i
- PA6 ------> SPI1_MISO
9 l) J& P: k- s# L) B6 ^ - PA7 ------> SPI1_MOSI) Y( e/ |& s& {( N+ @6 }
- PA15 ------> SPI1_NSS 但是这里不用
+ T. s3 g3 x b8 f) D l5 ]$ o+ Y - */</i></font>
. G! y+ F/ C6 U" z3 F8 M - GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;2 x) M y# P- B: }4 y' s
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;2 y- B7 ~5 A1 t" x: v7 ? p0 V
- GPIO_InitStruct.Pull = GPIO_NOPULL;9 a5 `, @" _$ r+ e: b
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;9 D5 Y+ {! b/ s. v3 L
- GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
& C7 G# h+ ?- z7 u - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
: ^5 D6 Q6 L- k/ V2 \* [* R; r( O - 6 ?7 c2 M3 q4 N) z" W
- /*__HAL_RCC_GPIOC_CLK_ENABLE();
4 E7 f& s9 T2 O! _' {5 K* Y8 t3 ?; O* M - GPIO_InitStruct.Pin = GPIO_PIN_1;
+ n# W" {/ v! H( t( Z - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; E T# d$ P6 g# N) N7 @
- GPIO_InitStruct.Pull = GPIO_NOPULL;) s) V2 }' i* N4 Q
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
* [; A# b0 a, v' @ @ - GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;6 b- |5 A5 g' q+ u: Q* @3 r6 z9 U
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/
. R! z2 \2 j9 m; K1 G& u2 { - }' B# T8 O F; g$ Z
- }) {7 q2 k4 E+ N7 I+ n$ f4 L1 T* l8 L
- </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/ _. |
- <font color="rgb(155, 155, 155)">#define SPI_CS1_PORT GPIOC</font>
0 E/ L0 k/ _1 R7 p, W - <font color="rgb(155, 155, 155)">#define SPI_CS2 GPIO_PIN_2</font>
- M4 B+ ]2 G i/ K6 i$ |) d - <font color="rgb(155, 155, 155)">#define SPI_CS2_PORT GPIOC</font>9 V& h" k9 U9 ^& W- R
- <font color="rgb(155, 155, 155)">#define SPI_CS3 GPIO_PIN_3</font>
; T4 Y) @' p( i( v1 R - <font color="rgb(155, 155, 155)">#define SPI_CS3_PORT GPIOC</font>
6 a' M+ I# N* a+ e - static void init_spi(SPI_HandleTypeDef * spi_handle)
* i& O3 a1 n1 j - {, K1 P8 X& U$ R8 A9 _
- <font color="rgb(87, 166, 74)"><i>/* SPI1 parameter configuration*/</i></font>
* j) R- O5 C4 ~. \. \ q. K - spi_handle->Instance = SPI1;
0 ^* q7 h: a$ e - spi_handle->Init.Mode = SPI_MODE_MASTER; b3 q% v4 z! h
- spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
) x$ C7 t/ J) ` - spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
9 v, K! Z( L! N# K - spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
. y, a+ b) Y0 v9 |, _9 P - spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;
! X/ [4 s4 G$ A0 z0 X% F6 E, a - spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;/ X9 d3 o/ k- \
- spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
1 |" ^7 v" p! T7 u+ D% z - spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
# L0 f' V0 X# g V9 B - spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;, y6 |$ E6 m# M/ }8 }3 W
- spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
% m4 Q) j' W+ O j) {3 c - spi_handle->Init.CRCPolynomial = <font color="rgb(184, 215, 163)">10</font>;& u- k3 z$ P" M$ P F* k0 j. K
- ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);' _9 W6 q# t* W3 l. ^
4 S( I, P6 V1 A% [+ v* R, N- GPIO_InitTypeDef GPIO_InitStructure;5 g7 b- J K% t6 x8 H/ V
- 6 L- p5 U" X+ B/ Q; k U
- __HAL_RCC_GPIOC_CLK_ENABLE();0 ^- b% k! }/ f' q1 U% o
- ' m" \6 p; o5 q% g1 v+ ^3 l
- GPIO_InitStructure.Pin = SPI_CS1;# o. b& v1 g$ ], ?
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
6 t8 q- `. i3 Q/ N - GPIO_InitStructure.Pull = GPIO_NOPULL;0 l5 u& L( v! X6 [
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;! w$ R8 [6 R9 Y" _, ]
- HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure);
4 A7 b3 n2 d# |& x' l; Y -
; b$ S" J$ R! }& O d$ G/ a; v0 L - GPIO_InitStructure.Pin = SPI_CS2;6 A9 Z1 q9 E. H5 w, [
- HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);
) Z- J" h& X9 D& i- l, { - ' m! j) l8 \% i' W% f% S T* p q
- GPIO_InitStructure.Pin = SPI_CS3;
( F2 j, h0 a; R' G" w1 C. Q. D2 N! @ - HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure);
7 f+ l3 B' J* {$ N8 H7 P$ y2 p a7 V - }
- S6 x( u% ^& e0 z - </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 }
- {
" {0 [4 T& S& O$ k/ h2 Y8 ] - SPI_CH_1=<font color="rgb(184, 215, 163)">0</font>,) G% P2 E6 L& R
- SPI_CH_2,
# m+ [1 ^; C, I+ @7 B0 I, h - SPI_CH_3,3 v( H+ Y" |$ u0 o# s. I3 N
- SPI_CH_LAST,
9 w' X% T" ^1 q3 V - } SPI_CH;' t6 f% [ s8 u3 a0 \# w
- static HAL_StatusTypeDef SPI_Select(SPI_CH ch)
k- v X0 I( @5 p - {
# x" Q w8 j% ]. A6 w - <font color="rgb(86, 156, 214)">switch</font> (ch)4 }3 v4 U$ }1 l' k1 A
- {
- D: s5 b: T) d9 Q1 S9 A - <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:* ~5 q" J9 }! Z" \
- HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);
, n, j% Z# b; j5 `. H - <font color="rgb(86, 156, 214)">break</font>;; I4 [1 Q) i4 d% x% ^
-
* R2 W2 h) d3 t `' A, @" F0 W - <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
5 Z* B5 x( L6 [2 h! E$ t( o - HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);$ V; Q" `% z. j( [2 K; s6 T+ k
- <font color="rgb(86, 156, 214)">break</font>;
& C2 I. f; f- |3 C0 D1 ]2 k - * l2 A K' |, M4 k5 z
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:! a7 O9 f( U7 Q" y1 p
- HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);
5 X* |5 r0 Z5 K - <font color="rgb(86, 156, 214)">break</font>;
: K+ N+ b1 M$ G7 s' }6 ] - 9 Q( o R$ y! U0 E: b/ o( D
- <font color="rgb(86, 156, 214)">default</font>:
6 w/ j6 L8 ?: y) t) t+ B - <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;9 Q( s* N; F, f( n; M
- } . `& a; D; F6 E/ o
- <font color="rgb(86, 156, 214)">return</font> HAL_OK;
1 h& e6 N' q( x( e - }
* P" j8 x% M+ S - static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)5 P; a7 N' J, I1 B( i$ ^
- {# u: ~1 e$ |' {. e( z6 E: O* a- d
- <font color="rgb(86, 156, 214)">switch</font> (ch)
# V, J% R G a - {) U7 f! i) [5 }1 y+ X% T+ L
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:
: c7 G: H' e) ~' V- B- E - HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);
" i6 {! w4 [+ ?8 ], _, N. \ - <font color="rgb(86, 156, 214)">break</font>;1 @% Q2 a0 k- H+ ~" i, `4 H" x
- ' R" L! d V2 d0 N: j: I
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:4 |) r! {* I" P- \( U, ]
- HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);
4 Y! G1 j9 E: t, z% r/ |; f* L4 n - <font color="rgb(86, 156, 214)">break</font>;* C# U( ?8 N) t1 W) L
-
$ q/ _; x" ?0 ~4 J3 p! @& [ - <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
& N. B9 W" ^7 ^7 \6 x, } - HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);
- |9 K( |2 M7 ^6 X1 Z - <font color="rgb(86, 156, 214)">break</font>;
& R9 Q+ B! a4 q, S0 g( Z - $ c# @- p; x. V$ \; ^4 n
- <font color="rgb(86, 156, 214)">default</font>:( ]2 w* }) W' _3 N- r* d" U
- <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
1 g/ j% _, [% a+ F8 d - }
I6 W# Z! l' C8 {- r4 x2 T5 h - <font color="rgb(86, 156, 214)">return</font> HAL_OK;
2 A' a; M9 i1 h% u, a4 w7 X - }
5 X. H1 ]& s% S y& {1 t" h" e - 0 ^) d# B/ {: Q* }3 o8 t/ D. r
- HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,7 c6 I6 d3 [+ x! ~5 N. x% b
- SPI_HandleTypeDef *hspi,
! l7 @& A1 {, M - uint8_t *pTxData,
, C; P B& @; @$ z5 v6 X" c - uint8_t *pRxData,
7 o( C- C2 V6 _, v) Z$ R: {1 [ [9 V - uint16_t Size,/ e4 c- \% Q5 A6 [
- uint32_t Timeout): G! G% Q" u/ J8 {# W
- {
- |" c0 R2 V* H4 { - HAL_StatusTypeDef ret; # w: _. e1 T& g" t+ n
- <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST), M' k* S$ q% m/ |) j6 f* w
- <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
/ X$ L9 p! t* Y X -
& l/ Z6 K K% x) J3 a0 f" g$ b - SPI_Select(ch);& C7 x1 z* @0 Y2 T
- ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);: g b2 e) K0 Z" D& }
- SPI_DeSelect(ch);6 ?1 f n/ |9 _7 k+ }+ z
-
+ n% ?6 l. v' {1 k - <font color="rgb(86, 156, 214)">return</font> ret;
$ L* g0 x1 D& O, [ - }
; e- ~1 v' |# a3 g+ r4 e% r% F& w! Z
5 ], x2 Z5 S/ z" N& ^- HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,0 n5 l& o" L7 q; m% L+ A$ h
- SPI_HandleTypeDef *hspi,
# X: v" C( M! V$ \8 ` - uint8_t *pData,
2 K( P( }% T. L& F- n4 I - uint16_t Size,
$ `6 t }& o2 Z* o& N3 B - uint32_t Timeout)
. j3 U# d9 J8 J - {1 s) O0 ]) Y1 H# J# K
- HAL_StatusTypeDef ret; 4 G4 P* L$ @: I8 ?
- <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)0 c2 r( d" S+ {. C# W: j
- <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
; L9 a/ w" A, |8 Q9 h' j - : K) T- e2 B* u3 ^9 D6 d
- SPI_Select(ch);
9 ]' x! a( M; x: H3 L - ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);: p9 v) ?1 W) ]/ s7 h, i; v
- SPI_DeSelect(ch);; _: P( v: l6 S8 k% x
-
3 @4 L; L# T$ ~0 W - <font color="rgb(86, 156, 214)">return</font> ret;
' h. L; r4 k/ k4 W9 [ - }</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
|