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

【经验分享】STM32F7实现SPI读写,读取W25Q16型号

[复制链接]
STMCU小助手 发布时间:2021-12-12 21:44
SPI协议的原理,网上大把的资料可以找到,这里记录一下SPI的初始化过程,以即以读取W25Q16型号为例的一个简单的SPI读写过程。% @  ~( D) p* X  C1 L" O. F( U
CubeMX配置:8 }$ y7 y% d9 d8 e8 H9 h

& X1 U* ]% F& b3 H: x2 X
20200423110312574.png

( t! @+ E; T; V  ~  ^( R- U; h! [  [# }1 |- i
SPI模式
; c( ^1 p, w4 T! L有只发送、只接收、半双工和全双工模式;
' P- L7 h1 F& t9 x根据自己的需求,和SPI设备支持的类型,这里选择全双工的SPI;
1 K: w; e- `# s% a. H( W% v! X/ E  I( Q( k) {3 ~! k
片选信号
# c" r2 w' A* Z! P3 e因为我们这个SPI总线上会挂载多个从设备,而且只有一个主机,所以,这里禁用硬件片选,程序里面读写之前使用软件进行片选;
& X  A, p) B/ }% q/ P3 o' I
; x* M' z4 }  p$ Q- M6 t帧格式
2 K# i! O4 Y/ K: W3 M  J% Z这里选择Motorola帧格式;
: k" H3 L& G  ~选择TI格式不能设置CPOL和CPHA,而且必须要开启硬件NSS这里才能选择TI模式。* E# }2 @' M- g9 I7 K
博主在网上搜了一些关于TI的SSP协议相关的资料,只有简简单单的一句:SSP总线兼容SPI,SSI 和Microwire 总线的接口。
6 D  S& Z  h) a6 j2 B# ~博主又搜了以下Microwire协议,和SPI一样,只不过片选信号是高电平有效。
- i6 x$ ^+ S# {% b- {这是手册里关于TI模式的说明部分和波形图:
8 x' F$ s1 y' J  Z! h9 y- ]. h9 H, q# H( I1 \3 i; U
20200423112839303.png
; m! {1 d! i" Q  t! @7 u8 D

' r. H" U3 b* ]" @7 A! B2 n
20200423112906213.png
7 d$ A, B' p& v# U8 S; U7 h

, j) H& j1 j) a4 ^) {# }% z也不清楚这个SCK的触发信号是干嘛的,所以这里老老实实选择Motorola就行了。
$ ?5 l& ?2 Q- _+ k6 f" i% ~4 D1 O; ^: {; p+ b
数据长度
: T3 a9 L# Z4 O1 ]4 b4-16bit可选,根据实际,选择8bit;
; B( _0 {/ ]/ }; ^  l1 L7 u, k  ]0 D) r
数据传输模式( ~; V" p5 W- }9 J4 O
第一个传输的bit是高位还是低位,这里根据设备来选择,好像MSB(先发送高位)的比较多,注意这里的会同时设置发送和接收,如果设置错了,发送的指令对方就无法识别,可能收到的就是0xFF这种值。
" A/ v; r2 }: p! O0 s  W8 e  r1 D  G
SPI速率& u& p/ Z0 M6 Q0 G4 T
SPI的波特率是由时钟分频得到的,CubeMX很方便的还帮我们计算出来了时钟速率,可以根据自己的需求设置。
" h9 c/ {9 X2 h% I) i) V
  W5 C% j/ {3 o& K" o时钟极性和时钟相位/ f3 \: L$ a( ?( y8 O: E1 |9 k
根据极性和相位的不同,可以有4种不同的工作模式,这个根据芯片手册支持的模式选择,注意,一条总线上尽量挂载支持相通模式的设备,这样就不用每次在设备切换之前重新配置SPI外设。6 N6 C  s% p! W( |. \3 B  Z' @  O

+ n& ?8 P* Y  p1 O& y8 K9 ]CRC校验6 @- Y- ^- z2 U
暂时还没研究到这里……
/ e+ p% c# h$ c( ~  |8 K8 L0 F0 @" A" a7 X1 v, [. T
NSS脉冲
8 E% ?$ |& l+ R3 E7 l) u6 i9 T
参考SPI的NSS 脉冲模式的作用,这里用不到;% @7 R4 M4 `! Q6 B5 _; Q

9 _1 J4 t9 S2 V: JNSS信号类型

  a& Z3 B5 |3 `) ]5 R因为前面禁用了硬件片选,所以这里只能设置位软件模式。7 A) h7 V7 J/ l8 _  j$ M- R5 g

5 e0 e/ w# b: w2 M除此意外,还需要把连接硬件片选信号的GPIO,设置为输出模式。% |8 V6 m7 H* v5 |
CubeMX生成的代码如下:" Y& Q9 c* T# c0 N
4 B1 I1 q7 d+ M, M
  1. SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄0 L  i) O/ v# ]9 K' v, }1 g& z
  2. . j" W6 G/ \6 e3 b" B
  3. void SPI3_Init(void), `+ [6 Y- g8 W: V
  4. {: ^, N; |" F. ]; }. @5 k+ a
  5.     SPI3_Handler.Instance = SPI3;, b, v0 S! J$ d
  6.     SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
    ! s' _. P1 v. [9 V6 s! W
  7.     SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
    3 A+ U' z! Z4 [& ?( [6 Q" e
  8.     SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;0 g# ]3 O. `* Q# l
  9.     SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;1 B: d& S$ v4 _, \: A- q) N
  10.     SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
    6 j7 [' H8 s- Y$ T) k7 B
  11.     SPI3_Handler.Init.NSS = SPI_NSS_SOFT;5 U/ p) N2 u9 A, P& e5 V! s
  12.     SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;, C* D! U8 d/ |% F5 Z
  13.     SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;; M. i9 A- C! |* U3 V
  14.     SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;6 _$ v% e4 d8 D9 x& j5 \9 @
  15.     SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    ! w0 w- x9 M! J) ?6 @" S
  16.     SPI3_Handler.Init.CRCPolynomial = 7;
    3 D8 ~* ^) U  f( [3 o
  17.     SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;( D7 [! U) |( l- w
  18.     SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;$ e( ?; K& u; B5 f( Z) C6 @
  19.     HAL_SPI_Init(&SPI3_Handler);9 }( h+ p: A- S8 N

  20. 3 P& N6 d/ i; H& r- o( v
  21.     __HAL_SPI_ENABLE(&SPI3_Handler);               # m0 W5 U: C- U1 k4 D
  22. }( R& p% @  L) y4 {* t
  23. ( a4 x& n4 i2 I* i0 w
  24. void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
    # m+ f/ P9 P0 k
  25. {1 g7 U0 S3 G. g! k1 h" J
  26.   GPIO_InitTypeDef GPIO_InitStruct = {0};& C5 s7 C& q- }( u% [1 {7 Q6 D
  27.   if(hspi->Instance==SPI3)' w- k8 Z" _% f  |
  28.   {5 t* f1 y8 r% _

  29.   ~) A6 R6 G( A. m/ S% k
  30.     __HAL_RCC_SPI3_CLK_ENABLE();
    / c2 b- J6 C  H2 E
  31. ) d# U' l6 W# X2 Z. f
  32.     __HAL_RCC_GPIOB_CLK_ENABLE();! U( B+ S) a- ?# p
  33. 2 ~& V& G" K" y
  34.     GPIO_InitStruct.Pin = GPIO_PIN_2;& ^# G% J1 y, |1 @) U. }+ u
  35.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    + r( W- A6 l, n
  36.     GPIO_InitStruct.Pull = GPIO_NOPULL;. m: m5 p# h9 j  i& W* c
  37.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;. K2 |9 k( Z: A1 b$ O7 X2 `
  38.     GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;$ b, @2 p. F3 z9 c/ H+ v
  39.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    5 ?2 y: d/ s6 c
  40. / d  I4 Y" j/ y* S
  41.     GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
    : h, e* s2 N% B" f% Z- }
  42.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;$ o4 C, a1 ?7 @2 E0 N3 L
  43.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    - d8 Y! E1 `- J" O! V8 z
  44.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;, I+ [; H! y% n0 ^1 `" r
  45.     GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    ( j  B* v& g" x7 T! ]
  46.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);, k( h/ Q% H$ H, R2 L0 F
  47.   }
    8 y  f8 e$ ?. k
  48. }
    / D/ h2 d& g2 q8 X/ Z' r

  49. , K7 `. m8 Q( R1 e7 ~/ d( M

  50. ! `" ~3 f* ]. G' e
  51. static void MX_GPIO_Init(void)
    4 t1 P1 m4 I9 c0 f+ m& }, y# X9 Q
  52. {
    5 k7 D% [$ J: |: R3 e, c
  53.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    9 R3 i% w8 H, Z! t9 T2 u- f

  54. 4 l2 w' b* v- ^9 |% \
  55.   /* GPIO Ports Clock Enable */
    , B# Z- G; i/ }/ T+ Z
  56.   __HAL_RCC_GPIOA_CLK_ENABLE();
    1 v* Z, Q4 |1 T4 v
  57. $ s: B1 w% z5 a* A  O' D4 D3 V' M
  58.   /*Configure GPIO pin Output Level */
    + c( x. q, [+ ]4 H/ i9 R& `
  59.   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    7 g8 p- x# }8 K3 T4 D6 @* R( U& _

  60. : s* @( P  }* x6 \3 `
  61.   /*Configure GPIO pin : PA4 */( B/ j2 D6 r+ r: M" Q. U0 [
  62.   GPIO_InitStruct.Pin = GPIO_PIN_4;; V& }  h- `2 p
  63.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;* k; }7 o. e; W1 D) d/ I' {" K7 r
  64.   GPIO_InitStruct.Pull = GPIO_NOPULL;+ j; Z. W: ^% l+ s4 ]# I# @, R+ M
  65.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    % q% o5 x0 X* H/ Z: t
  66.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    : ?) r: f4 B3 m  L5 X

  67. % q: c& I& F3 h& L; C1 V7 _3 _
  68. }
复制代码

: l( l% H. u; p# r' d# Q# J同一总线上不同设备,工作在不同模式的时候,速率可能不一样,需要一个重新设置速率的函数:) U! f3 g% o+ ]+ w9 R% A. z, ^

8 u' y- ]2 C' [4 _
  1. void SPI3_SetSpeed(u8 SPI_BaudRatePrescaler)* ?) S/ a& e" [' D6 }
  2. {2 ]/ }% f1 p/ W2 R- s8 A& L
  3.     assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
    6 z3 j! A( q/ [+ B( _9 Z
  4.     __HAL_SPI_DISABLE(&SPI3_Handler);            //关闭SPI' T  n  ~1 F# H( d+ A
  5.     SPI3_Handler.Instance->CR1 &= 0XFFC7;        //位3-5清零,用来设置波特率
    : t' ~7 e* P6 g0 e; J
  6.     SPI3_Handler.Instance->CR1 |= SPI_BaudRatePrescaler; //设置SPI速度
    2 e* o8 f% s* b) f' \7 `
  7.     __HAL_SPI_ENABLE(&SPI3_Handler);             //使能SPI: b  D. w( M& R6 r* E& |/ c3 V: I  C3 _
  8. / B  i" C- a' |+ z7 j2 ]( C
  9. }
复制代码

- n' a8 ?8 D7 l1 ]; s因为全双工的读写是同时的,封装一个读写函数:
3 M3 q, c1 l% y8 R1 w4 ^" w+ Z
' w3 @/ d" x3 O9 C; V9 q
  1. //SPI2 读写一个字节) S- B7 f5 B( g4 i. ]# m. P
  2. //TxData:要写入的字节
    ) D4 c  m, ]# h' {; c
  3. //返回值:读取到的字节  s" [5 p- k1 n2 o# K% S
  4. u8 SPI3_ReadWriteByte(u8 TxData). D* j$ m/ [5 O: D2 g9 p& j
  5. {
    ' R  X) e; D3 _; W
  6.     u8 Rxdata;1 X( Z) r2 A& R
  7.     HAL_SPI_TransmitReceive(&SPI3_Handler, &TxData, &Rxdata, 1, 1000);
    8 @9 ?+ A6 G; T& V$ A( M
  8.     return Rxdata;                      //返回收到的数据" h, [: x% x  M
  9. }
复制代码

  `  ]# D! c$ p- n根据W25QXX的数据手册,写一个读ID的函数:
* z$ M2 ^" Q! c. L
  1. //读取芯片ID" T; F7 H7 T- @3 [, N) |1 t( P
  2. //返回值如下:                                   
    : k" y' @* y* {  \) ~) S7 N2 R, ^
  3. //0XEF13,表示芯片型号为W25Q80  
    1 W: I2 ^% e, J) G* r0 Q1 b
  4. //0XEF14,表示芯片型号为W25Q16    & X/ i- c' i) o# t* k0 T% V8 J% u
  5. //0XEF15,表示芯片型号为W25Q32  : G: S6 R/ ?1 Y7 N
  6. //0XEF16,表示芯片型号为W25Q64
    " p2 L8 x. h+ a8 S" w1 l
  7. //0XEF17,表示芯片型号为W25Q128           $ V$ [, @' E2 W  u2 \" w
  8. u16 W25QXX_ReadID(void)
    8 c: a3 }; S+ v( O7 m0 S1 C( F
  9. {
    9 ]4 }# n! f: f8 H& P9 F7 u. A# A
  10.         u16 Temp = 0;         
    ! \5 M- _: U5 Y4 g, H' q" i
  11.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);            $ p+ g3 w1 Y) Z- `2 g( }
  12.         SPI3_ReadWriteByte(0x90);//发送读取ID命令            
    4 b" B5 Q& W# M5 \; T) V! k% E$ I7 u
  13.         SPI3_ReadWriteByte(0x00);             + X$ g- F1 m& I
  14.         SPI3_ReadWriteByte(0x00);             1 |5 a* l4 @7 e- A6 Y
  15.         SPI3_ReadWriteByte(0x00);                                    
    4 w9 H( L, @, m& k9 h& l2 p+ S, H
  16.         Temp|=SPI3_ReadWriteByte(0xFF)<<8;  8 C  X0 l/ g; p8 a( ^
  17.         Temp|=SPI3_ReadWriteByte(0xFF);         : A$ I- d9 `" W2 c: O/ w& q9 m
  18.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  6 C! M* R9 H5 v% p
  19.         return Temp;% G- v. W' c- J
  20. }  
复制代码
2 j$ x- w- R% v
最后写一个在主函数中调用的接口函数。& p! d& W  J) |- k# _: n+ q% r

. Z0 |. N$ N5 S) P
  1. void W25QXX_Init(void), d4 i  q5 j/ G6 `; V
  2. {/ ?, h0 Y2 S- a) e$ m0 p# U# X3 w
  3.         MX_GPIO_Init();
    4 w* x& F- Q+ S, n$ p
  4.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
    , V9 f! S* v  ~
  5.         SPI3_Init();1 z8 b9 M# X$ [9 ]) m
  6.         SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);
    % p: q3 p. Y7 Y/ b) u
  7.         uint16_t W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.  
    * R6 R/ U# H5 L9 ?- N" f5 m( B
  8.         printf("W25QXX ID:0x%4x\r\n",W25QXX_TYPE);
    # N4 r# T! g$ d
  9. }
复制代码

7 ]. L+ K8 m( L8 p下载运行,读取到了芯片ID。
5 h2 w7 z2 A- u" o  \" p  Y; x' p( b
20200423121114508.png
5 T2 a' R* i) g
( B; U1 z4 @5 f. R
收藏 评论0 发布时间:2021-12-12 21:44

举报

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