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

【经验分享】STM32使用HAL库模拟SPI方式驱动W25Q128存芯片

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
1、模拟SPI方式的IO配置
! N$ x# @! ^# u0 F6 |0 @/ J) t/ j5 p9 a: N3 {
20200622094245892.png & t. Q7 g( P" s
6 R3 o, ^% Z% A
2、驱动代码

3 s9 ^& Z$ X, ~/ m5 p; u2.1 头文件2 E) @1 F. o+ b' \8 F7 G. Y7 ^
  1. #ifndef __W25QXX_H
    7 L1 d$ K- P) q
  2. #define __W25QXX_H                            ; C5 k  @9 z  g
  3. #include "main.h"
    3 m% s1 `1 ]4 }% S& o: x
  4. " P! i3 }& u) `
  5. //W25X系列/Q系列芯片列表           
    3 T& g9 @/ S% Q6 ]
  6. //W25Q80  ID  0XEF13
    : D. ]; [8 d5 U" t' c, g
  7. //W25Q16  ID  0XEF14
    # M* r  Q6 b6 q1 D1 k2 [
  8. //W25Q32  ID  0XEF15. e+ o) i8 L' q8 `0 d2 t4 l- c
  9. //W25Q64  ID  0XEF16        
    / [7 w. |/ r( H+ A
  10. //W25Q128 ID  0XEF17        6 T. J- }) {  ?. O/ @
  11. #define W25Q80         0XEF13         
    ' P- j! v) R' T) A# W) z
  12. #define W25Q16         0XEF14! K9 {; n) _6 `8 E' e3 v6 I4 R9 V
  13. #define W25Q32         0XEF15
    6 g, j  b+ X) K# ]
  14. #define W25Q64         0XEF16
    - f4 f( P& A( U" h
  15. #define W25Q128        0XEF17( @0 Z; s5 e% F3 c  q& R
  16. 3 D* Q% W2 l, w* M# ^, A8 i
  17. extern uint16_t W25QXX_TYPE;                                        //定义W25QXX芯片型号                   * n4 n3 S2 f9 a% K' T' W' T$ ~, z2 d
  18. extern uint32_t W25QXX_SIZE;                    //容量3 |0 `- z* F* E7 a. M
  19. extern uint8_t  W25QXX_UID[];                   //唯一ID7 _" x- {3 j4 T
  20. 5 n- M/ z! d2 x/ G  O
  21. //
    # b; W, M! u2 T+ u
  22. //指令表! A4 n% @* W% _1 D3 d
  23. #define W25X_WriteEnable                0x06 * d. k$ U7 {. o! c$ _1 ~
  24. #define W25X_WriteDisable                0x04
    / z% f# j& Y" @: N( ^! a
  25. #define W25X_ReadStatusReg                0x05
    * p" D3 \' Q9 S+ Q8 \; u
  26. #define W25X_WriteStatusReg                0x01
    ! f" [' X0 q  z9 p- a  g4 Q
  27. #define W25X_ReadData                        0x03
    ' ]: c" l! D* T1 x8 T
  28. #define W25X_FastReadData                0x0B
    5 G% r* Q( r* O2 }2 F4 S) A
  29. #define W25X_FastReadDual                0x3B
    ( r( t6 U# i) Q- R$ Z
  30. #define W25X_PageProgram                0x02 5 B4 d- _# D1 T+ T
  31. #define W25X_BlockErase                        0xD8
    " N8 d; b; `3 y$ u
  32. #define W25X_SectorErase                0x20
    9 k* j' o3 F; |0 m
  33. #define W25X_ChipErase                        0xC7 ! F6 w( R; @7 u" \& g; U
  34. #define W25X_PowerDown                        0xB9 6 ^- `0 y. g* r& S
  35. #define W25X_ReleasePowerDown        0xAB : M9 H! E& x  J" \+ m0 `4 G$ D) D/ z& L
  36. #define W25X_DeviceID                        0xAB $ M& v- T4 h: s
  37. #define W25X_ManufactDeviceID        0x90
    6 `3 |' P$ k8 D7 O' E! c
  38. #define W25X_JedecDeviceID                0x9F $ p9 ]$ X3 A7 d* ?" }

  39. / A) k+ C1 A3 H6 b3 v- @
  40. void W25QXX_Init(void);
    ) H6 d9 l$ l8 n/ K$ S5 X# W+ K$ u
  41. uint16_t  W25QXX_ReadID(void);                              //读取FLASH ID" L. M: v, {! y$ a* ]
  42. void W25QXX_ReadUniqueID(uint8_t UID[8]);       //读取唯一ID5 r2 Q8 R3 J& J3 p( p# N
  43. uint32_t W25QXX_ReadCapacity(void);             //读取容量" H& i5 P3 w. {( f$ [/ S
  44. uint8_t         W25QXX_ReadSR(void);                        //读取状态寄存器
    ! ~) R2 E3 _6 o* @% h9 u
  45. void W25QXX_Write_SR(uint8_t sr);                          //写状态寄存器1 U3 C; {" E- P: ^4 U5 G; y
  46. void W25QXX_Write_Enable(void);                  //写使能
    ) ]2 \- q: Y% w9 t. ~7 \6 N( X
  47. void W25QXX_Write_Disable(void);                //写保护
    1 t: J) p6 A" x0 e/ X7 R0 `! _
  48. void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
    1 I0 Q# C9 B$ J8 m! \* O. Q
  49. void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   //读取flash
    8 v7 |" r9 ]( t
  50. void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
    4 W6 O" r# H- i, N9 a
  51. void W25QXX_Erase_Chip(void);                      //整片擦除* g: V, {- H0 N( T. h5 ]! X2 W7 v! O
  52. void W25QXX_Erase_Sector(uint32_t Dst_Addr);        //扇区擦除
    1 P% g8 k( _2 L. U: M, z  z
  53. void W25QXX_Wait_Busy(void);                   //等待空闲; Q+ ]& h3 S+ I# {: y
  54. void W25QXX_PowerDown(void);                //进入掉电模式
    # o6 ^5 m) R) a: n
  55. void W25QXX_WAKEUP(void);                                //唤醒
    $ _& |: ^* E. s' c3 @, J9 T4 E) M8 K0 V
  56. 9 N  K/ F2 f1 g+ y+ `  k( R% p2 }
  57. #endif# e  z4 t5 y! z4 o' C: L1 e
复制代码

5 ^. X$ M+ A- h' v% E2.2 源文件

2 i. r1 E# N7 N7 I+ b1 v5 M
  1. #include "w25qxx.h") k8 W- q& x4 w6 I6 G& ?. |
  2. 1 i4 U8 q; p. `" M  }- h
  3. " X" u/ R' H/ \( c; P
  4. uint16_t W25QXX_TYPE = 0;4 a: w  K0 x& @8 b( o6 }: ^
  5. uint32_t W25QXX_SIZE = 0;
    % U5 x" |0 ]  s0 D+ E
  6. uint8_t  W25QXX_UID[8] = {0};) X" j* `: O2 ~& t

  7. ! D: ~4 K% @/ x% C2 n# ^

  8. ! W: Y/ h. O: a% S1 j4 ~
  9. 0 Z. Y3 p9 y2 {

  10. 7 k' t0 D) a& P! m7 o% e
  11. ///
    - h5 \+ i& T9 M. G' d" T) l8 l
  12. ///            移植修改区* p& U" ], m/ D1 ^. a: {2 y
  13. ///
    3 l  k# @% K' V+ H$ Z# U% P& t
  14. ///
    5 V9 _  c' Y/ \
  15. 9 i! i4 C7 B2 R( l
  16. #define W25QXX_CS_H()         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET)) X: h- p/ h: a4 W
  17. #define W25QXX_CS_L()         HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET)
    * M5 t4 _- n+ y( ]

  18. 0 m6 d& B2 E/ y" N1 q
  19. #define W25QXX_SCK_H()        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET)& E0 c5 X4 ^. I8 _# ^% x, Q2 }( i
  20. #define W25QXX_SCK_L()        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET)! F$ r$ D. a0 l/ Z

  21. 4 G# j# o1 o0 x' |. H
  22. #define W25QXX_MOSI_H()       HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET)
    - U; X& i7 r# E; j. P
  23. #define W25QXX_MOSI_L()       HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET)
    8 |9 i% e  D( `
  24. 9 T+ F0 u8 @2 h6 d) }# e) I' F; W
  25. #define W25QXX_MISO_GET()      (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_SET ? 1 : 0)3 O9 X7 l# r% m5 W. z
  26. ( z, |  ^; i( b2 g* ^
  27. static void delay_us(uint32_t us)( U# d  i. `! H4 y
  28. {* u/ |! L9 ], ?( M6 ^, u. h
  29.     uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
      f' O! @' `/ I
  30.     while (delay--)$ W3 z/ [3 f8 ~9 V' V
  31.     {9 x7 n$ w; T  l# v4 L7 z. [4 S
  32.         ;7 c7 M' [, n: O8 L  d
  33.     }
    9 t. X0 O# D% P
  34. }
    / }4 H( x9 a8 r: U0 x! h
  35. 6 Y0 [' w5 u% Z: m6 _' _* V
  36. static uint8_t W25QXX_SPI_ReadWriteByte(uint8_t TxData)& ~- [1 Y8 X% }9 U$ ?3 T4 a& L
  37. {
    5 K" j" I* t3 h% ]3 o
  38.     int i = 0;
    9 L8 J0 ?6 l& P; ^
  39.     uint8_t RxData = 0;
      @* n" O7 [9 t1 k7 b
  40.     W25QXX_SCK_L();
    2 U# u4 F' O9 a3 D
  41.     for(i = 7; i >= 0; i--)" _/ h. V  U  u( }; C" K0 d
  42.     {
    % T, {3 U6 T2 g3 A
  43.         W25QXX_SCK_L();# Y( k  B6 U  s1 E4 k& H7 S
  44.         if(TxData & (1 << i))7 Q5 P4 _" ~( H
  45.         {) `& R7 b. p: Y# r2 F) @6 X) m
  46.             W25QXX_MOSI_H();
    - j+ [5 y: l0 D3 q& c/ A: O3 _
  47.         }6 y1 o# Q8 F9 |; r# ^- F) t5 v7 L
  48.         else
    : Z4 N# ?, A6 z/ T
  49.         {1 U+ c9 P8 i! Z4 A' z- ^
  50.             W25QXX_MOSI_L();  o  |# m' }: u2 M
  51.         }3 E$ k  |' n( K+ e) r2 K( G7 U9 }
  52.         delay_us(1);  t2 x% n$ P" W+ d: P5 X/ {
  53.         W25QXX_SCK_H();6 _# s3 {8 _: v6 b( R% Z
  54.         RxData <<= 1;
    3 d. ?& S5 z  L' x
  55.         RxData |= W25QXX_MISO_GET();
    " P$ D4 x/ `$ `6 k( u. Y8 R
  56.         delay_us(1);
    8 G4 K9 _$ W/ b
  57.     }# T- Z7 @# E. e. D3 A- }
  58.     W25QXX_SCK_L();. F. n# }: Q7 A
  59.     return RxData;8 ]8 R$ L6 {4 n
  60. }
    & G7 h3 L& @# P

  61. : r/ @. U3 H4 K/ {
  62. static void W25QXX_SPI_Init(void)
    7 N) U' F8 `5 T6 C/ z- `
  63. {
      W2 K- Q: V: C: o. [/ N
  64.         // 这里添加初始化IO的代码
    ( K9 Z1 \# T4 U5 P8 y
  65. }/ G* i5 L4 M: B( g
  66. ' e/ c& O$ Z9 j! \; N8 j

  67. % \% p* L+ J0 k2 X. p
  68. 2 }, K$ v3 I( F/ M& a; e5 l
  69. ///
    % I4 x3 d, g7 f: m3 l
  70. ///            驱动代码8 Q- l/ D6 f: O% s
  71. ///! I7 L% @; R$ @  e. }1 K
  72. ///
    1 P) ]  v" M- \, B( z
  73. 5 Q8 L' E, @; e: J
  74. % Q' l, }7 I) A6 Z
  75. //4Kbytes为一个Sector& b) V/ R" q1 A/ x  p! g) u  Y
  76. //16个扇区为1个Block
    $ l  ^4 H6 J/ s7 @' p$ R' l
  77. //W25Q128& |) M: O6 S6 l
  78. //容量为16M字节,共有128个Block,4096个Sector
    ' U* L) R$ w9 m  T0 }. |- b

  79. " ^% N0 v7 z0 Y9 Q
  80. //初始化SPI FLASH的IO口
    & E' y. k: L* V& p% ^
  81. void W25QXX_Init(void)% V: ?  H0 }7 I& `6 v) `
  82. {$ }6 y8 D" k0 Y5 i2 p+ r1 x% g
  83.         W25QXX_SPI_Init();) ?5 i; W6 a: X. @$ m* h/ {
  84.         W25QXX_CS_H();                // 取消片选* L( U: W; |3 W2 d+ B# o& r; g3 `
  85.         W25QXX_SCK_L();               // 时钟空闲为低电平7 _+ @, I' t1 C3 m
  86.     W25QXX_CS_L();6 l6 k2 [) P+ Q8 ^! I
  87.     W25QXX_SPI_ReadWriteByte(0XFF);1 a( s( e; m$ f  g- s' Y, F. v
  88.     W25QXX_CS_H();2 N7 T" ~- X) x) X% o- O
  89.     W25QXX_TYPE=W25QXX_ReadID();             //读取FLASH ID! j3 l* y# J! F
  90.         W25QXX_SIZE=W25QXX_ReadCapacity();       //读取容量
    6 `5 k3 W6 D7 Q! I7 y& ^/ ?1 ?
  91.         W25QXX_ReadUniqueID(W25QXX_UID);         //读取唯一ID& R3 U* P& |7 q% V0 Y- i  X7 c
  92. }  y2 ]( x4 ~3 W4 h

  93. : B, E( A+ V( \2 v: c
  94. uint32_t W25QXX_ReadCapacity(void)
    + E) j) y/ D+ f: @+ d4 {( j
  95. {
    ' @8 P$ i& i4 K
  96.         int i = 0;0 }9 I! f0 k: p' R" Y
  97.         uint8_t arr[4] = {0,0,0,0};: r. y! _+ a# L7 |+ w
  98.     W25QXX_CS_L();
    ' w/ v, B% d5 i9 u, F2 D
  99.     W25QXX_SPI_ReadWriteByte(0x5A);6 H. G' z' e3 R6 l- I- y& c' a! o
  100.     W25QXX_SPI_ReadWriteByte(0x00);3 L/ z) m) w% w, h
  101.     W25QXX_SPI_ReadWriteByte(0x00);
    ' [7 _. t1 S7 I4 b+ M
  102.     W25QXX_SPI_ReadWriteByte(0x84);
    ) c2 c4 x7 r" }+ P. z% |+ O8 s
  103.         W25QXX_SPI_ReadWriteByte(0x00);
    1 G9 A3 {1 H" w. ^) r
  104.         for(i = 0; i < sizeof(arr); i++)1 o3 Y/ o: _4 y3 M3 Z- j3 h
  105.         {
    " ?2 d1 w( s) X6 k% v. b0 o
  106.                 arr<i> = W25QXX_SPI_ReadWriteByte(0xFF);
    8 {% a4 ?( |0 v
  107.         }5 o" `9 u6 e# _4 q' S  I+ p: Y3 f
  108.     W25QXX_CS_H();
    ; \, |0 D0 G& ]1 Z9 g* `% R
  109.     return ((((*(uint32_t *)arr)) + 1) >> 3);
    : |) p/ l+ I5 n: S# v
  110. }2 q  L5 o1 H+ Z! g7 x
  111. 2 A) ?, n0 ~) Q& d$ B# i
  112. void W25QXX_ReadUniqueID(uint8_t UID[8])* v7 v& P+ z* }, F2 ^. N; d
  113. {
    ) T, V3 |7 t! @" {6 f1 m: h9 F
  114.         int i = 0;
    9 i' @: j: b+ K5 _6 T' |. L* N. v
  115.         W25QXX_CS_L();
    , a2 `4 U& _4 D8 t0 s
  116.     W25QXX_SPI_ReadWriteByte(0x4B);5 {. }/ [0 C5 t9 |" f" ]- ?+ h- p
  117.     W25QXX_SPI_ReadWriteByte(0x00);
    0 S' X6 {) b6 {
  118.     W25QXX_SPI_ReadWriteByte(0x00);+ X! V4 R; x$ s2 H, u2 E
  119.     W25QXX_SPI_ReadWriteByte(0x00);
    & j' [0 R6 z# k2 Q3 a7 H3 _
  120.         W25QXX_SPI_ReadWriteByte(0x00);
    4 C0 k, }1 ?  {; v3 W7 G7 i! q- C
  121.     for(i = 0; i < 8; i++); ~# J4 D" Q6 U' m9 I
  122.         {
      y2 E% Z% z1 A: w1 v) `7 F
  123.                 UID<i> = W25QXX_SPI_ReadWriteByte(0xFF);
    / f  s0 {1 P8 n" u, h
  124.         }$ l* I" {. d6 g
  125.         W25QXX_CS_H();$ a% B+ ?5 n% S) v# j. D
  126. }- M3 D0 e9 d' Y9 d4 E1 X0 q! b* u

  127. 5 B$ P7 V# Q. B: g
  128. //读取W25QXX的状态寄存器4 B" I/ o5 S5 {! C$ D
  129. //BIT7  6   5   4   3   2   1   0/ U7 R# Q7 s& w6 f+ G
  130. //SPR   RV  TB BP2 BP1 BP0 WEL BUSY
    $ M2 ?* j. |9 v" i% s- ^- b$ l
  131. //SPR:默认0,状态寄存器保护位,配合WP使用; b* o! i. q5 j7 X
  132. //TB,BP2,BP1,BP0:FLASH区域写保护设置/ O* L' ~+ [) F4 t0 U+ f
  133. //WEL:写使能锁定
    ( ?+ H. A9 @' d7 a* ?, K0 J
  134. //BUSY:忙标记位(1,忙;0,空闲)% m2 O+ A( M# ?3 J- ]
  135. //默认:0x00
    % Y) g( Q" |6 i6 h; G
  136. uint8_t W25QXX_ReadSR(void)4 B3 G! p) V9 p& h3 ]! ]$ I; O" j
  137. {
    ! M4 h0 i6 U! r) d# S- @
  138.     uint8_t byte=0;: {% R8 J9 ]) R1 ]/ y& j4 E
  139.     W25QXX_CS_L();                            //使能器件
    3 u4 a! c  t  F$ v( ]6 T( J2 [
  140.     W25QXX_SPI_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
    + x4 j" L9 C- H. T3 p; p/ T! g) K
  141.     byte=W25QXX_SPI_ReadWriteByte(0Xff);          //读取一个字节( r/ d" K4 |2 C) t' m. r
  142.     W25QXX_CS_H();                            //取消片选% ^4 F3 B9 I3 g; \
  143.     return byte;6 a$ g1 K: a6 @' S2 B, n: y
  144. }( s4 d" D4 [1 \# E: i& H
  145. //写W25QXX状态寄存器
    % L/ F' z) j6 P9 u6 p
  146. //只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!- V; V) N: H( `
  147. void W25QXX_Write_SR(uint8_t sr)* b: f# R  b+ d
  148. {- b0 U" i& r" z/ d* [8 S9 g
  149.     W25QXX_CS_L();                            //使能器件( y, M( g: |& Z4 H
  150.     W25QXX_SPI_ReadWriteByte(W25X_WriteStatusReg);//发送写取状态寄存器命令
    ( f  L, q' f2 H2 x
  151.     W25QXX_SPI_ReadWriteByte(sr);                       //写入一个字节
    7 W$ O; L9 G1 ?8 U5 Q
  152.     W25QXX_CS_H();                            //取消片选# n/ W7 l( \! ~' ~) R3 ~
  153. }+ S. i( J# i5 G3 _7 ]
  154. //W25QXX写使能; ^4 s+ i. U4 G7 Y- y
  155. //将WEL置位# l% [) F  V; b* s: ]! _, M
  156. void W25QXX_Write_Enable(void); ]1 C* L" K7 {+ z& W
  157. {2 L$ }4 f# c3 U1 `1 @( R
  158.     W25QXX_CS_L();                                  //使能器件
    " H9 i/ b' N4 n' m2 q9 X& [" z
  159.     W25QXX_SPI_ReadWriteByte(W25X_WriteEnable);         //发送写使能
    - @. u  _- s6 |+ T" X! a2 A
  160.     W25QXX_CS_H();                                   //取消片选
    ( H8 g/ I& b% e0 c7 Z
  161. }+ K, h. \/ h- @# e$ r& J
  162. //W25QXX写禁止. X8 a) \0 f' U7 i1 V( C( Q
  163. //将WEL清零, K! Y/ R: D; ~+ J0 W
  164. void W25QXX_Write_Disable(void)
    7 U6 t0 b9 r2 ?! v% D/ D1 N" B
  165. {3 x  g2 Z5 S: B
  166.     W25QXX_CS_L();                            //使能器件
    ' @4 m; e3 B% u6 t$ o) d
  167.     W25QXX_SPI_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令% {4 z/ m8 S- E  [$ P
  168.     W25QXX_CS_H();                            //取消片选2 _# W. k  ^- `
  169. }6 U$ e8 i7 V  ?
  170. //读取芯片ID
    ) B! C0 c- D* B, h& b9 F
  171. //返回值如下:
    ; ~0 H" S) o1 q! x8 V, F" P
  172. //0XEF13,表示芯片型号为W25Q80
    * S. q: Q, y" M! W2 F5 E$ X- _+ a
  173. //0XEF14,表示芯片型号为W25Q16% _1 U! b8 q* H0 ~# F
  174. //0XEF15,表示芯片型号为W25Q321 p, J  c5 E5 p- J7 J3 J
  175. //0XEF16,表示芯片型号为W25Q64
    : q& p6 }) e" y% e4 G, N
  176. //0XEF17,表示芯片型号为W25Q128( _9 v8 m$ H5 w3 P9 G
  177. uint16_t W25QXX_ReadID(void)
    , G( ~: d2 {/ |/ X
  178. {
    8 B, t; f( V8 d/ j# s4 H7 a6 w
  179.     uint16_t Temp = 0;
    ! g# w9 }+ y. }' P
  180.     W25QXX_CS_L();1 J- ?. }" o( i1 E& E
  181.     W25QXX_SPI_ReadWriteByte(0x90);//发送读取ID命令
    8 j% q/ s% k, A
  182.     W25QXX_SPI_ReadWriteByte(0x00);  z! r5 m3 y. x" ?: G( h1 ]; W
  183.     W25QXX_SPI_ReadWriteByte(0x00);
    ( T1 b9 h% p5 j6 X/ E& B
  184.     W25QXX_SPI_ReadWriteByte(0x00);1 Z* K" s5 e4 ?% h
  185.     Temp|=W25QXX_SPI_ReadWriteByte(0xFF)<<8;6 }. D" r3 F" C- |0 R4 y; y' Q
  186.     Temp|=W25QXX_SPI_ReadWriteByte(0xFF);, r: K+ D. a: D0 S& S" Q$ ^
  187.     W25QXX_CS_H();2 |) M1 c* k: V$ Z5 B# v& K
  188.     return Temp;; V8 B' r/ k6 [/ X1 d
  189. }8 `6 o: ?. ~9 W- D+ \9 f
  190. //读取SPI FLASH" Z& O- L/ Z! T
  191. //在指定地址开始读取指定长度的数据
    5 D; [' S7 w" k
  192. //pBuffer:数据存储区
      z9 r# O! g1 z8 i1 p5 ?; }1 L
  193. //ReadAddr:开始读取的地址(24bit)3 Q7 O' j7 x6 l6 Y, }5 \
  194. //NumByteToRead:要读取的字节数(最大65535)
    0 o9 f5 H, |  m9 S. L) u
  195. void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)/ z% P  L  i7 A. }+ \
  196. {0 |" v' ?% E, N
  197.     uint16_t i;7 L: C4 Y/ L, e
  198.     W25QXX_CS_L();                                    //使能器件
    & w' Q" i+ z  g" d; b$ t
  199.     W25QXX_SPI_ReadWriteByte(W25X_ReadData);                 //发送读取命令7 J( _" f, V7 Q+ [
  200.     W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr)>>16));          //发送24bit地址
    9 U  j) t3 I7 H  X; j. y
  201.     W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr)>>8));. `/ d. e8 j% j/ o6 A
  202.     W25QXX_SPI_ReadWriteByte((uint8_t)ReadAddr);
    # u8 M' t  v/ B6 }- X+ ^
  203.     for(i=0; i<NumByteToRead; i++)
    2 z- `. ^8 m% ^( p, m' y6 w6 I9 i" |
  204.     {
    + _% u' ^( x( K
  205.         pBuffer<i>=W25QXX_SPI_ReadWriteByte(0XFF);           //循环读数
    ! k* b$ K  U' j, }1 z
  206.     }! z/ w" h, E3 y- E+ @9 ~% J
  207.     W25QXX_CS_H();5 w+ S; y8 c) h8 S% Z; p
  208. }
    ) v: A- x6 M- h7 G' `) d
  209. //SPI在一页(0~65535)内写入少于256个字节的数据7 U0 i* l% |! Z" c
  210. //在指定地址开始写入最大256字节的数据
    ! g' V8 c* h4 `" J9 `
  211. //pBuffer:数据存储区0 I% Q; o9 e0 ]" ]5 u
  212. //WriteAddr:开始写入的地址(24bit): n; S5 g+ A4 _2 V+ N: J+ P% }3 s
  213. //NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!* B* p/ ]7 L/ h$ V
  214. void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)# a  f; S  Y; G0 C; m3 Y
  215. {' y7 g# l# W; N. ]& |; j: I
  216.     uint16_t i;) \8 B2 e" T# l
  217.     W25QXX_Write_Enable();                          //SET WEL+ {4 u2 G$ _3 J( O! l: c
  218.     W25QXX_CS_L();                                    //使能器件
    6 f& f- a0 {/ J5 o4 y. q1 g
  219.     W25QXX_SPI_ReadWriteByte(W25X_PageProgram);              //发送写页命令% W  {$ l3 {5 _3 J2 K- s6 \
  220.     W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr)>>16));         //发送24bit地址$ I2 S3 r9 N8 V1 x
  221.     W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr)>>8));1 B* ~4 g* \/ Z( n& D( E
  222.     W25QXX_SPI_ReadWriteByte((uint8_t)WriteAddr);( N+ l; c7 n2 Z) I5 D4 X
  223.     for(i=0; i<NumByteToWrite; i++)W25QXX_SPI_ReadWriteByte(pBuffer<i>); //循环写数- J6 E! J  Z* Z2 [+ i' s
  224.     W25QXX_CS_H();                                    //取消片选
    ! ]" p: ]. k- v5 q# J# @- z5 u
  225.     W25QXX_Wait_Busy();                                                           //等待写入结束0 H# r! W+ k; J+ _! |( T/ g
  226. }. y8 i6 s0 W5 X3 q# z
  227. //无检验写SPI FLASH
      |+ r$ v' b4 T; p  G
  228. //必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!0 Y. u& @6 o. ~1 E
  229. //具有自动换页功能
    . R+ W( y( B* S: a) M
  230. //在指定地址开始写入指定长度的数据,但是要确保地址不越界!: U  z( B' P9 y# d8 I$ A
  231. //pBuffer:数据存储区
    0 N0 R5 g. ^9 e7 p+ A
  232. //WriteAddr:开始写入的地址(24bit)
    8 H3 x# l2 Q, j+ a* N3 ?
  233. //NumByteToWrite:要写入的字节数(最大65535)* r! k9 e' K- u6 S; y: J) k( q
  234. //CHECK OK
    0 o2 C5 R2 p/ b+ y" z- v
  235. void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
    2 e* I+ t; u2 u% T  G
  236. {
    6 j9 \' A9 |. }0 g$ E9 r( E
  237.     uint16_t pageremain;$ {/ L1 C2 k/ d3 F* A8 S0 g% v6 v
  238.     pageremain=256-WriteAddr%256; //单页剩余的字节数
    * i. N; `. h6 R: M- a3 _* c+ v! M, S
  239.     if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节( D- o3 c& s" |6 V" v
  240.     while(1)3 m3 ^7 Z$ l& Z
  241.     {  i: n$ w& G: `6 U6 v* Z' I0 \, }7 p
  242.         W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);: T. ?$ N4 b5 N- S  j
  243.         if(NumByteToWrite==pageremain)break;//写入结束了
    & W/ T- |7 y: J1 R& ?7 }
  244.         else //NumByteToWrite>pageremain
    9 }5 O+ w' h" ?; R5 ]$ K. z
  245.         {
    , Z! Z  Q. b8 d' T3 E
  246.             pBuffer+=pageremain;
    ; r, o7 `, _. ?0 t
  247.             WriteAddr+=pageremain;5 t- Y- b( X! z
  248. * o6 H, N9 ~$ c% C9 q- j  a
  249.             NumByteToWrite-=pageremain;                          //减去已经写入了的字节数$ J3 ~; q+ Z) v% z; Z9 M# o% _# T
  250.             if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节4 L! g8 b8 n" I; S. j
  251.             else pageremain=NumByteToWrite;           //不够256个字节了
    3 X: Y  ]8 P- w% K
  252.         }, d0 }' y$ E# u. d9 A, K2 e+ s" G
  253.     };8 k8 u# P9 t- G) ?8 {5 o
  254. }( T1 f1 J$ {4 E' F  q
  255. //写SPI FLASH
    5 o/ Y4 O, d- r2 d
  256. //在指定地址开始写入指定长度的数据
    3 A5 w0 _7 |" y5 i* V( E
  257. //该函数带擦除操作!) `& B: [4 x7 r; T& R
  258. //pBuffer:数据存储区
    / ?' y; a1 j# \* X" r  M  }
  259. //WriteAddr:开始写入的地址(24bit)
    ) D6 ]2 @. n! S# I
  260. //NumByteToWrite:要写入的字节数(最大65535)+ C( _2 O5 E/ }0 H' r
  261. uint8_t W25QXX_BUFFER[4096];6 Y* v; Q7 X: \: V$ `
  262. void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
    & I4 |9 X" A! O0 I
  263. {  U$ W7 _1 o1 Y4 ^. a2 z- I
  264.     uint32_t secpos;
    ; E. Z% d, K2 p, b6 A3 ~
  265.     uint16_t secoff;* h: }3 |  U2 o4 R) P& C: P
  266.     uint16_t secremain;
    3 u6 `( {9 |, D
  267.     uint16_t i;: p6 c5 w* y/ y- G
  268.     uint8_t * W25QXX_BUF;
    3 p! [, h( ?5 V8 @4 x
  269.     W25QXX_BUF=W25QXX_BUFFER;
    # }' R- ?/ \8 p1 R- f6 V
  270.     secpos=WriteAddr/4096;//扇区地址  W8 V" t5 t" A$ I7 C
  271.     secoff=WriteAddr%4096;//在扇区内的偏移" o( V5 K0 e# M" `, ?; x
  272.     secremain=4096-secoff;//扇区剩余空间大小& Y1 `& W: x+ u, K: W' S7 M
  273.     if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节+ E. e, \2 }, |  _  T( q
  274.     while(1)
    * i9 b7 J! a! n( [! }- w4 |
  275.     {/ ]: {9 f3 f' [* a4 a1 Y
  276.         W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容" R0 J: ~5 t& Q5 I
  277.         for(i=0; i<secremain; i++) //校验数据& i9 T$ D& C* ^% ]3 N5 J
  278.         {
    - F5 w5 ^! w  ]4 W7 h3 z
  279.             if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除/ `9 ~- c6 H/ H+ N
  280.         }
    ' F- a9 R6 p( ?
  281.         if(i<secremain)//需要擦除
    ! a% l1 ^: M+ s0 I% o2 m5 z: F) g1 t
  282.         {$ i% y/ b- d( z. b. U8 f
  283.             W25QXX_Erase_Sector(secpos);                //擦除这个扇区
      O% e  y+ _+ Q0 p5 T. X2 n0 P
  284.             for(i=0; i<secremain; i++)                           //复制6 A- k6 j) }$ `8 U$ A- n' B2 h( D+ U
  285.             {$ v$ M5 h% ]. U7 M
  286.                 W25QXX_BUF[i+secoff]=pBuffer<i>;9 e5 i- w2 C% ^4 E8 r
  287.             }6 {8 v6 O3 x4 c
  288.             W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区
    ) @. T% M/ G5 \9 W6 i* Y. j

  289. - B. {1 ^, y5 ?, K4 Q
  290.         }. x$ y8 S. \; f' H: q; P3 h
  291.         else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain); //写已经擦除了的,直接写入扇区剩余区间.  F3 R- Y6 \, `7 G$ b5 b/ w9 E
  292.         if(NumByteToWrite==secremain)break;//写入结束了
    9 N- ^+ @4 G* |2 u
  293.         else//写入未结束
    ; s9 [7 A% k3 r& F8 [0 g
  294.         {
    7 b- n4 Y4 h! ~2 M
  295.             secpos++;//扇区地址增1
    & n0 o3 t: c- Q. I4 l
  296.             secoff=0;//偏移位置为0& d0 N' A2 h+ w7 t. Y7 |7 G

  297. 8 O5 h/ D  }! c3 r! |1 L
  298.             pBuffer+=secremain;                                  //指针偏移
    ; M1 g6 C3 `3 z* l0 A
  299.             WriteAddr+=secremain;                                //写地址偏移
    ) G% @' T9 S! M! u9 K, `8 E
  300.             NumByteToWrite-=secremain;                        //字节数递减
    4 ]4 _# x, P  _; P# r# y# h
  301.             if(NumByteToWrite>4096)secremain=4096;//下一个扇区还是写不完0 |# n( g2 Y) R8 B
  302.             else secremain=NumByteToWrite;                //下一个扇区可以写完了
    8 p4 @/ G. S' @& H  H! }  N" O
  303.         }
    4 V: Y2 a, O$ f' _7 \$ }
  304.     };* A  D. b9 H" a# q/ L0 B
  305. }
    ! c5 i1 U7 H" O! x& \$ [0 l+ k4 V' t
  306. //擦除整个芯片7 K0 u( y" G6 T2 g
  307. //等待时间超长...
    5 r9 j; Q. K7 Q8 g, z  F7 h
  308. void W25QXX_Erase_Chip(void)1 R2 n& O9 ]! |$ [3 e  Z
  309. {4 X( }: v1 r7 s3 \
  310.     W25QXX_Write_Enable();                                  //SET WEL
    * X8 d* z, v/ v
  311.     W25QXX_Wait_Busy();" I8 w$ b% S. H( s" _7 ]
  312.     W25QXX_CS_L();                                    //使能器件; f3 W5 q3 L* C0 T2 S% S
  313.     W25QXX_SPI_ReadWriteByte(W25X_ChipErase);                //发送片擦除命令; Y2 u1 h6 n. f
  314.     W25QXX_CS_H();                                    //取消片选3 x4 V2 Q0 y; a/ b, A0 e3 y5 {
  315.     W25QXX_Wait_Busy();                                                      //等待芯片擦除结束+ I1 X* A0 |+ b) A: j3 `
  316. }- z- N# M( A; d
  317. //擦除一个扇区
    , s/ X8 {1 S' ?5 u9 q0 ?) h% B
  318. //Dst_Addr:扇区地址 根据实际容量设置
    0 I7 J% U+ i' [: J& C0 e
  319. //擦除一个山区的最少时间:150ms
    ) B' U6 d" M7 M/ j& a( a* ~$ i
  320. void W25QXX_Erase_Sector(uint32_t Dst_Addr)  W/ s- F) ?- b- ?% n1 A- E. L
  321. {
    & n1 K7 N' e% s( ]
  322.     //监视falsh擦除情况,测试用
    7 I( }' M( ]9 B! C2 d0 n% r/ e
  323.     Dst_Addr*=4096;
    0 i; L# O* X# l$ x) N
  324.     W25QXX_Write_Enable();                          //SET WEL
    $ t2 Z6 @7 V/ @
  325.     W25QXX_Wait_Busy();& e; g" }9 y* s/ [0 J
  326.     W25QXX_CS_L();                                    //使能器件$ w; e6 g1 K7 u2 t+ x9 C  ^
  327.     W25QXX_SPI_ReadWriteByte(W25X_SectorErase);              //发送扇区擦除指令
    , e: c( m  v2 e% l; ?9 P1 W
  328.     W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>16));          //发送24bit地址( `5 x/ `* _0 |) X: e2 t0 d) U8 A
  329.     W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr)>>8));
    . V: A/ I* ]. Z- ^4 j
  330.     W25QXX_SPI_ReadWriteByte((uint8_t)Dst_Addr);. x; f. O3 F3 V# F
  331.     W25QXX_CS_H();                                    //取消片选
    + K  k9 U7 E  ~3 x9 O! @
  332.     W25QXX_Wait_Busy();                                                      //等待擦除完成& {( Z4 n1 q; ]! x
  333. }
    # w& E' L, g' q3 [6 F2 \9 n
  334. //等待空闲
    ' |# V4 y, `3 [7 m* J: I* m
  335. void W25QXX_Wait_Busy(void)
    5 A4 }% Z6 L7 |; n
  336. {, x7 ?( s: z4 L) ?0 V* o
  337.     while((W25QXX_ReadSR()&0x01)==0x01);                  // 等待BUSY位清空  V/ {' ?1 m( o
  338. }: Q8 l) U7 V5 m8 z' T# U
  339. //进入掉电模式$ B7 c9 A5 `' l+ L! ]) j4 @
  340. void W25QXX_PowerDown(void)
    $ E& E% ?* f2 t, ?* ^' y
  341. {
    3 n6 D5 a0 Q( h* b+ ^  F
  342.     W25QXX_CS_L();                                            //使能器件" N. a4 w6 S* O5 A- ?% [) Z
  343.     W25QXX_SPI_ReadWriteByte(W25X_PowerDown);        //发送掉电命令$ I/ W  t" C' X$ ?& u
  344.     W25QXX_CS_H();                                    //取消片选4 H* e9 Y! E6 f3 S1 g! M4 ]
  345.     delay_us(3);                               //等待TPD
    $ g, C0 q7 Y  Z+ S6 s; R, U
  346. }
    0 [& C+ V6 U2 z. z
  347. //唤醒
    - @( d; ~6 j/ h8 k6 L
  348. void W25QXX_WAKEUP(void)
    2 K4 x% R7 E4 I3 V: w
  349. {
    $ t. j: l& }! l: B4 z# y# G
  350.     W25QXX_CS_L();                                    //使能器件  ~+ `6 L* G: `6 S5 W) {
  351.     W25QXX_SPI_ReadWriteByte(W25X_ReleasePowerDown);        //  send W25X_PowerDown command 0xAB
    % _9 ~; _6 Q- E, C; B
  352.     W25QXX_CS_H();                                    //取消片选
    : r: `4 m0 y" @! X& c
  353.     delay_us(3);                                    //等待TRES1$ Y- R; v' F, X* c& g
  354. }
    0 v% e1 F- o, c) I2 U: V! H

  355. + m0 q4 z0 a6 c
  356. </i></i></i></i></i>
复制代码
0 G, k; q# f+ j$ }
赞 收藏 评论0 发布时间:2022-4-11 10:16

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版