|
之前用STM32的SPI需要控制很多外部芯片,可是一个SPI的外设只有一个片选,要实现独立片选一主多从,怎么实现呢? + j+ s# ^: F# d& b/ D: F
SPI总线拓扑一般地,SPI总线按照下图方式进行连接,一主多从。
0 B# u% T1 G! P* ?3 r2 b W& u& u/ l
* a# ~* j3 {( J- ?* i如上图: - 每个从设备都有独立的片选引脚,主机同一时间段内,与一个从设备进行通信,也即选中一个从设备。
- MOSI/MISO/SCLK并联在一起
- MISO须是三态门,当从设备未选中时,该脚须设置为高阻态,而不能是输出态,否则会影响总线!
- 对于MOSI/SCLK,虽然并联在一起,但是由于仅一个输出,多输入。
* F0 w3 m1 u, N6 J8 n+ J* | M
5 V! h# ~0 Z6 `! A9 x7 q
但是你看STM32的SPI外设,一个SPI仅有一个NSS信号,以STM32F407的SPI2为例:
/ U: Y) {% W! G" M, a2 k8 p% f那么要实现前面说的一主多从,怎么办呢?有朋友说,直接用GPIO去模拟不就可以了。 不错,SPI总线要用GPIO模拟还是很容易的,但是这样做波特率做不高,需要占用CPU时间,效率比较低!而用SPI外设控制器,底层bit流的收发由外设控制器实现,用GPIO模拟则需要CPU参与。
, |) q& z; N$ _) @7 U 怎么破呢?菊花链拓扑) {* N* T d, V' a) f
: ?) P# S$ |) g+ G4 Q, Q: n
# S; W9 N) L5 G+ ?1 |& L+ X, y
; L, Y' V+ t1 X' k" l5 i9 A
3 Z' s0 G. c& n这种方案,省引脚。但是要移位控制,相对独立片选效率还是低不少。 1 P9 W. |* v% a4 F1 N2 r
独立片选拓扑 SPI外设的MOSI、MISO、SCK还是照用不误,但是片选我们不用,设置成通用输出模式,再用其他的GPIO片选从芯片即可。 上代码看看: - <font face="Tahoma"><font size="3">void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
% l! \0 T7 h$ J1 D - {7 G+ y4 P5 g" N# I Q4 f
- GPIO_InitTypeDef GPIO_InitStruct = {<font color="rgb(184, 215, 163)">0</font>};. e! j, {2 @$ N3 k8 z
- <font color="rgb(86, 156, 214)">if</font>(hspi->Instance==SPI1)! ^) P- d0 s6 a. n" x
- {
0 U6 G5 _+ h( W8 b4 ?2 v$ w - __HAL_RCC_SPI1_CLK_ENABLE();
x* y1 n5 V# ^- U% g' b/ ^ - __HAL_RCC_GPIOA_CLK_ENABLE();
; k/ C+ h! ^! t% W: I - <font color="rgb(87, 166, 74)"><i>/**SPI1 GPIO Configuration
. q' x ~9 Y8 M$ J4 J* | - PA5 ------> SPI1_SCK
2 j1 j) x) E+ c5 ]/ I - PA6 ------> SPI1_MISO' D; F( n4 a/ r. ]/ s1 J) Y& V
- PA7 ------> SPI1_MOSI
- G+ C9 @; t, ]1 ^ - PA15 ------> SPI1_NSS 但是这里不用% f# H$ @1 c6 y$ i
- */</i></font>. m* m3 T$ t1 M
- GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
6 w6 J3 J% ]( a2 { - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;6 E7 j$ ?- l$ m2 |% d c5 m* z5 Q
- GPIO_InitStruct.Pull = GPIO_NOPULL;
2 `4 t' b. B) S# r - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
% L/ v0 } e8 k" h& D$ R/ y& I - GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;2 d. ]7 F* q* S5 Q( S
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
' O: O, _) O! y! K, J9 i' U5 y
9 U0 \9 F R4 X! w O+ L2 q- /*__HAL_RCC_GPIOC_CLK_ENABLE();
. D3 Q/ L! f7 @( x" G - GPIO_InitStruct.Pin = GPIO_PIN_1;
5 B0 _, d! w/ g) i( C* h - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
p/ [3 y, s- l; l8 S - GPIO_InitStruct.Pull = GPIO_NOPULL;
/ m0 |) b% T4 S: u# j - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;3 b+ L) c! s6 n% q
- GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;# }& ?3 [% m2 _) [
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/ 8 r3 D/ p7 @. c& z
- }* S, l8 Y; L; T' A, {, {% Z8 O
- }
% y5 n7 ]7 ?- o) i/ s, n0 W" ` - </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>
, K; U& R2 _; a; Y - <font color="rgb(155, 155, 155)">#define SPI_CS1_PORT GPIOC</font>
' d0 @" D, S9 h: w - <font color="rgb(155, 155, 155)">#define SPI_CS2 GPIO_PIN_2</font>; ~9 _4 U1 o) @& p. P( k$ `
- <font color="rgb(155, 155, 155)">#define SPI_CS2_PORT GPIOC</font>
e" D# P: s4 b+ b& M% T3 v- t4 T - <font color="rgb(155, 155, 155)">#define SPI_CS3 GPIO_PIN_3</font>( g" _; X+ P8 W% B5 J4 @
- <font color="rgb(155, 155, 155)">#define SPI_CS3_PORT GPIOC</font>* f( c3 Z! G- y' t+ v0 [7 }; u( n
- static void init_spi(SPI_HandleTypeDef * spi_handle)0 R2 ]; n1 b$ U( l4 S
- {2 L, r1 D! {9 l; L7 A
- <font color="rgb(87, 166, 74)"><i>/* SPI1 parameter configuration*/</i></font>
# y% Z% o6 u8 w+ |- Q2 R- M - spi_handle->Instance = SPI1;: E' i1 c! }2 _
- spi_handle->Init.Mode = SPI_MODE_MASTER;
& P2 D- x2 v5 F- h: q' I - spi_handle->Init.Direction = SPI_DIRECTION_2LINES;
/ j8 N% @* S. h2 w3 y8 P! p - spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;
2 s; }. f5 J- D8 _ ? - spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;
& }% B: @3 _) k' U - spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;) M6 n3 [; j! V: [6 B/ a$ A1 k
- spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;( N7 A- G* Q4 \9 j4 L: }) w* t; g
- spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
8 k. t8 v, P" J - spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
; g* B, v0 Q4 b/ \( s - spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;+ h! B& f' X- |2 q* b
- spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
% U5 T+ s* Z% M5 m) x) x - spi_handle->Init.CRCPolynomial = <font color="rgb(184, 215, 163)">10</font>;
: u5 Q: i# V0 v V7 H# Z, s; ~) m - ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);. M) c* s: A$ N# c. i; R
) [! e: r. Y1 [- GPIO_InitTypeDef GPIO_InitStructure;
# E! a$ h% h+ H* x9 {6 S
`% q3 |; z: p- __HAL_RCC_GPIOC_CLK_ENABLE();- O8 I& J' _1 g) m
7 N8 ~/ k1 I. z* C3 t6 _. c- GPIO_InitStructure.Pin = SPI_CS1;# P U1 p' P4 c% u$ v' L
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
! e9 g* P6 g" I2 o - GPIO_InitStructure.Pull = GPIO_NOPULL;" B; V+ q* Z X3 e" [5 y( ~
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;: i; C) n- y! ^
- HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure); . ?# e- S9 M6 W' \) Z: V
- ; T" _3 N$ j7 k0 Y
- GPIO_InitStructure.Pin = SPI_CS2;# T6 N1 W& Q" m6 P: y
- HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);
! I! q, s/ l0 t8 F) X( ]$ m5 T2 D -
! ]# O8 h1 i( K5 W( Q% I& ] - GPIO_InitStructure.Pin = SPI_CS3;
# f! i0 ]5 O) D- j. a - HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure); ' a1 d% E- `( `: a( }( K) q1 G
- }4 ~% v' i$ w) {2 G& w
- </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> - C# n* S& U! E/ p& x7 K5 b3 {* z3 H
- {
& R' D9 z6 d( F4 s) e - SPI_CH_1=<font color="rgb(184, 215, 163)">0</font>,
& s2 G( n" z/ q& j2 {8 C - SPI_CH_2,+ k% }2 F7 A' d! m
- SPI_CH_3,
: t( y( S2 y% M! o - SPI_CH_LAST,$ O; p9 j% {% s$ d$ Z% G# W; b0 E s
- } SPI_CH;
! F/ s: K) @0 z( |. p - static HAL_StatusTypeDef SPI_Select(SPI_CH ch)$ t3 u2 e$ Z; X; r1 Y$ x$ H
- {# g: V$ V5 m9 n9 W J6 R
- <font color="rgb(86, 156, 214)">switch</font> (ch)
: j0 n6 i/ O0 J* v* \5 `; I - {
% d9 Q4 s# a4 A - <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:; A' j% f; V7 h. R
- HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);! F& _7 N& U5 P7 j. J
- <font color="rgb(86, 156, 214)">break</font>;
! o! a9 k: o+ Q u g8 Q - 1 m) L5 n+ c' i
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
+ l/ k/ a: r' |+ p/ Z- p; c- E - HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);; z, `8 ?6 ^! v
- <font color="rgb(86, 156, 214)">break</font>;
- D) V2 e' B. U2 y) @4 l -
- [- Z. c& c1 W. ^# g. {; N" s! r - <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
& a. W6 ?8 J7 v# Y - HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);
- U8 z# ^! x2 {+ e1 @( ~6 ? - <font color="rgb(86, 156, 214)">break</font>; 5 J0 p. n) m9 g0 O5 p u! {3 C5 g
- + g2 B/ n: e, b
- <font color="rgb(86, 156, 214)">default</font>:0 N- E. b _6 a5 [3 d' e
- <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;! X6 ^+ ?( d; F9 E% |
- } 6 `. g3 }/ W# `8 R% I* w
- <font color="rgb(86, 156, 214)">return</font> HAL_OK;
, p7 S" Q# V4 y0 F- K7 C3 {' R - }
6 w9 O* J7 H7 O- f - static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)* @- H, x/ X+ z. f2 H
- {
- i0 ?3 v* V. C$ s - <font color="rgb(86, 156, 214)">switch</font> (ch)
6 _6 u4 B! ]5 W' T9 P - {6 H& }+ Y' ~( f
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_1:
1 w/ w- `! s& H2 R - HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);7 V1 \8 U( N$ E( F, M( s
- <font color="rgb(86, 156, 214)">break</font>;# z7 F" t" ~5 \. A- C; |# }
- d7 ?. t+ ~5 k; ]6 d( v
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_2:
2 W9 K; _" R1 U# @% Q+ I! o" \! O - HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);
1 _$ ?+ W1 \& v7 b' M - <font color="rgb(86, 156, 214)">break</font>;
3 i% b* [; ^7 U1 l& u - ! h& c/ b @+ ~% J, [& o
- <font color="rgb(86, 156, 214)">case</font> SPI_CH_3:
8 ~. c2 h$ i+ H8 s' { - HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);
& L* L% n* g- g$ ~( g3 N - <font color="rgb(86, 156, 214)">break</font>;
4 i* X. E0 ^; p0 H! e) `4 w - 9 L8 y% d& Q4 q' [+ `$ L& i( x6 \
- <font color="rgb(86, 156, 214)">default</font>:
b' c, ]! _- q x- p; M( ^) D - <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;) e; D6 Y8 }4 ` m. b" [
- }
0 X: o; J3 e' W: w# Q9 g - <font color="rgb(86, 156, 214)">return</font> HAL_OK;
- d" w! {& L6 L( M( L$ V' ~ - }. ^" S9 y0 u, U6 |. S
- 6 k7 q1 U# s. g- T5 J% o7 C
- HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,; i$ U" g n, e; R# W
- SPI_HandleTypeDef *hspi,
& S( r+ `; }; n" ]# G' a - uint8_t *pTxData, 9 Q8 {5 C8 G1 k" [" s" ~; g$ G
- uint8_t *pRxData, 7 a4 _ @7 C* D/ n3 s# G- m
- uint16_t Size,
; r' Y$ ^/ j {4 } - uint32_t Timeout)
, F+ i- V. G% j. ?2 o - {# d( X+ B# q2 e3 h; Q6 Y' f
- HAL_StatusTypeDef ret;
. V {- e3 K ^. [4 ?+ L. Q* R - <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)
* j6 s; f, x( c( _+ T$ m& b0 O - <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
, H' }9 h9 P* U. E" }# w1 W) w1 Z6 k- C8 g -
$ W: ?. i& s( d" m, z6 x( w A2 y3 Z - SPI_Select(ch);+ N, d3 v" F0 B+ N9 `6 f
- ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);
7 h \5 I4 t4 t, ~8 \ - SPI_DeSelect(ch);
# A0 Z9 y- n: U' ? -
5 r9 L8 n! w+ U2 v# K2 q - <font color="rgb(86, 156, 214)">return</font> ret;0 }4 s; ?1 w5 w* L# G" e
- }8 {' g8 t/ K# l! H
1 w) Y" H S; \3 U' N" Q, P- HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,
/ b% R4 X% N$ J/ J" Q M/ S* o - SPI_HandleTypeDef *hspi, ) _! ~( h* u) |
- uint8_t *pData, , U. r3 a z; O7 ^( D$ M! p# D
- uint16_t Size, 6 i) {& }# {4 S- P& o. F- m; O
- uint32_t Timeout)" d0 t8 U) s. U8 H+ Z0 l! Q3 ]
- {
* o$ L9 U% ~5 Q# [ - HAL_StatusTypeDef ret; / { b( C7 I7 ~, n2 o
- <font color="rgb(86, 156, 214)">if</font>(ch>=SPI_CH_LAST)
, x7 M5 T# X+ d; ^6 T - <font color="rgb(86, 156, 214)">return</font> HAL_ERROR;
# f8 M$ q f& a# z6 Z! `! g - 8 e/ n5 p: n) w8 r f" ]' W5 r
- SPI_Select(ch);
7 E1 X' M$ t6 X6 K* U) s8 O# z5 e - ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);5 }( M0 l. x, M
- SPI_DeSelect(ch);
( x, s: b9 N5 }! q" k1 ]" c& c - $ B3 G5 b0 B( ~; F
- <font color="rgb(86, 156, 214)">return</font> ret;
! l- m, I) E- Y- ]5 K - }</font></font>
复制代码
& x7 d5 m4 ^+ H6 B( `如此一来,一个SPI外设就可以控制多个从芯片了。你如果有兴趣,不妨照这个思路试试看 f9 k& t6 y1 } f. Q7 Y. h
8 j) H* B$ S* F( D' f; [6 b
|