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

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

[复制链接]
STMCU小助手 发布时间:2021-12-12 21:44
SPI协议的原理,网上大把的资料可以找到,这里记录一下SPI的初始化过程,以即以读取W25Q16型号为例的一个简单的SPI读写过程。8 G1 f' m0 k2 t) S+ W
CubeMX配置:+ N" n* X4 Y1 D. r* F

: b/ }5 u# R4 b
20200423110312574.png

6 N2 h- E+ D1 y3 o/ X$ N: d
) x% J/ t$ @9 V7 S0 DSPI模式# w9 ]  \; l" s! {+ }0 {
有只发送、只接收、半双工和全双工模式;
2 ~$ v& o3 u/ P" |1 y1 o. B/ E根据自己的需求,和SPI设备支持的类型,这里选择全双工的SPI;
5 Q0 U. Q* B' w' _9 B+ V. G7 _. [8 @: q4 i9 d8 Z
片选信号' f" x0 D& V' Q3 n: s1 |% n/ g2 R% |
因为我们这个SPI总线上会挂载多个从设备,而且只有一个主机,所以,这里禁用硬件片选,程序里面读写之前使用软件进行片选;
! ~/ v) ?& M+ q5 a6 i& M" T1 k3 w5 ]* s3 L/ m. ]; a# A' d" w
帧格式& S+ a& ]$ K- T: ]
这里选择Motorola帧格式;
0 g3 y: O) h/ u  A' a* c选择TI格式不能设置CPOL和CPHA,而且必须要开启硬件NSS这里才能选择TI模式。; ^' n) E2 i" W5 \+ ^1 K! _9 i
博主在网上搜了一些关于TI的SSP协议相关的资料,只有简简单单的一句:SSP总线兼容SPI,SSI 和Microwire 总线的接口。
7 B, e- }0 l' v0 _7 N" s3 j博主又搜了以下Microwire协议,和SPI一样,只不过片选信号是高电平有效。
6 _3 f9 ?# K' Q6 ~0 V: H+ U8 R这是手册里关于TI模式的说明部分和波形图:$ C7 ^) O5 b/ U
$ A# Y, E& L, b, C6 p
20200423112839303.png
* D0 x/ Q% K8 `5 Q% q
; e, S5 j; J- O8 Q6 O
20200423112906213.png
/ M: Q, F, r5 s0 j8 e: ]( e  F
& j5 i' G' S, }8 B+ [. }
也不清楚这个SCK的触发信号是干嘛的,所以这里老老实实选择Motorola就行了。9 r3 j( N6 C6 A$ \$ a

  Y, e9 J2 I. P; N数据长度
5 a. `3 m4 p, t0 p1 y4 p% Q4-16bit可选,根据实际,选择8bit;
: a9 |2 b% c1 m5 {4 I/ G$ n3 e1 M* A* h" I9 L- d
数据传输模式  @6 I  e- h3 |! R4 d
第一个传输的bit是高位还是低位,这里根据设备来选择,好像MSB(先发送高位)的比较多,注意这里的会同时设置发送和接收,如果设置错了,发送的指令对方就无法识别,可能收到的就是0xFF这种值。
  L9 Y- D: q* A( ~. M0 M" R3 h2 b. Y* C: E0 {0 T' X1 g/ q
SPI速率5 ^, f2 T% Z7 X7 n
SPI的波特率是由时钟分频得到的,CubeMX很方便的还帮我们计算出来了时钟速率,可以根据自己的需求设置。
6 [) e# e  k: i) j8 X9 |, P3 \; @+ @  ^# p8 G! e
时钟极性和时钟相位
" T  A# y9 I& w2 i* C9 F根据极性和相位的不同,可以有4种不同的工作模式,这个根据芯片手册支持的模式选择,注意,一条总线上尽量挂载支持相通模式的设备,这样就不用每次在设备切换之前重新配置SPI外设。9 C: q2 ?0 j' T3 ]0 y' z3 a
1 T1 h* j0 Q" j. Z" q' @" p# h/ {
CRC校验
2 p2 m" L+ c) J8 }3 |暂时还没研究到这里……
" `1 v, L) R' Y  I! k
4 {# B8 G- B# P$ \0 L- C9 x: p; pNSS脉冲
$ |# ]1 y& Z  g) w- B8 A9 r
参考SPI的NSS 脉冲模式的作用,这里用不到;
4 J0 |( s9 m. ]% f( a/ T' |% P2 O3 J* a5 ~
NSS信号类型
' W; {% F+ `& @2 A% o
因为前面禁用了硬件片选,所以这里只能设置位软件模式。8 R+ Y. D* k' ~( V& ^
/ G/ {" f! L! N9 Q
除此意外,还需要把连接硬件片选信号的GPIO,设置为输出模式。, q4 v/ Q% L. S; m" D
CubeMX生成的代码如下:, j1 P: ]! [7 R
4 i% A; o- H. [
  1. SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄
    * t4 G+ H* Y, k3 k

  2. & Z) S9 d8 Z* E) D/ b
  3. void SPI3_Init(void)
    ' p8 F) I/ V% G/ X0 s# m7 O) J
  4. {
    6 p& G% P! K5 X9 w" Q, c
  5.     SPI3_Handler.Instance = SPI3;
    2 p6 X4 z# b* G
  6.     SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
    # ?  m2 I. c+ l0 ?
  7.     SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
    $ _0 O6 X4 A* ~* A7 Y! b
  8.     SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;$ f" Y( [2 b. E; J4 c" n
  9.     SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;& f+ Q0 l! c8 C3 k$ P- I
  10.     SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;9 _6 {5 _) l6 U: I9 u, B5 V
  11.     SPI3_Handler.Init.NSS = SPI_NSS_SOFT;' u3 K( ~- U8 _
  12.     SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;5 e2 k4 c6 J/ G4 a/ k8 _/ B% {
  13.     SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
    - S9 ?& x( ?" C/ q
  14.     SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
    ) r% I& ~2 Z/ M+ c; ^* ]
  15.     SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    9 _  {$ D. u# K# f) T4 s
  16.     SPI3_Handler.Init.CRCPolynomial = 7;8 {3 l' _) F: c7 N
  17.     SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;8 n8 V7 t5 {! b! `- u* \
  18.     SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    & ]# q% A+ \) G# n0 \, l* y8 x, K
  19.     HAL_SPI_Init(&SPI3_Handler);
    & x6 p9 ^+ I' _& t

  20. , |$ {4 T" v2 w1 u  s% t5 F
  21.     __HAL_SPI_ENABLE(&SPI3_Handler);               
    : F1 a/ x( n, q6 V, k; g
  22. }
    % S0 C2 O7 I5 M5 h. a

  23. # |7 Y& ?# t$ c- b
  24. void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
    3 e+ C0 W8 z- D+ |7 V
  25. {
    * C4 }3 o; B2 y' C2 N
  26.   GPIO_InitTypeDef GPIO_InitStruct = {0};& ?) ^- ~% T7 Y+ N
  27.   if(hspi->Instance==SPI3)
    ( k$ _; `0 A4 F; l* P
  28.   {, h. z- R5 y7 L! d

  29. - `% W' H8 X( X% p& h/ W
  30.     __HAL_RCC_SPI3_CLK_ENABLE();
    6 X# {% J$ R- l9 z2 d0 s% d

  31. ' Q, ^, ]6 ?+ I0 z. Q. `7 L# e" M
  32.     __HAL_RCC_GPIOB_CLK_ENABLE();# k8 |  R5 S# m6 d8 k
  33. 0 c9 H% e1 |, T: Q( W; t" k
  34.     GPIO_InitStruct.Pin = GPIO_PIN_2;1 ^( `2 S( }& s! I
  35.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;( u' G4 f. j  e$ V
  36.     GPIO_InitStruct.Pull = GPIO_NOPULL;- z1 K! v- v7 U
  37.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;2 C3 o) L: N8 L
  38.     GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;
    ) c: Z0 @# j  G: ]/ l! L3 H: Y
  39.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    8 H: Y& b! V4 W' S
  40. , _! M' N6 @. L8 w2 B9 Z6 q3 M' a" ^
  41.     GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;5 D' D' C% N3 D. w; F& v
  42.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;/ h0 G8 l# R0 i: `5 G9 z8 \
  43.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    4 l+ K7 c/ x& j. E& i, Y
  44.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;: g; G8 @4 O1 t. x+ q+ w4 u
  45.     GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;, d2 G; e4 M7 `
  46.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    & C8 J. K$ g$ b7 R
  47.   }
    ; H6 g6 a% n9 F% g
  48. }+ i) ^8 A$ w! d) C- ~  C
  49. $ [; }3 ?* k9 ?7 V

  50. 1 ]2 _* O" e' L. x7 ^
  51. static void MX_GPIO_Init(void)( O7 `; ~9 P4 V  q5 G
  52. {; ]" k1 Q! y  P7 M1 X: |
  53.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    2 M; Z- w& E+ U/ V7 g

  54. 9 L) c+ }+ s3 y) N) A5 G* Q* z
  55.   /* GPIO Ports Clock Enable */. Z: R) I" `, B0 Y
  56.   __HAL_RCC_GPIOA_CLK_ENABLE();
    % k' o, _/ ^0 W  W% L' {& R+ F

  57. 4 _0 G! V- Z  C7 b1 i3 }
  58.   /*Configure GPIO pin Output Level */2 H; d) ^- e; Q0 n( u; |3 W
  59.   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);( T( a9 X. w4 ^& n

  60. 5 F  G9 w# Z, g$ X! r# F" \
  61.   /*Configure GPIO pin : PA4 */
    3 @6 r4 d$ B6 o5 E  q
  62.   GPIO_InitStruct.Pin = GPIO_PIN_4;6 {4 A7 X2 L8 B7 }
  63.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    4 [2 Y& S% y3 c) S
  64.   GPIO_InitStruct.Pull = GPIO_NOPULL;% `' r; [2 Y+ K4 C; Y* V
  65.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;4 c1 G; R9 d. d
  66.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    ! M6 h9 W5 O* ?

  67.   [+ y* K8 k) e
  68. }
复制代码

  Y3 V0 s9 R1 `8 h6 ?* T同一总线上不同设备,工作在不同模式的时候,速率可能不一样,需要一个重新设置速率的函数:! D1 g3 X9 J, H- A  y- Z

- [: `& c9 [' u( p( x! j0 Z
  1. void SPI3_SetSpeed(u8 SPI_BaudRatePrescaler): I: U* w+ w1 }% ^; R. W" y9 k
  2. {7 r# }+ m) ?% B, \/ i
  3.     assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性6 W0 ~4 p2 O) o3 p" m1 P
  4.     __HAL_SPI_DISABLE(&SPI3_Handler);            //关闭SPI
    + k3 B) m* z; ^5 N$ `4 l2 [$ F
  5.     SPI3_Handler.Instance->CR1 &= 0XFFC7;        //位3-5清零,用来设置波特率
    , b+ y. u+ w9 O% H, Y! E. m3 v
  6.     SPI3_Handler.Instance->CR1 |= SPI_BaudRatePrescaler; //设置SPI速度
    0 ^" G& ?  L( x1 i+ }5 f  r
  7.     __HAL_SPI_ENABLE(&SPI3_Handler);             //使能SPI5 j* L1 O# m7 b. o  G

  8. * V' `+ @9 O2 h. A: f
  9. }
复制代码
; @8 O6 ^( Z" T6 q, B& I
因为全双工的读写是同时的,封装一个读写函数:6 f$ i+ D/ K& G# R" B
4 c9 @$ n) V: v! C! e* z: D+ [5 U
  1. //SPI2 读写一个字节
    ' Q& I" T" x3 U3 y; Q6 T
  2. //TxData:要写入的字节
    " b/ u) b' U2 c+ h
  3. //返回值:读取到的字节6 `8 b* L5 Q( `; Z1 @- B6 X
  4. u8 SPI3_ReadWriteByte(u8 TxData)
    6 x& p5 K/ o+ U9 |( ], C5 o
  5. {7 N9 S+ R0 e3 b$ G6 n) |3 g
  6.     u8 Rxdata;0 y8 O' l  k3 d
  7.     HAL_SPI_TransmitReceive(&SPI3_Handler, &TxData, &Rxdata, 1, 1000);
    , u8 j% q6 T  v' ~9 Z; C! ~
  8.     return Rxdata;                      //返回收到的数据
    2 |8 }" y' J! k- a' j2 s5 g
  9. }
复制代码
' }' F1 {, l' K& j' s1 A
根据W25QXX的数据手册,写一个读ID的函数:
+ D) V6 H1 o# f$ u2 K" W/ m5 ~
  1. //读取芯片ID& R. Z1 x6 J7 K, K$ m' Y! v
  2. //返回值如下:                                   
    7 t4 B3 t) w& J8 c
  3. //0XEF13,表示芯片型号为W25Q80  
    , A$ J3 V) R/ `" E
  4. //0XEF14,表示芯片型号为W25Q16    & j/ ?; G! _( p' {
  5. //0XEF15,表示芯片型号为W25Q32  8 g" g  V4 w  K* T: w, @7 F! G
  6. //0XEF16,表示芯片型号为W25Q64
    $ o, r6 H. o3 ]) U( ~
  7. //0XEF17,表示芯片型号为W25Q128           
    0 [, l4 C8 V/ s& ?7 B5 L) H
  8. u16 W25QXX_ReadID(void)7 R0 F( l: ]0 ]
  9. {
    & Q' }( F% F0 e: |/ I# E6 n8 G+ J
  10.         u16 Temp = 0;          ) J0 V; c: _& `( n. W
  11.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);            
    + t8 m9 v4 K5 S) R' n
  12.         SPI3_ReadWriteByte(0x90);//发送读取ID命令            
    9 P2 i# M, l( T0 d* C+ G' I
  13.         SPI3_ReadWriteByte(0x00);             - Y) S% s7 n1 N, {5 [8 W! M& x
  14.         SPI3_ReadWriteByte(0x00);             " @: Q; p! F* ?/ J% e8 K' Q
  15.         SPI3_ReadWriteByte(0x00);                                     8 P+ |& t1 H# ~5 F2 X7 Q# C5 q
  16.         Temp|=SPI3_ReadWriteByte(0xFF)<<8;  3 X  o  T* J( L7 n5 C/ H! X& k& v6 b2 V
  17.         Temp|=SPI3_ReadWriteByte(0xFF);         5 u3 X' }  R; B$ T
  18.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  ; Q/ D4 @0 h' |7 ]
  19.         return Temp;( v" a+ r; d! s( |
  20. }  
复制代码

  A* ^; Y, i: ]6 D+ t8 s最后写一个在主函数中调用的接口函数。4 @# P2 W9 K: J$ B5 e

3 ]2 V; ^7 D: k! w
  1. void W25QXX_Init(void)7 k3 p+ `( S+ S% [
  2. {
    : w4 d8 A( `% Z% q& [  i( r
  3.         MX_GPIO_Init();1 E( K$ i+ V" S9 Z5 J; B$ E
  4.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);' P/ p, V4 H4 }) r' w+ F
  5.         SPI3_Init();5 F  w* q2 J6 M  F' S1 f- x. i
  6.         SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);
    2 v) c3 q8 [% i0 B- y
  7.         uint16_t W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.  6 |7 {9 S4 n2 |; X0 x1 c$ }, X
  8.         printf("W25QXX ID:0x%4x\r\n",W25QXX_TYPE);" c4 U$ A8 u/ w  J7 ^: O  K7 L( f
  9. }
复制代码
9 T' X2 L4 i" ]/ ~
下载运行,读取到了芯片ID。- u/ X8 Q, G; W" z

& W5 G1 B( C3 S
20200423121114508.png
6 F) Q' M1 a7 }, z! `' g, c

8 D  W8 [, W' d+ s6 c" c: d$ Z
收藏 评论0 发布时间:2021-12-12 21:44

举报

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