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

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

[复制链接]
STMCU小助手 发布时间:2021-12-12 21:44
SPI协议的原理,网上大把的资料可以找到,这里记录一下SPI的初始化过程,以即以读取W25Q16型号为例的一个简单的SPI读写过程。
' d8 h/ V' v% g+ \: s: M- u! P, mCubeMX配置:0 T3 I) |$ m1 O+ G1 Z' M
: p# Z, ]: a4 f
20200423110312574.png
: R4 B- B& T) b9 V; _/ r
( I* ?7 J1 w& q) w
SPI模式2 {# r' P! m% A9 @" C
有只发送、只接收、半双工和全双工模式;5 q! {  @" i, m; F& [
根据自己的需求,和SPI设备支持的类型,这里选择全双工的SPI;8 ~2 f; ?5 I- a8 t. q+ J% T0 _7 E
7 E! ^, s) L5 t' l
片选信号: t3 F) m2 D2 ^0 m6 c$ i; r; |
因为我们这个SPI总线上会挂载多个从设备,而且只有一个主机,所以,这里禁用硬件片选,程序里面读写之前使用软件进行片选;
$ Y, O+ z. L$ H" F' d! H; v
5 S+ c( F# {* p! L# ]/ o* W& }6 `帧格式9 w- Z8 T' `' k9 a% W6 s7 a7 G
这里选择Motorola帧格式;) H8 J8 P; Q7 r
选择TI格式不能设置CPOL和CPHA,而且必须要开启硬件NSS这里才能选择TI模式。
2 [8 `7 m8 n, S3 @: @博主在网上搜了一些关于TI的SSP协议相关的资料,只有简简单单的一句:SSP总线兼容SPI,SSI 和Microwire 总线的接口。; w/ E- |0 ^. r$ X( R3 j
博主又搜了以下Microwire协议,和SPI一样,只不过片选信号是高电平有效。& ]: x: y, X# Y0 D$ M/ p
这是手册里关于TI模式的说明部分和波形图:- N( ^" J3 q7 D& r' {. U
; _$ n. r1 R* r$ Q8 i0 h8 u! K
20200423112839303.png
6 t+ |$ I. {1 z% h- `' i3 }
* N7 i) @) B+ p
20200423112906213.png

! G5 Y. @& Z5 ~& n6 i" T' k1 ]7 f' G+ V( [4 ?
也不清楚这个SCK的触发信号是干嘛的,所以这里老老实实选择Motorola就行了。
  O3 P! q& d. o( L2 x8 p7 Q4 b7 s
2 m" F  t8 f* B  v8 A% K, D数据长度6 n( i0 L7 C6 i
4-16bit可选,根据实际,选择8bit;
6 g4 }0 U7 w) J$ i+ w% C. N6 `6 w* A( C1 V8 p, a  s  S6 \
数据传输模式  t# K$ V' a+ L: \
第一个传输的bit是高位还是低位,这里根据设备来选择,好像MSB(先发送高位)的比较多,注意这里的会同时设置发送和接收,如果设置错了,发送的指令对方就无法识别,可能收到的就是0xFF这种值。
( `7 J, b( [; o, w! @3 h7 B& M# [+ |. E6 V. o" H9 q
SPI速率  P, p& M- g2 ^0 s) `8 q! h
SPI的波特率是由时钟分频得到的,CubeMX很方便的还帮我们计算出来了时钟速率,可以根据自己的需求设置。, e' t5 W6 O( x2 u$ u" R/ J8 V. A( v
& _; d1 H( M* r: v# i/ w
时钟极性和时钟相位6 A6 s  p: }' [) Z% D2 R
根据极性和相位的不同,可以有4种不同的工作模式,这个根据芯片手册支持的模式选择,注意,一条总线上尽量挂载支持相通模式的设备,这样就不用每次在设备切换之前重新配置SPI外设。; X, }! F. A# ?

7 x: k+ m( ]" R! K! F' SCRC校验$ d3 M+ ]) ^- k( ]# m# j* S
暂时还没研究到这里……8 b- ]8 a, Z# _8 i/ L& J1 g& B( @3 l8 |

4 {# {9 o! M9 |4 K. z' UNSS脉冲

1 j5 b3 o, l+ [4 q参考SPI的NSS 脉冲模式的作用,这里用不到;
% N6 k  G9 H0 F* n3 g& F% F
9 b+ V; Y7 i( _NSS信号类型
2 U5 `( C4 i0 e7 w5 Q. I* t* V
因为前面禁用了硬件片选,所以这里只能设置位软件模式。" k6 N9 n6 J/ j

  f  ?9 e, S$ e9 t除此意外,还需要把连接硬件片选信号的GPIO,设置为输出模式。
7 D' O# q: a' \4 w3 x1 jCubeMX生成的代码如下:- c& \. m* E% U7 h; l. p+ F
1 \7 r4 a$ g& ]( b6 `% n
  1. SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄+ g) w9 S% c) V* X7 m0 r

  2. * w' T' e: K4 L, W" r; y+ e1 c
  3. void SPI3_Init(void)
    0 L; s' O' f- [) g7 V8 P
  4. {  W  j! l) f& q# b4 D( {
  5.     SPI3_Handler.Instance = SPI3;
    ' _& G9 \1 l8 H; \8 ?) A9 W, T
  6.     SPI3_Handler.Init.Mode = SPI_MODE_MASTER;
    * ?8 D! ]' L8 E( c
  7.     SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
    5 r3 i) f9 _* }9 x1 v2 k
  8.     SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;
    2 y8 G& |: z# U- C3 h
  9.     SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
    # G" v) B) q; M  {
  10.     SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
    % x8 v0 |% W1 j2 s
  11.     SPI3_Handler.Init.NSS = SPI_NSS_SOFT;3 U  M$ h  l/ `# \
  12.     SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;5 j0 B7 K7 \1 M0 z+ h" A$ D
  13.     SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;7 b% ^1 K) G2 o* ?+ i
  14.     SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;
      D- s& |8 }6 o8 l  n& j+ E/ x7 R
  15.     SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    # s+ P4 z, b( w" ~4 h3 b7 m& R/ ?
  16.     SPI3_Handler.Init.CRCPolynomial = 7;* d, R. e6 n  B5 H9 ]
  17.     SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
    4 d+ n& a+ z/ w) w
  18.     SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    + B1 s9 w& k6 x
  19.     HAL_SPI_Init(&SPI3_Handler);
    ' i6 r3 {0 ^. j
  20. + V' Q+ n9 B) l4 u) T
  21.     __HAL_SPI_ENABLE(&SPI3_Handler);               , A" @1 q  @8 ?  {
  22. }
    " ?/ x6 Z. x# D$ F: N% T

  23. * j/ ^! W5 N1 e. p
  24. void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
    + y8 p- N# s/ u# f  M5 o
  25. {6 M! k/ _7 t6 d4 [2 ^8 N
  26.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    " D; e  I% r* w& h- l* s; [$ f
  27.   if(hspi->Instance==SPI3)
    , s* ]( C, ?2 v8 ]6 d
  28.   {9 p0 {6 H& Q9 N% ~! k; P8 A

  29. 8 a' u" U6 N+ |: X2 j
  30.     __HAL_RCC_SPI3_CLK_ENABLE();
    , v2 E3 m& Z/ g+ {7 Y
  31. 0 ~8 j% w- ~  q0 f4 @' {! n- _
  32.     __HAL_RCC_GPIOB_CLK_ENABLE();2 N3 N& `  |8 u9 b

  33. ; L" q/ g3 H7 `
  34.     GPIO_InitStruct.Pin = GPIO_PIN_2;
    , V- O; n. ^+ F  a) W
  35.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;% E# N8 N  w( [& l5 Q
  36.     GPIO_InitStruct.Pull = GPIO_NOPULL;8 R% U2 @/ s* j4 [" M
  37.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;1 `! Q  {6 r1 F: |% v0 ?
  38.     GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;
    ; O% c, D! X& D7 D4 ^' E
  39.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    , m. U) Z! d6 x7 Z5 x  c- C+ _

  40. 8 X6 Y" Z* O' z6 p* b! \' ^1 u# Q
  41.     GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
    , Z+ v9 D$ k- u* V& l
  42.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    . I( ?* ~  N5 j
  43.     GPIO_InitStruct.Pull = GPIO_NOPULL;  V0 a. n6 K3 _$ O# o- n
  44.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;9 q$ B% X" J+ Y/ I& d2 a
  45.     GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;0 A7 _* }' \+ P' s# ]+ q2 \/ C
  46.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    # X' d1 N/ N% }/ ?
  47.   }/ X1 P" ~* b1 ^; t' \* ]
  48. }
      q) }( v% l4 L9 l
  49. ) j- S4 H" [& z& g7 S8 G) i0 ^
  50. # i  ^$ ^( x7 D3 u
  51. static void MX_GPIO_Init(void)! e$ B) @3 @1 S: ^2 ~- W2 w% M" @
  52. {% q2 X: ]7 ?2 ~* ]5 ?4 m
  53.   GPIO_InitTypeDef GPIO_InitStruct = {0};; o$ U- P* g5 e7 b: Y$ b
  54. 6 X% `; Z1 A% ]' f/ u! S: a
  55.   /* GPIO Ports Clock Enable */
    / A, f. E  \7 G6 _" u& j4 M
  56.   __HAL_RCC_GPIOA_CLK_ENABLE();3 I( K' v5 g# h( m  ~+ P
  57. , n6 H# O' c; }8 N0 ^
  58.   /*Configure GPIO pin Output Level */
    1 o* _& [2 Q2 N+ v
  59.   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    ( L, B8 A4 K) U* _6 t1 M
  60. ) Y% K; G+ W- R% }3 V3 Y
  61.   /*Configure GPIO pin : PA4 */8 I/ e2 ^6 N) v7 T- M
  62.   GPIO_InitStruct.Pin = GPIO_PIN_4;
      L- v  {& t: H+ _& G: }
  63.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;# o. ]( C8 T% r, y
  64.   GPIO_InitStruct.Pull = GPIO_NOPULL;  j- n+ m2 E) J8 R( V5 D8 `4 I
  65.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;' {& ], G% d* r5 s0 k0 l0 h( }+ L
  66.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);6 m4 ?8 Z( E+ O$ H
  67. ' c3 ]0 R) H! g$ `! q
  68. }
复制代码
9 ?7 t; b! _1 x- Q# H5 g! L
同一总线上不同设备,工作在不同模式的时候,速率可能不一样,需要一个重新设置速率的函数:0 e' \4 E! ?4 A

( i! Q  R: j, E, q8 D
  1. void SPI3_SetSpeed(u8 SPI_BaudRatePrescaler)6 m  W  W5 i. X- G0 E. \+ G+ u
  2. {
    1 Q' a* |: {, \! e
  3.     assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
    ! x. T- u- h. o9 k
  4.     __HAL_SPI_DISABLE(&SPI3_Handler);            //关闭SPI! t& u- U6 n1 }: _, ]5 L
  5.     SPI3_Handler.Instance->CR1 &= 0XFFC7;        //位3-5清零,用来设置波特率$ Z  ^# S; K' @0 S
  6.     SPI3_Handler.Instance->CR1 |= SPI_BaudRatePrescaler; //设置SPI速度
    / [7 J" u0 _9 o' L; c
  7.     __HAL_SPI_ENABLE(&SPI3_Handler);             //使能SPI
    , q  a. Z* a- j0 m. R' S; [; o
  8. ; c; l3 q8 W! L
  9. }
复制代码
3 U3 i" H) c- u% `
因为全双工的读写是同时的,封装一个读写函数:
8 W9 I3 B1 n; B  z1 U7 W, M$ |0 K6 Z$ F/ u6 `' J3 W) T
  1. //SPI2 读写一个字节4 k$ t4 x' U7 h. ?
  2. //TxData:要写入的字节
    $ t0 M: B9 Z9 f2 b& T# e
  3. //返回值:读取到的字节
    4 n, I3 {3 c. t: p7 F. G
  4. u8 SPI3_ReadWriteByte(u8 TxData)' L; e7 m4 ~" P. v3 f) O
  5. {2 z4 |% \% D  c, q5 K
  6.     u8 Rxdata;
    1 K" D' m5 U1 w4 V+ o# p5 ?1 w" [
  7.     HAL_SPI_TransmitReceive(&SPI3_Handler, &TxData, &Rxdata, 1, 1000);; [; b0 n1 x( {. |6 E
  8.     return Rxdata;                      //返回收到的数据
      O0 I4 y; ~6 F2 _/ x3 h
  9. }
复制代码
# Y9 ^: C+ P' K, R% _
根据W25QXX的数据手册,写一个读ID的函数:
4 M& y7 j. ~) w# l6 f
  1. //读取芯片ID% _0 S' ~1 y6 m: @: A) k3 A* W
  2. //返回值如下:                                   
    & H2 `* O' c- |! n
  3. //0XEF13,表示芯片型号为W25Q80  
    ! f5 {! n1 `9 f
  4. //0XEF14,表示芯片型号为W25Q16   
    & |+ f4 F$ @9 g  e0 o6 S6 U2 \1 e
  5. //0XEF15,表示芯片型号为W25Q32  
    ! T$ n# S" b/ g8 J
  6. //0XEF16,表示芯片型号为W25Q64
    0 W% F# i' p" k1 M  ]) Y
  7. //0XEF17,表示芯片型号为W25Q128           9 q  x+ j; v( {8 e: u
  8. u16 W25QXX_ReadID(void)2 B0 t) l, P% ]4 X4 r- K6 c  F
  9. {! K) h. p0 J! ~% R
  10.         u16 Temp = 0;         
    2 D# {7 \. e: [& f: f
  11.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);            * B5 u9 x4 z1 e4 g' ]: Q7 ~! e
  12.         SPI3_ReadWriteByte(0x90);//发送读取ID命令            4 }( |) V. b, f
  13.         SPI3_ReadWriteByte(0x00);            
    $ L1 Z9 M) h6 W+ w2 B1 v. O- _
  14.         SPI3_ReadWriteByte(0x00);            
    5 Y7 I2 j9 q( L5 X+ U
  15.         SPI3_ReadWriteByte(0x00);                                     1 r7 k; |& O* ]- }* e6 |7 d
  16.         Temp|=SPI3_ReadWriteByte(0xFF)<<8;  & Y* M* C! w9 ^- N8 `/ c
  17.         Temp|=SPI3_ReadWriteByte(0xFF);         # d, t/ ], x7 L" q& g' }) u9 W
  18.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);  
    * U8 R( q( g0 K( T  K7 `5 M
  19.         return Temp;
    4 `. ]2 _# A4 Z3 k1 {- h+ Y- |3 _
  20. }  
复制代码

7 L% o- [* i6 S最后写一个在主函数中调用的接口函数。( g3 b% f5 d% R  ]$ i9 p( h0 ?
2 f: q+ q  I* ?; B
  1. void W25QXX_Init(void)
    5 v2 D+ q* ^" A3 ^& j7 L
  2. {
    7 i" f0 t) l- k  k0 E5 n5 \
  3.         MX_GPIO_Init();/ m" x+ h  O- C5 p5 K% D0 E
  4.         HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
    " Z; ]' C5 u. V$ ~3 i, s* ?8 t
  5.         SPI3_Init();- F# h; a& R% o9 C. d7 U  @
  6.         SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);
    ) l4 X. C) ]7 V) x3 j5 T; U+ G
  7.         uint16_t W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.  
    # `1 h! K8 Z5 u' d1 Q7 u8 N/ l
  8.         printf("W25QXX ID:0x%4x\r\n",W25QXX_TYPE);
    ; N% T& Y- y7 L6 d6 Q0 l3 z" A
  9. }
复制代码
2 h' w! J: [* L# C: i( V) R) \5 l# c
下载运行,读取到了芯片ID。
( b' @! z5 ~; t  Q* C$ I5 c4 J6 `" b) g3 c7 ]- Y" t
20200423121114508.png
0 e2 |: t- V1 h/ n7 B6 B1 D
4 a- r* o( W: Z$ g0 i5 o
收藏 评论0 发布时间:2021-12-12 21:44

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版