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

STM32CUBEIDE(15)----移植兆易创新SPI Nor Flash之GD25Q64Flash

[复制链接]
STMCU小助手 发布时间:2022-10-20 19:14
spi概述
0 E* n  I* g" K# r6 i6 fSPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如 EEPROM,FLASH,实时时钟,AD转换器。
/ j3 X( n0 N9 ?% ~: {: AW25Q64 是一款SPI接口的Flash芯片,其存储空间为 64Mbit,相当于8M字节。W25Q64可以支持 SPI 的模式 0 和模式 3,也就是 CPOL=0/CPHA=0 和CPOL=1/CPHA=1 这两种模式。
) ^' H9 m, q, Q+ x* E" k! q& b$ }' q/ u* j$ J3 I" l+ \$ ]5 G
生成例程
, ^% F1 H4 e( b
使用STM32CUBEMX生成例程,这里使用NUCLEO-F103RB开发板5 X' S: ?! A8 |# o- E
- _, I* h# M1 z* Z
839757b637ee4ab69623fce326742df6.png
/ s9 u( ?- R0 J8 r& }; g, R: y  }9 R" ~8 q1 r
配置时钟树,配置时钟为64M。. f& e5 j/ l3 L" d$ N& m6 l* u' g
1 r- B  ?" [$ f3 x
360005becba24788aee6f547baae5b52.png % C9 w  p0 ]5 Z3 j* s  d& j+ d- g

1 b' H; Q) S9 ]2 Q- r查看原理图,PA2和PA3设置为开发板的串口。
0 g2 B: f' N. ?' \  x9 G) g- i( e
+ c$ `7 f) f0 f/ G1 E- g, a$ C  |
4c2181dbda8946e7b90c9e404d7fe75e.png + Y  F- d+ W7 \: f8 C
) `  m* n# k# L  k
配置串口。
: x; ?+ q, u2 S  t8 R
# P# ~7 T( v( C( S3 N
6fa28172f063490c9f66b66f1808ef96.png 8 C) R& E# M3 P) w( ]* G

" P; J: d1 C8 h! \5 B9 U由于需要输入数据,开启DMA进行接收。' y# C7 C7 ]3 ]& ^5 d
! e6 `; X! c( I+ y- L2 |" ^
f412f32d11f4428ab1f21fac63759508.png " t9 L# B7 ~3 a! F* h
/ s4 z% t* c% f9 W9 d; j- T. k
中断。# `1 @2 \7 k) V

# |+ g6 |; n! n) p4 C
31ebe8f4bd604fec9bfa0b087220b3e0.png   ~! R" w+ z1 X# _( E
, R" Z( ^& D; j( [& D1 t$ n* {
SPI配置
; _' b! ?- H4 ]  j) V在开发板中有arduino接口,配置这几个接口为spi。

1 n4 U, ~. K: t5 ?7 x% ]4 b3 z0 C5 q; @: P+ Z

, d& Z# x* A, u4 j 72bdb04b993d4c71900160ab38f4822d.png
* M) [7 y5 ^6 K: W) D, S
& a+ D) A9 l, \0 e  O( P本次实验使用的SPI与Flash通信,配置如下。
, t; K+ t: s7 F$ Y7 h- f/ y% I  s3 }SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。
! h" h  P& y* V6 J; K% F(1)MISO– Master Input Slave Output,主设备数据输入,从设备数据输出;
$ F! l3 H- x' P/ ](2)MOSI– Master Output Slave Input,主设备数据输出,从设备数据输入;
, X3 ~0 D1 T8 U6 l* V" A(3)SCLK – Serial Clock,时钟信号,由主设备产生;) q  F4 p8 a7 k- }( a
(4)CS – Chip Select,从设备使能信号,由主设备控制。8 w! o4 `$ G4 B$ K' K* q
! B) B( |  i/ ?" s4 e5 P5 S3 o
e066bc13ff35431789a0f629dc56c583.png
, n" k6 U; e( U8 m+ T( `1 b' w3 ~# u, c8 C
负责通讯的3根线了。通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。这就是SCLK时钟线存在的原因,由SCLK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过 SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,输入也使用同样原理。因此,至少需要8次时钟信号的改变(上沿和下沿为一次),才能完成8位数据的传输。2 T4 p5 O1 L. |
时钟信号线SCLK只能由主设备控制,从设备不能控制。同样,在一个基于SPI的设备中,至少有一个主设备。这样的传输方式有一个优点,在数据位的传输过程中可以暂停,也就是时钟的周期可以为不等宽,因为时钟线由主设备控制,当没有时钟跳变时,从设备不采集或传送数据。SPI还是一个数据交换协议:因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出。芯片集成的SPI串行同步时钟极性和相位可以通过寄存器配置,IO模拟的SPI串行同步时钟需要根据从设备支持的时钟极性和相位来通讯。
; {, Y: V& g* I9 U. p# @最后,SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。
. j) z) k7 ^4 d9 c) z  J4 e; q/ a0 J8 z7 \, Y- j% B
0518bf0da3df42a79291d95c298f9fed.png / g( e9 S2 W# l/ k, d& B

8 c/ p3 \; s* e- _其中,CS是从芯片是否被主芯片选中的控制信号,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),主芯片对此从芯片的操作才有效。这就使在同一条总线上连接多个SPI设备成为可能。: }( t  d3 P6 O
随便配置一个端口为CS片选,并且命名为CS。
# D% ~+ Y. @1 T! G2 x, j6 k& x( Z1 N3 S4 x
baaf5e9bdae84d68a8599ed26c05f5f4.png & J: z; g# `# ^* n; o

& S3 s: p  h  ^' P. y$ rNOR Flash! H7 _5 _8 P/ X# ]- |
NOR Flash是一种非易失闪存技术,是Intel在1988年创建。是市场上两种主要的非易失闪存技术之一。
3 A  R6 V' Q/ i2 e4 g3 {5 T以GD25Q64E为例,该 Flash为64M-bit大小,即8192K-Byte。
" r* R6 ]( X: F0 b) h& _8 `

" o2 _, x2 w9 |% I1 k

% J; g  u! n3 L) x! v* |9 a; M* V 2558b1096ae9468b92039c513af4bf4a.png
9 n' T7 c, X1 V( \7 T! k: [+ B3 r2 n
W25Q64将8M的容量分为127个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K个字节。W25Q64的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。
3 m* t( A/ _4 m. z9 \即4K16128=8192K=8M- r" [- h9 j2 `; E' a+ f4 U
0 E7 }% T' y3 h; \% O, o3 F& g
f95a474eaf814b508082a9605b54504a.png ' e! f# U2 Y# U; r

1 E" i+ G, R! ~: ^+ K" h- AW25Q64的原理及应用
% R& V' Y( y& _6 V6 m( ~复位初始化
5 G" z0 ?4 w3 {对于复位,需要发送0x66和0x99$ @- l3 d- {7 t! n/ g) p
8 ~1 a1 d. M" x$ q) H
8b2131d6a7a74015becf6dc6ffe5e2c3.png
5 ]) }& r" Q6 ~
. y* W$ E0 N4 G( Q代码中的初始化。% s# d5 f! s% ^8 G

. D& K: N3 O; a7 O2 g
  1. /* Reset Operations */
    " k; f2 C( N3 M
  2. #define RESET_ENABLE_CMD                     0x66
    5 }3 E# D) s* W8 O9 L
  3. #define RESET_MEMORY_CMD                     0x99) y( ^% h# p( M/ a" ~3 S+ j+ a5 H2 V
  4. /**; l* K: k# P* q# `5 g0 u# Q; w
  5.   * @brief  Initializes the W25Q128FV interface.
      I2 a  a/ I/ v* m" s3 G8 O
  6.   * @retval None  ]* v, z) l& a. H! u
  7.   *// A/ {+ q: M$ q0 x
  8. uint8_t BSP_W25Qx_Init(void)1 R' K: H. j' J' k
  9. { * h- F/ c8 H9 B5 @5 O$ C
  10.         /* Reset W25Qxxx */! i) L( H0 n6 J
  11.         BSP_W25Qx_Reset();
    $ i4 v: k: f4 ?) w1 b
  12.         4 T7 M  @) e. X
  13.         return BSP_W25Qx_GetStatus();, d, t# v! v; _$ b/ X
  14. }
    ( T+ |$ w7 d0 R# Y0 l  R8 G
  15. 4 L/ f6 z' J, z$ x4 b
  16. /**
    # X% o. y8 {5 z9 R$ ~, K
  17.   * @brief  This function reset the W25Qx.0 u# l" L( F2 w' X0 ?/ E% ~7 x7 ?: I
  18.   * @retval None
    . v8 _; y0 V% @+ D9 A) }
  19.   */$ v+ a& U% ~/ L; y! `/ |! I
  20. static void        BSP_W25Qx_Reset(void)
    / _; k! \2 v& }' C% ]. b# r8 h  U; B
  21. {
    5 y1 n$ D3 R* l  m! f
  22.         uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};$ T; |/ b4 v% ?) g5 k1 [7 w! Z; X2 a
  23.         
    2 _, E" Z+ o7 S" A  ^  s) X) V! R0 t. n
  24.         W25Qx_Enable();
    - _) c. E- Z9 ?8 ]- o. I  }
  25.         /* Send the reset command *// U9 O, d, K( }' [* r$ T1 Y) G+ ]4 D
  26.         HAL_SPI_Transmit(&hspi1, cmd, 2, W25Qx_TIMEOUT_VALUE);        
    0 {8 s  |& B* A3 E+ x4 E- E
  27.         W25Qx_Disable();' K1 N& W9 U% Q# W; O
  28. 5 G0 \( d, h0 N- t7 k$ @8 L- i
  29. }
复制代码
8 d6 \% E& j, N1 a5 a
b6587dfc4fcd4f4a8ca0d58f32bd0f3a.png
( s7 d: B) ~) s( U4 ~% _
# j8 i) I# ?; {+ P/ K! NID
0 \( p0 G" ?" P) ?* N对于兆易创新W25Q64,主要有三种查询ID方式。
/ _# v& ^) y; z  |  F
0 n) S( F; j- A/ U
a48ae7cccf1045c1ab70aa6ad37a32a1.png
6 ]( @- x0 R# N4 h0 U1 D& |' m# g: [) \! A& ^* _
可以使用90H查询设备ID,以判断是否是W25Q64设备。% O5 N0 j) q$ X, s+ I
: X2 Z$ Y# H2 c
1d515b4535034f138381e95e7dfaf268.png / j5 |. h; Z6 R& U
  1. . r3 x  }+ D; Y% B
  2. /* Identification Operations */5 {- {/ k1 s. A
  3. #define READ_ID_CMD                          0x9F; p9 v6 u5 C5 }9 ?
  4. /**
    % h( [0 b8 c/ b0 r* [& u
  5.   * @brief  Read Manufacture/Device ID.
    4 e* I) M* R& d' g) l& b  ?
  6.         * @param  return value address
    + E, K& j! R" `( V# j: ]& F
  7.   * @retval None
    8 Q. G0 ]" s/ B: T6 U+ b/ ^
  8.   */
    0 v, T4 H" A, t' Z) K
  9. void BSP_W25Qx_Read_ID(uint8_t *ID)+ {7 B7 x& H' h# l( p; ^  y3 B
  10. {& |! G& H; S9 ~- \! ?9 U
  11.         uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};
    # {7 ]% l9 U: k1 L: U0 Z3 @
  12.         
    * g- r  D$ v3 k3 ]. ^; ]- B: Z
  13.         W25Qx_Enable();$ X* a) ~- L5 S! ^6 J" M: \
  14.         /* Send the read ID command */
    4 V" l3 ]) S; {! ^3 o; d$ a
  15.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        
      o0 Q2 j; L  _+ F8 u) ?. B9 m/ P
  16.         /* Reception of the data *// |) ]: m5 p' {6 ^: z
  17.         HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);$ L, O2 ^9 W$ n' R9 V( W
  18.         W25Qx_Disable();
    , C5 l' z6 k1 m5 x8 w6 C% @
  19.                
    2 f" C4 r3 {# _0 _, s# `6 m3 G
  20. }
复制代码
# p2 u1 [* D0 h) q3 ^

1 `: [2 c3 J% d: ~( h2 x
e5f3e86b8a87496e942a4ea634b05f7c.png 8 k6 W  k' P8 u
( L' X" {6 J! l0 m( y
读取数据
" j5 o6 {5 w4 [$ E- f% Y对于兆易创新W25Q64,读取数据使用0x03指令,后面添加需要读取的数据地址。
/ t* W8 F' ~# B2 J  t! i数据可以一直进行读取,当不需要读取数据时候将片选CS拉高,关闭时钟SCLK即可。6 @1 ]2 v: H7 e  h: ]" R3 q

8 `( l) }/ N+ [  I, d0 D
b272600672cf45799b3e64f55e6aae0d.png * N3 D( R$ F3 L$ B' I

( H+ S( f0 h. t: g
  1. #define READ_CMD                             0x03' }- n# ~+ P9 ?% g

  2. $ ^9 b" k3 D' l+ M1 }- {3 I) c/ j9 Y
  3. /**+ }! c! _% s' T, y: h1 z
  4.   * @brief  Reads an amount of data from the QSPI memory.
    $ t! V. Q& V) E+ Q4 p1 C/ N
  5.   * @param  pData: Pointer to data to be read
    6 H0 |( l( w3 l& v* o/ O/ l
  6.   * @param  ReadAddr: Read start address5 u5 i0 G) |) x1 Z- }6 _0 Y
  7.   * @param  Size: Size of data to read    & F% ~! v' a, D( d
  8.   * @retval QSPI memory status
    ) I& e/ h1 g" O# Y& b
  9.   */
    $ V) \* u; V$ V4 }
  10. uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
    ' t2 l% n  l6 E' ~& }& P
  11. {
    $ h# R) f, [" V
  12.         uint8_t cmd[4];
    % ?, W' w5 s* r( ~2 L

  13. ( M3 \3 D5 O) Z) j0 e% v* R! k
  14.         /* Configure the command */
    5 T) V0 y$ T3 W7 @/ J
  15.         cmd[0] = READ_CMD;+ {( F  D; r2 q' c% }
  16.         cmd[1] = (uint8_t)(ReadAddr >> 16);
    9 s" J  X& ~- ^7 q  Y
  17.         cmd[2] = (uint8_t)(ReadAddr >> 8);* B) h/ o# f+ S& `6 i2 g! ~; Q
  18.         cmd[3] = (uint8_t)(ReadAddr);- R% p& O# l5 O$ B) Q! |
  19.         
    1 k& K" t/ _5 W8 z: p3 H6 x" S  @
  20.         W25Qx_Enable();
    + p7 c, F# r' B4 [1 M% h% i
  21.         /* Send the read ID command */
    ' ?9 d7 a) T+ H6 H
  22.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        
    # v: x. D. r' ~8 x8 m
  23.         /* Reception of the data */
    ! ]' m4 {9 H) A. ^2 k  y  o
  24.         if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK)
    4 K) a4 Y; S- H( g/ n' \4 ]
  25.   {' n" d/ f$ ?8 i% t: c
  26.     return W25Qx_ERROR;
    $ R4 N! @5 [4 s2 G. \* j8 N
  27.   }9 j3 P! P) f0 H9 d9 E, i$ l
  28.         W25Qx_Disable();+ Y; k$ X6 i) a/ {1 z4 X' ^! F
  29.         return W25Qx_OK;; w2 v4 R" L$ K3 l' t; u: {
  30. }& Z" [- M2 W% S. e5 S
复制代码
$ k1 l. a9 P* E$ z4 ~1 I9 z4 V, z
以读取10个数据为例子,波形如下所示。- i' b6 M+ g. b  M9 L/ q
7 n8 g; y0 W. U
  1. BSP_W25Qx_Read(rData2,0x1000,0x00a);   
复制代码
   
6 Y1 ?7 c, h$ Z
c3d6f7aad1d44480af9c864c7ac99306.png
' h& _! |0 |" i& e; g; u. S$ q/ k7 J' t
擦除扇区
, L/ i  h: k$ ^  e8 m$ t最小的擦除单位是扇区,擦除指令为0x20和3字节的地址。
9 B# U2 L/ A+ k# n& f# k; }4 t  w. P) b1 E3 {. |/ }4 b
3d02dfd6d21f45bb83426a95008cdbed.png 3 |6 ]4 I7 t7 M+ [5 ?" ^8 D

0 s$ l% X, k- X. p7 k
  1. #define SECTOR_ERASE_CMD                     0x20# y$ j1 f$ j; o9 |
  2. uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)
    9 q% u- C* v+ `
  3. {
    2 X9 j! v' m, c; b, l) v( e& k3 ^
  4.         uint8_t cmd[4];1 W" U2 b1 u( w! i
  5.         uint32_t tickstart = HAL_GetTick();
    ; m" V* d' Y" W. x
  6.         cmd[0] = SECTOR_ERASE_CMD;
    ( q' e9 {$ K, [  H4 ?  F
  7.         cmd[1] = (uint8_t)(Address >> 16);* z( c) J" F* R6 G0 C
  8.         cmd[2] = (uint8_t)(Address >> 8);
    ! [  c' ~8 F( e1 B2 Z
  9.         cmd[3] = (uint8_t)(Address);7 J3 M0 c& q6 x; s
  10.         
    1 C0 S+ {) v( O2 u4 D
  11.         /* Enable write operations */9 W# p7 ]/ X& o' A
  12.         BSP_W25Qx_WriteEnable();- m. }0 g* g- M* p  U4 ?- j4 j' V
  13.         
    ; V. c1 ]# }: A
  14.         /*Select the FLASH: Chip Select low */: R$ s$ A1 R) i" r
  15.         W25Qx_Enable();
    # x! p" \5 G  o& N
  16.         /* Send the read ID command */- @: k7 k- Y8 c$ s6 T
  17.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        
    & {( K5 ^, w0 T# h) W
  18.         /*Deselect the FLASH: Chip Select high */) @& W8 u/ L. j. `5 r2 ]7 K5 S
  19.         W25Qx_Disable();, E" I7 v' J+ K- I; f5 Y5 V, Z
  20.         
    + Y7 }2 U1 Z6 X/ @3 w6 K
  21.         /* Wait the end of Flash writing */
    + M( r5 K. W+ {6 L1 t% D
  22.         while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);. G" p) Y3 ?0 a
  23.         {
    ( d8 W- f! [+ o& o2 |
  24.                 /* Check for the Timeout */1 {, [4 _0 M; H
  25.     if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME)
    0 u9 a. j6 \( g7 ~  |% v3 Q$ @
  26.     {        ; t0 e) \1 [4 o' l- F" F! G
  27.                         return W25Qx_TIMEOUT;' F) p5 f5 }7 i$ F, k8 U4 Y: g% P/ C
  28.     }# h" i, ]8 b+ ^
  29.         }* i& y3 K1 g6 F. U* I: n+ g
  30.         return W25Qx_OK;7 ]- F! ]2 B& P& \9 f9 K8 t& U
  31. }
复制代码
6 s! r9 S$ o% t
% J9 a6 @; n! N! h: y6 z) J' j  _+ ?
834c52348abb435c80e75aa7c084fe7d.png
9 H& G4 H7 k$ {
* r  H( U" U- N1 ^- ]写数据4 w) a& y- I! E' D# I' U* k. r
对于写数据到flash中,使用0x02指令进行写数据,后面还需要指定24位地址,才能进行写数据。; C: a" K* E* E) l5 l+ {4 v7 n
9 H& E7 t8 K; q- _! t
08573995dfeb42a9afffabdeefe38f2b.png
* ~: W+ P/ Q( T  B: q9 ?. x& I/ c+ N. |6 H7 h1 o% w5 [" ^
  1. #define PAGE_PROG_CMD                        0x02
    3 J# d0 ^' j# X4 G% B" M4 ^
  2. /**
    4 F# N. r$ R4 T* W  i# I; h
  3.   * @brief  Writes an amount of data to the QSPI memory.3 j" X% t3 x% l: S# A* {
  4.   * @param  pData: Pointer to data to be written2 _& |( J8 @" C
  5.   * @param  WriteAddr: Write start address
    6 Q7 r( }' N+ n& S  R4 l
  6.   * @param  Size: Size of data to write,No more than 256byte.    / s+ q3 Y" P- n9 d) D, ?$ E
  7.   * @retval QSPI memory status
    % Y! n* r0 m' }- Y0 l
  8.   */8 @- r  S! O' w+ w# i' w
  9. uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
    ) G) v8 V! a$ g1 ]
  10. {( Y3 v2 w5 M6 P" I
  11.         uint8_t cmd[4];; T& O' `  L! P: A6 M
  12.         uint32_t end_addr, current_size, current_addr;- L5 ?% K! Z6 m7 S, c  [
  13.         uint32_t tickstart = HAL_GetTick();
      L8 Q& i9 D/ W) S  R
  14.         
    ( D8 @7 c; e" J/ m# M; U8 B7 k) `
  15.         /* Calculation of the size between the write address and the end of the page */
    ! Z) i; M0 M! G
  16.   current_addr = 0;, F) V/ @5 L6 L! J
  17. 9 p& L' t* H! a( F. `  |" d
  18.   while (current_addr <= WriteAddr)//判断地址属于哪一扇区开始/ V+ @- b! S' }/ q. \
  19.   {' E5 s2 g' I, W9 V9 {
  20.     current_addr += W25Q128FV_PAGE_SIZE;//0x100-> 256 bytes& l7 v% w* u: L% o# w7 m/ H
  21.   }$ G" F0 M/ _4 ?- o# D# O1 b/ j
  22.   current_size = current_addr - WriteAddr;# r3 z+ y" E" S" U0 O) I% m
  23. & l; f- P2 M* O: T. s
  24.   /* Check if the size of the data is less than the remaining place in the page */
    # K( O! q* \7 r  u7 J1 O5 \) u
  25.   if (current_size > Size)" P. j! L! U4 `) m2 m) Z( ~6 r
  26.   {' d$ j! Y! D$ z" V
  27.     current_size = Size;' a9 C, }$ ~9 R4 {1 Y7 D6 G
  28.   }+ e! m2 ?3 }. i) m' K

  29. / y: I6 R6 C$ T& i
  30.   /* Initialize the adress variables *///写入地址大小范围
    / M* ~3 P2 A  c' t) B
  31.   current_addr = WriteAddr;
    % c+ b# O: |; ^" H3 N  m2 U; O
  32.   end_addr = WriteAddr + Size;4 v# L8 p  U4 W4 K2 I
  33.         
    7 L8 ]% b. r+ R9 s' `( e
  34.   /* Perform the write page by page */
    2 r% |( A" \. `- P4 o/ z+ I
  35.   do
    + L: i- n9 L! z( O( P
  36.   {7 k6 ^! U- ~2 I' K& e
  37.                 /* Configure the command */
    2 B! A/ O" A9 I7 q& ^5 H/ J
  38.                 cmd[0] = PAGE_PROG_CMD;5 y5 p' x! c* P2 r; [
  39.                 cmd[1] = (uint8_t)(current_addr >> 16);2 r; S9 }0 C+ b. s9 h4 ?
  40.                 cmd[2] = (uint8_t)(current_addr >> 8);' ?6 b  x+ z4 D0 ]
  41.                 cmd[3] = (uint8_t)(current_addr);
    1 Q( U) [1 j* \8 z
  42. ( a$ e& F0 f; G. J( h
  43.                 /* Enable write operations */5 Z( C) z/ @: K, k% A/ Z
  44.                 BSP_W25Qx_WriteEnable();
    . {6 [. ?' |  r( ^/ H: z% q: l
  45.         # F! R; U( }- t6 b+ `: q
  46.                 W25Qx_Enable();
    & H: f" f1 ?+ e6 ]4 m! H
  47.     /* Send the command */; X( K( J; M9 S6 e, P9 `+ W: A. Z
  48.     if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK)
    4 E" A; e( {' q/ @
  49.     {
    ; l6 }: J! p' |; s3 Y$ a1 y
  50.       return W25Qx_ERROR;  M, P- `6 P7 ]( q
  51.     }) @& K, \  z: ]0 P, a8 t8 g( K
  52. $ o7 n( z% e3 a# x8 t. ?. z+ Q
  53.     /* Transmission of the data */$ m  v% z3 {' a
  54.     if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK)3 V4 W- h; q5 U; s# H5 V
  55.     {
    7 Z& ^# n+ G) g3 A8 [
  56.       return W25Qx_ERROR;+ f/ p; w% K4 L$ ]8 V9 R
  57.     }
    " h; ?1 A+ t: |
  58.                         W25Qx_Disable();- Q/ J3 h+ H- D1 `
  59.             /* Wait the end of Flash writing */3 b7 I7 I' {# {; C( S+ [* j/ n
  60.                 while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
    * B2 a  t$ T! p
  61.                 {( d: k: M  ]2 p+ q8 W  F
  62.                         /* Check for the Timeout */
    + u; `1 Q( y! g, q
  63.                         if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
    4 D3 P: [- [/ X
  64.                         {        
    2 C. K/ d# T; u1 |
  65.                                 return W25Qx_TIMEOUT;
    9 z4 ~" e! c% n( {
  66.                         }/ Y( g) r& v/ ^' V- `
  67.                 }
    5 @* l# v8 R6 Z6 X, o/ L5 e- n

  68. ! C) M+ R1 Q* C3 m
  69.     /* Update the address and size variables for next page programming */
    - Z6 y- `% ?2 \6 ^  J: V8 [" [/ V  X
  70.     current_addr += current_size;
    + C  F6 c7 N+ k
  71.     pData += current_size;% H; W, E+ b' T+ P/ P; ?
  72.     current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;
    1 j9 r% N" M4 B: U  Q8 j9 W( O! l
  73.   } while (current_addr < end_addr);$ n4 H0 O! ^8 G8 B

  74. 7 L) l/ m' [6 z- t4 X
  75.         - t. N' w7 z8 ~# N( f
  76.         return W25Qx_OK;0 j) U/ D& u" x% C. H# R
  77. }
复制代码

: H$ O" n9 F; |. F) n* P1 ]对flash的0x1000地址进行写数据,指令如下。
) }: g# [: r/ O- {. \% B; D
# G" l( X; D! }8 {4 {9 ~
  1. BSP_W25Qx_Write(wData2,0x1000,0x000a);
复制代码
0 D, C  _% ]0 |/ n* S. c
波形如下所示。
: n4 S& n2 H& @, d& S- V
. T) U( X  a8 s5 H/ m
394ce62c94db47a2875ff0cec94ffbda.png
6 ?3 r' _2 k+ U% b& V
1 @, g4 Y1 f1 @( P2 l4 EW25Qx.c
$ X0 O2 Q5 ^3 d, z0 n9 h
  1. /*********************************************************************************************************1 O, w  j9 q$ p" ^( C% p& M  p
  2. *6 E3 ?% ?  Y0 u  N& K7 J
  3. * File                : ws_W25Qx.c; n' D& s# `% G- i
  4. * Hardware Environment: 3 x! E; R& W2 h9 z6 m
  5. * Build Environment   : RealView MDK-ARM  Version: 4.20- X0 q2 \- R0 L4 d* k
  6. * Version             : V1.0; X9 W6 |1 g0 m0 j
  7. * By                  : ) b  l# Y  K  T) }
  8. *
    & l( E* B" O2 t9 A1 ~2 U
  9. *                                  (c) Copyright 2005-2011, WaveShare
    + o4 b' x4 U) @8 V' V+ `: O
  10. *                                       <a href="http://www.waveshare.net" target="_blank">http://www.waveshare.net</a>* ~5 U$ b+ X$ L! w2 g8 @
  11. *                                          All Rights Reserved6 p) {( J" \5 f
  12. *
    1 }) a% I" o  Y6 O) g. u
  13. *********************************************************************************************************/+ l: T4 r3 \+ {8 j

  14. ( \  ?4 O7 R7 b, l& G# p9 J
  15. #include "W25Qx.h"
    + b: e0 v, p7 V' Q$ P

  16. * Y  I' c4 `# {) Z$ d; b; Z
  17. /**+ y: D. E3 ?0 L0 w6 H
  18.   * @brief  Initializes the W25Q128FV interface.$ N, E5 z7 l5 e( s
  19.   * @retval None* v# ~7 m* M" S- H
  20.   */3 ], m' X% o, f* e
  21. uint8_t BSP_W25Qx_Init(void)4 w7 t1 ]9 @) {, I; N& \
  22. { + j/ p# q& u* {" F
  23.         /* Reset W25Qxxx */$ B) j- A; Z# ^# c& X
  24.         BSP_W25Qx_Reset();- j) V+ C+ }% w) p/ G
  25.         - W; p. l6 L3 Y
  26.         return BSP_W25Qx_GetStatus();' g" ^$ h" \, f+ F9 J) v
  27. }1 \) |9 z& v* d& [: z) K9 X% d
  28. ' b6 ?/ X- K, W' F
  29. /**
    + b, K# Y1 N" ^/ k0 h0 i) {7 t- g
  30.   * @brief  This function reset the W25Qx.6 Z0 Q6 c' X& u. _2 {
  31.   * @retval None
    4 F3 t4 a& y2 V; u% N( u
  32.   */. z' \. g2 a6 j4 V7 A1 ~* @; m
  33. static void        BSP_W25Qx_Reset(void)
    / N/ ]7 c  }/ p+ S. |
  34. {3 l( R- l1 I2 ~3 V% d
  35.         uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};: d- r+ r) ~. E$ t, Q
  36.         
    3 c% S3 ^$ K& p
  37.         W25Qx_Enable();* Z) H/ m0 a# B0 ?
  38.         /* Send the reset command *// o" p) T+ `3 J8 [. c" q
  39.         HAL_SPI_Transmit(&hspi1, cmd, 2, W25Qx_TIMEOUT_VALUE);        
    + ^, Q1 X; t0 |- R" z, ^
  40.         W25Qx_Disable();' u' b1 n: r) }: x

  41. 2 F; i8 b$ q2 h; S
  42. }9 }# m! z7 o% z' q- |

  43. 7 Q9 v3 |) @8 R: }' K( r
  44. /**
    8 O' }$ u' A& m* h) j, E
  45.   * @brief  Reads current status of the W25Q128FV.
    : o9 A) c6 q; Z% t
  46.   * @retval W25Q128FV memory status
      z3 c8 z, |& G: n( W6 p
  47.   */
    % B& F. N! @! B: n$ j
  48. static uint8_t BSP_W25Qx_GetStatus(void)) N6 k2 d5 L8 X  K; ~! @, [
  49. {4 U  P0 P! \+ f! K
  50.         uint8_t cmd[] = {READ_STATUS_REG1_CMD};
    ; q! c' a+ P. C- L. O  g. F+ |
  51.         uint8_t status;6 B. n9 M% M4 U: X6 M
  52.         . F: L: ]1 p( {8 h' j
  53.         W25Qx_Enable();5 C. n& K5 Q% g2 o5 I6 v) k
  54.         /* Send the read status command */
    ) f3 {, G' a. E3 h
  55.         HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);        
    * @3 t& H6 q& \( P8 }
  56.         /* Reception of the data */7 Q# Z/ I4 k1 B/ B& c1 R$ {
  57.         HAL_SPI_Receive(&hspi1,&status, 1, W25Qx_TIMEOUT_VALUE);% o/ C" k$ j& m! h
  58.         W25Qx_Disable();" d  j6 \' N& L% D8 w% G
  59.         
    7 P& L% Y1 r1 Z! @
  60.         /* Check the value of the register */
    " E$ j& Y. B  U* Q3 q9 s% ^  D! w/ l
  61.   if((status & W25Q128FV_FSR_BUSY) != 0); R  Y7 m( W5 t& ^# R  B
  62.   {
    ' N3 Z$ v0 |2 T8 R- B' e
  63.     return W25Qx_BUSY;
    ! k1 q2 A2 @* _/ }! v& P. N
  64.   }- a. \2 F  O& z0 k' ^$ O
  65.         else
    - J: X& S" n& U( w  `# E! `  a! K
  66.         {3 r. m& t; V2 a) F- G
  67.                 return W25Qx_OK;
    ' |+ W( n7 i3 j6 g
  68.         }               
    " [7 E# M2 P: h/ O4 [
  69. }0 J5 g' ]( g! H. Y) _% b" S

  70. % H6 k/ q3 M8 d: P
  71. /**. ~/ i8 Z6 @3 q" w% d
  72.   * @brief  This function send a Write Enable and wait it is effective.
    & U+ B( y2 F. z6 \
  73.   * @retval None
    7 b! N( N2 F& }& _8 O
  74.   */
    : G' P! d) u" Y
  75. uint8_t BSP_W25Qx_WriteEnable(void)
    " M  f& h9 z4 v
  76. {% Q5 ^" e* C# P5 |# Y# X5 Y
  77.         uint8_t cmd[] = {WRITE_ENABLE_CMD};7 u  i4 K  b0 |. ?
  78.         uint32_t tickstart = HAL_GetTick();
    - Y2 r5 C" ^3 \& w

  79. 0 Y  ?: w! k6 x
  80.         /*Select the FLASH: Chip Select low */
    ; @, C4 f- N1 Q8 h- V% y
  81.         W25Qx_Enable();7 N$ {. X) h; F
  82.         /* Send the read ID command */
    5 O" `$ l. [1 G  Q; e
  83.         HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);        
    - }+ ^" b* k- t+ P; t; u, H! w
  84.         /*Deselect the FLASH: Chip Select high */
    ) L9 v. v6 M; N2 F+ h
  85.         W25Qx_Disable();
    1 x9 Z4 v* |0 A% Y
  86.         
    + _% |1 @  ~0 w8 o- I/ B. |& g" t* F
  87.         /* Wait the end of Flash writing */
    ! m; r! f, o5 T. D
  88.         while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
    , c8 J$ B# A6 i; T
  89.         {" m) ~9 v( M" S+ C. x
  90.                 /* Check for the Timeout */7 ^' H% U) D! V$ P
  91.     if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
    $ C3 E& P. M4 J+ t
  92.     {        0 O+ O8 O* ?4 ^$ q8 f2 J3 h
  93.                         return W25Qx_TIMEOUT;
    3 \% y* o4 o: P9 U& ]; r* d9 T9 y- y
  94.     }
    1 `, l6 b$ ~$ q" r
  95.         }  Q0 ~2 B- R) Q* H; n( A; u
  96.         
    8 o2 [$ }( s6 ?/ e7 y
  97.         return W25Qx_OK;
    $ J+ k6 p$ G" t+ r- r# H! L
  98. }
    ) k2 I: Q4 k0 \! v  \

  99. 6 t1 [+ W6 q! N4 h
  100. /**
    3 D4 f. W- M# e( @9 H1 @" _) s0 L
  101.   * @brief  Read Manufacture/Device ID.
    * o  c6 C/ y  c- v6 n% T% Q& w% t
  102.         * @param  return value address
    3 d! i6 y. j/ _: J! |- P( i: h' b
  103.   * @retval None8 q9 e4 l6 r2 P" H  e' p) E
  104.   */
    9 \8 _% y3 N# A7 o. G$ O1 v
  105. void BSP_W25Qx_Read_ID(uint8_t *ID)6 c" d9 L" G3 M, ~
  106. {  ~. S8 ]% D' ~7 a% w. @0 c
  107.         uint8_t cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};
    8 o" B) O6 f3 M$ [
  108.         
    . e: I6 V- B6 _1 Y) l9 ?6 W1 w# s' X/ l
  109.         W25Qx_Enable();
    $ c0 o9 `( J2 W/ u1 `% T; ^: M
  110.         /* Send the read ID command */
      X% m7 V0 n) D
  111.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        % L8 C: [& l5 J5 ^5 ~6 Y6 u
  112.         /* Reception of the data */
    6 J2 e* a1 Q# x. h- W$ N
  113.         HAL_SPI_Receive(&hspi1,ID, 2, W25Qx_TIMEOUT_VALUE);. S) I& _3 C# n# c
  114.         W25Qx_Disable();3 Q3 q# U; c1 b+ g" G4 D
  115.                 " }* t/ Q' ?/ [: r% s
  116. }& r' B. i0 Z1 n. ~- |
  117. # r2 u! C; Y4 P4 G2 S5 [; P
  118. /**
    / Y5 d1 h4 Y  ?$ Y# v/ R2 D
  119.   * @brief  Reads an amount of data from the QSPI memory.
    / H, Q: P) T! a1 o3 o8 |/ F" L/ [# C
  120.   * @param  pData: Pointer to data to be read
    / b% ^2 l6 s4 @) {% _
  121.   * @param  ReadAddr: Read start address
    * b( F/ Y; c  A' d8 ^  s6 I
  122.   * @param  Size: Size of data to read    ' f" |$ a8 i9 {3 O! t
  123.   * @retval QSPI memory status1 m! ?$ n& d$ B! R
  124.   */- i5 i* e2 e1 H+ _! B  l  M6 F
  125. uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)0 v% ~3 f6 M1 v5 P" m
  126. {+ H+ o- M+ N8 K. u" w/ p
  127.         uint8_t cmd[4];
    - P! j- t  ?' j: x; }  F, W
  128. 2 b4 \8 U5 w- o: s
  129.         /* Configure the command */. O* F. z5 J' b
  130.         cmd[0] = READ_CMD;
    * a! R  m/ f5 T& s0 W! Q
  131.         cmd[1] = (uint8_t)(ReadAddr >> 16);$ F% h; F2 R/ H9 _
  132.         cmd[2] = (uint8_t)(ReadAddr >> 8);
    4 [( y% ?$ E* o8 p
  133.         cmd[3] = (uint8_t)(ReadAddr);
      X  D7 x& ]+ l
  134.         
    ; K: d* Z+ S% @# p
  135.         W25Qx_Enable();, Z  V& w2 P5 G+ Z' R
  136.         /* Send the read ID command */
    % c, {0 Z0 _2 P. X
  137.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        
    ! D! I2 C/ s8 c! ?4 t0 N
  138.         /* Reception of the data */3 C3 ]+ V) j1 @# x/ R5 t( P
  139.         if (HAL_SPI_Receive(&hspi1, pData,Size,W25Qx_TIMEOUT_VALUE) != HAL_OK)+ C/ |: ?8 T3 G; b0 N
  140.   {
    - M4 ~% e$ _( {9 J4 \3 i, C" W
  141.     return W25Qx_ERROR;
    ! I4 W/ G: Y7 m' ~5 M
  142.   }& P4 g& t5 V) w* v$ m: c9 P( r- Y$ U8 X
  143.         W25Qx_Disable();! b8 D2 v+ ]' ^  I: ]  E4 ]1 |
  144.         return W25Qx_OK;8 L/ k- D6 {4 S4 T2 h, u
  145. }
    4 G2 F! ~1 R& x3 B

  146. - i& A: o: |$ S" G9 h" k) y
  147. /**
    ( H% g; ?2 U, A3 ^3 L) s4 @, ^
  148.   * @brief  Writes an amount of data to the QSPI memory.
    0 Z& {! f* I' @/ ^) R
  149.   * @param  pData: Pointer to data to be written
    * e' q$ p  \+ L  Y) a, a" r
  150.   * @param  WriteAddr: Write start address4 ?5 r5 f- i, h0 n! F2 K
  151.   * @param  Size: Size of data to write,No more than 256byte.   
    2 K( u6 W& {) Q
  152.   * @retval QSPI memory status
    - P& P# k! |! w: C- n5 T
  153.   */0 j3 D  ?& J5 D! O7 k1 }7 n9 I
  154. uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
    9 o  Q: t6 ?0 F; G. ~/ h
  155. {4 G% R. g5 z! w5 ~3 \/ i
  156.         uint8_t cmd[4];1 g" t$ G0 a$ H6 Q+ k8 G* ?
  157.         uint32_t end_addr, current_size, current_addr;
    1 t. s$ H7 r8 u2 o, }$ ^1 V7 c
  158.         uint32_t tickstart = HAL_GetTick();! J8 p- i( l% z+ S! t
  159.         
    $ [; b1 Q7 ~5 ^+ z. w" C
  160.         /* Calculation of the size between the write address and the end of the page */
    % j, R. d2 ]. N& O5 i: Z
  161.   current_addr = 0;1 M* E1 _' a* U# O/ ^' C0 L
  162. ( c0 ?: ]4 S8 y: q" D6 n/ D
  163.   while (current_addr <= WriteAddr)//判断地址属于哪一扇区开始  }9 r# L3 \+ _% S2 v
  164.   {; v$ v+ M; ~7 z* k3 j
  165.     current_addr += W25Q128FV_PAGE_SIZE;//0x100-> 256 bytes
    7 k9 w& I, K9 I
  166.   }
    " r( V6 C1 s. O$ a# V
  167.   current_size = current_addr - WriteAddr;
    7 u+ A, Z/ `+ W. B; h- A1 U
  168. 1 I4 Q. h& G& ~. t
  169.   /* Check if the size of the data is less than the remaining place in the page */0 m! y) z1 @: E: w7 H$ S
  170.   if (current_size > Size)
    7 h' X& h% K' g8 T5 O
  171.   {. z3 @0 B& ]6 X) L: F; Z3 u- z' \
  172.     current_size = Size;
    7 k2 K4 t* ^# l$ Z9 h2 m
  173.   }7 E0 x; i% Z7 J& s( l

  174. # m' H0 R1 f# Y5 f1 H0 P
  175.   /* Initialize the adress variables *///写入地址大小范围
    4 g: H: J& U- s
  176.   current_addr = WriteAddr;( X3 A' @6 ~; C$ ^
  177.   end_addr = WriteAddr + Size;" f7 J0 [3 O, ?; M
  178.         
    . D/ j' r) Z6 C, y! J4 w, l4 Q, ]: J
  179.   /* Perform the write page by page */6 }, ?+ I+ @+ ~( Y
  180.   do
    7 e% p. v0 d! ?! d1 ~( I; a
  181.   {: H+ w9 `* N  s6 c( A" d
  182.                 /* Configure the command */
    0 c$ L7 r! ^! ?( H, a, l
  183.                 cmd[0] = PAGE_PROG_CMD;/ c" U- x  i$ e" n
  184.                 cmd[1] = (uint8_t)(current_addr >> 16);
    0 I) Z% Q! @3 h# L3 S, [
  185.                 cmd[2] = (uint8_t)(current_addr >> 8);
    2 z2 S$ l2 H, K4 n( H2 B) X
  186.                 cmd[3] = (uint8_t)(current_addr);# h+ W( l( F0 Z; M# w" c
  187. ; a0 e$ e6 K& X+ p" a
  188.                 /* Enable write operations */- V. p% [, {8 E& G1 F
  189.                 BSP_W25Qx_WriteEnable();3 I0 H  f! N% W% o, H* v6 Q8 A
  190.         
    / c: ]/ b) _9 w
  191.                 W25Qx_Enable();( J# h0 V+ }# I4 @; Q. N" P
  192.     /* Send the command */
    + j* F! p# p; p
  193.     if (HAL_SPI_Transmit(&hspi1,cmd, 4, W25Qx_TIMEOUT_VALUE) != HAL_OK)
    ! [- v' H/ M1 N
  194.     {
    8 R, u& W  c' ^' g0 Z
  195.       return W25Qx_ERROR;
    3 i) C. O; L9 y$ {
  196.     }
      r$ x8 `8 x+ Q# L) h4 f
  197. 0 Y, K, ?) H* _9 E, E
  198.     /* Transmission of the data */
    0 K6 f5 j5 x! {4 J. s% U3 \
  199.     if (HAL_SPI_Transmit(&hspi1, pData,current_size, W25Qx_TIMEOUT_VALUE) != HAL_OK), x8 U% Z" D( ?# j% Z
  200.     {0 W7 i- W7 f, r( A6 W/ m1 w$ y
  201.       return W25Qx_ERROR;
    6 r# x  i+ ^# O9 @
  202.     }+ I+ c9 m+ G5 M, K! ]
  203.                         W25Qx_Disable();
    ( c1 d6 f2 |5 E+ Y
  204.             /* Wait the end of Flash writing */
    7 E; v8 d2 [  }$ G
  205.                 while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
    & v. m# `8 @1 t0 ]# V7 U
  206.                 {1 o7 R3 x" ?6 X8 R+ H
  207.                         /* Check for the Timeout */1 h8 f8 Z: W  ^& a2 G: }% |! l
  208.                         if((HAL_GetTick() - tickstart) > W25Qx_TIMEOUT_VALUE)
    1 k. u  _' G, `4 n, @; ]
  209.                         {        
    : y9 q5 ~( d% S
  210.                                 return W25Qx_TIMEOUT;0 H: s  U1 D) X4 t, ?
  211.                         }, h; I# y5 }  j, S5 W
  212.                 }
    0 y) S  _/ V4 d  i3 N

  213. 3 T3 M1 y! d; {/ l
  214.     /* Update the address and size variables for next page programming */0 E0 g9 W4 L- l8 |6 k
  215.     current_addr += current_size;& d" V" w' A8 }7 ~0 p
  216.     pData += current_size;& Q; o# k) A, u4 y& a$ S
  217.     current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;
    9 M  i, t% d7 {+ }
  218.   } while (current_addr < end_addr);. c, u  I% ~- p7 i) U# r

  219. ) k+ N, E* E6 F: E1 w7 n0 J
  220.         
    # S0 m9 T/ J' }. f: o4 d5 ~+ s* k8 [- y
  221.         return W25Qx_OK;
    0 B2 I6 M  v- M4 B( c+ n3 [
  222. }$ t& O1 V1 i' l! v& `
  223.   F1 \, V3 a6 [2 n. E* [
  224. /**
    * U. A# o& I7 U+ [: b
  225.   * @brief  Erases the specified block of the QSPI memory.
    / W' m! y0 g" b4 I9 x9 }
  226.   * @param  BlockAddress: Block address to erase  / o9 T1 _4 O  p! Q  w
  227.   * @retval QSPI memory status
    0 N' T7 ?3 X% ?4 ^% o
  228.   */
    % I+ a, z, q5 i* n
  229. uint8_t BSP_W25Qx_Erase_Block(uint32_t Address)6 s( h5 k7 @1 v% ]* Y
  230. {) x: V2 ^, M) u9 ]- J' F) H
  231.         uint8_t cmd[4];
    5 _% b, Z( u; Q% y" M  c
  232.         uint32_t tickstart = HAL_GetTick();
    " u% ~' u/ n: d& Z
  233.         cmd[0] = SECTOR_ERASE_CMD;
    " r! ?! I) f& L6 y7 w) f1 `
  234.         cmd[1] = (uint8_t)(Address >> 16);6 i- I) Z" V0 |7 H: S" |
  235.         cmd[2] = (uint8_t)(Address >> 8);+ c$ I0 B5 P" s) I2 v
  236.         cmd[3] = (uint8_t)(Address);
    / A& U/ R7 Y1 ?- p; z/ L
  237.         8 J" m: T5 |; T( _4 w6 y
  238.         /* Enable write operations */
    ' p7 k; \5 [9 T' j6 ~
  239. //        BSP_W25Qx_WriteEnable();
    9 v1 z0 y; j8 }# g
  240.         + X- O6 |! J9 b# k3 C' y
  241.         /*Select the FLASH: Chip Select low */
    - C' P0 l6 U' }" p
  242.         W25Qx_Enable();. l0 `& m( M  |  l5 n! M, p
  243.         /* Send the read ID command */3 L! P1 [6 x, \5 H, ?! ]3 R) O
  244.         HAL_SPI_Transmit(&hspi1, cmd, 4, W25Qx_TIMEOUT_VALUE);        , p9 _. Z" e7 ?
  245.         /*Deselect the FLASH: Chip Select high */) ^6 d+ ~* s7 Q8 N1 H
  246.         W25Qx_Disable();& e0 [$ F% j& f0 e; {5 i
  247.         . v, I! C$ k7 w! O2 u3 Z  R
  248.         /* Wait the end of Flash writing */" a9 r6 l8 J0 C6 B& h
  249.         while(BSP_W25Qx_GetStatus() == W25Qx_BUSY);
    3 X  R4 ]2 V; o3 D% [+ J* _& L
  250.         {
    - ?% v7 r$ ~9 e8 z0 r
  251.                 /* Check for the Timeout */* b& B" U+ K1 w( S7 X
  252.     if((HAL_GetTick() - tickstart) > W25Q128FV_SECTOR_ERASE_MAX_TIME)
    7 |0 `( n& F8 U
  253.     {        ; I  b$ N. K, H; _; P# Y
  254.                         return W25Qx_TIMEOUT;4 Z( Z! c: n& T
  255.     }) m- J. _- B- @3 ^% y: _
  256.         }
    5 e" Y" ^# L% N; t; J$ H
  257.         return W25Qx_OK;# x' T8 S* N0 r7 s4 @
  258. }
    ( J' r7 g, y% W; \( c. r
  259. : Y4 w1 M: S9 h: Q: n% w- G; O
  260. /**
    ( V# J) i: X% _6 U; x" J/ r- G
  261.   * @brief  Erases the entire QSPI memory.This function will take a very long time.) P' u( {) f9 @; `+ V+ p: l4 R
  262.   * @retval QSPI memory status
    * G9 P. O5 _6 n) [* N( Z# {& q
  263.   */
    6 A/ i) j. J- H1 H$ T
  264. uint8_t BSP_W25Qx_Erase_Chip(void). n# E  A* Q! [7 w
  265. {
    - n6 }& ^) u: V/ h" M
  266.         uint8_t cmd[4];
    ' r6 i; ^9 H* e0 c0 t2 E/ T
  267.         uint32_t tickstart = HAL_GetTick();1 L+ M% G+ ~6 P9 k! M
  268.         cmd[0] = SECTOR_ERASE_CMD;0 Y% q  `$ y% w0 S8 K8 _  f
  269.         2 L! r# T8 z% p' l) t' ^) y
  270.         /* Enable write operations */+ \2 t! s* d. l  p
  271.         BSP_W25Qx_WriteEnable();# ?3 ^  X5 I' z$ j
  272.         " _4 O) w$ x, `/ X
  273.         /*Select the FLASH: Chip Select low */0 j2 L4 V: j$ K+ b0 r- m
  274.         W25Qx_Enable();6 B# {3 W; O3 @
  275.         /* Send the read ID command */
    6 L. E: w, B' V: f, \
  276.         HAL_SPI_Transmit(&hspi1, cmd, 1, W25Qx_TIMEOUT_VALUE);        
    : I# ?4 A+ t5 l- @5 f- x% ?- ^' m$ \0 i
  277.         /*Deselect the FLASH: Chip Select high */
    4 H0 D1 R* y/ W/ F: j: O
  278.         W25Qx_Disable();
    : }" s7 u  V5 J) M7 h  O: x
  279.         
    3 j' x/ P+ s. V8 H$ A- V
  280.         /* Wait the end of Flash writing */# k* B4 V* T9 V8 a3 h1 m& E) k
  281.         while(BSP_W25Qx_GetStatus() != W25Qx_BUSY);. ]# o7 b3 A( @* S
  282.         {8 n, e& o# j! C0 d
  283.                 /* Check for the Timeout */
    ) a. l1 K4 T, ~3 R. r
  284.     if((HAL_GetTick() - tickstart) > W25Q128FV_BULK_ERASE_MAX_TIME), D5 U& [, V' w7 O8 d& Q( n
  285.     {        1 F9 S( e0 p/ Y7 [, c
  286.                         return W25Qx_TIMEOUT;
    + O1 v. P( A9 ?! Y9 P) y2 ?. l
  287.     }' S5 J9 M- S* O2 i1 Z4 k
  288.         }$ m4 c2 ]5 R% d$ `8 E8 S& J
  289.         return W25Qx_OK;. R  y7 L  W, f
  290. }
    9 a: |, u" W* o4 C" w, N% i/ z; j
复制代码

* K; m4 F  s# {3 |* k9 XW25Qx.h  Q) c3 N" U2 u) R0 L8 C
  1. /*********************************************************************************************************7 Q5 e$ `' l- n+ O8 n& Y
  2. *
    3 [& Q* U: T$ N- v: q
  3. * File                : W25Qx.h
    6 D3 }3 B) P2 ~9 x6 z( }
  4. * Hardware Environment: 2 b9 W: L; y# N# A: D
  5. * Build Environment   : RealView MDK-ARM  Version: 5.15
    # f# T: ~3 u" T
  6. * Version             : V1.00 o9 i/ v1 Y* Z- i0 J# O# c
  7. * By                  : ) o- _  b1 U) {. t- g! b' {$ d
  8. *
    * H! j2 @1 f% }: Z0 ?
  9. *                                  (c) Copyright 2005-2015, WaveShare3 ?; n2 W, \9 H
  10. *                                       <a href="http://www.waveshare.net" target="_blank">http://www.waveshare.net</a>
    8 U0 r1 h$ K6 G
  11. *                                          All Rights Reserved
    ) R6 |9 R  ]9 {! [: P* T$ p+ [9 Z
  12. */ q2 Y/ n: j0 R& P$ x2 J
  13. *********************************************************************************************************/
    , t) m6 _* L; `6 C: M
  14. /* Define to prevent recursive inclusion -------------------------------------*/
    1 \* }3 K0 |7 j* E
  15. #ifndef __W25Qx_H
    # N; i% j, G# r9 y3 u, t) F
  16. #define __W25Qx_H( i0 f5 j! j  C" z  g+ a* c

  17. - D0 [9 R3 e8 M0 U, x/ q
  18. #ifdef __cplusplus
    ( W  T) k- ?5 I8 O. b% g
  19. extern "C" {6 ?% I7 ?: e* F  x
  20. #endif % [, x8 w! F6 h( ~/ G. t: h
  21. # a& X# `$ Z6 e' N  k
  22. /* Includes ------------------------------------------------------------------*/. o6 A" h: b- @( v$ N0 e, k: [
  23. #include "stm32f0xx.h"
    / c3 P6 F& }( y
  24. #include "spi.h"  S# |! c* ^" T' ]: g# }
  25.          . V- v1 y1 m# d7 g
  26. /** @addtogroup BSP% [, O3 D! M% B8 C! N6 m# J
  27.   * @{" s. A! s" ~9 p8 G
  28.   */ . P$ a+ l5 F. T- r7 ]
  29. / |6 c1 {2 j) [/ J
  30. /** @addtogroup Components
    " e$ G' g: b$ T# j+ w! ]
  31.   * @{- h4 L, y4 n% d6 Y8 ]' ?7 b, [
  32.   */ ' `, T# }% A" ~; Y
  33. + p  y5 k) r4 u2 P1 N6 _, |% a. K
  34. /** @addtogroup W25Q128FV
    5 X; E, B& {6 \2 |
  35.   * @{
    - |/ @" V( Y7 |" R3 r
  36.   */( X9 u7 k# K  O& ]
  37. ) V" |$ L2 r) w: Y  h
  38. /** @defgroup W25Q128FV_Exported_Types
    : @3 O: j, p- T! p7 J% b
  39.   * @{
    / B" h0 K% [. t1 Q9 }: _
  40.   */
    # L" |4 ^7 q# [3 O1 y8 r7 t2 ?1 J

  41. # H. F! H7 p; r6 n1 m! e+ T
  42. /**# e9 ?; M* I, X0 C. l" x
  43.   * @}' f7 k: ~8 z$ x- L8 ?: T
  44.   */ $ F4 ~  @8 e* |0 k7 l5 q! `

  45. : F5 c: q6 J7 L* h5 V" E8 a
  46. /** @defgroup W25Q128FV_Exported_Constants
    6 A& j% {% f& T7 T( H0 T
  47.   * @{
    ( o; Z5 {: n. e" N
  48.   */: u1 j) U% l" Y
  49. 7 b9 q2 K0 V: m
  50. /** ) U% U% k% x; f1 z4 L4 Q% f' u
  51.   * @brief  W25Q128FV Configuration  
    & H& ]& E& K$ @! ?# N3 u
  52.   */  
    8 w' F+ k1 U3 N% d( @
  53. #define W25Q128FV_FLASH_SIZE                  0x1000000 /* 128 MBits => 16MBytes */
    9 m# e! @! t3 d/ x+ `& G& K! U
  54. #define W25Q128FV_SECTOR_SIZE                 0x10000   /* 256 sectors of 64KBytes */% c( W: C; e1 J2 E/ Y
  55. #define W25Q128FV_SUBSECTOR_SIZE              0x1000    /* 4096 subsectors of 4kBytes */$ ~. U" ?) S& N
  56. #define W25Q128FV_PAGE_SIZE                   0x100     /* 65536 pages of 256 bytes */
    " v. M, N" l- J5 A& q  Z4 O, W
  57. 6 ~  ^: ~  [$ I1 g/ H
  58. #define W25Q128FV_DUMMY_CYCLES_READ           4
      P: z( \: _+ ~- P) E6 B" z2 X
  59. #define W25Q128FV_DUMMY_CYCLES_READ_QUAD      109 W" L; W, B/ n
  60. 9 d/ M3 W6 t0 Y  Q
  61. #define W25Q128FV_BULK_ERASE_MAX_TIME         250000# K+ {# m; X0 q0 b6 R3 ]* d
  62. #define W25Q128FV_SECTOR_ERASE_MAX_TIME       3000
    6 A7 c- E2 \4 h; ~5 t! h  F
  63. #define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME    800" m& m9 Q* j$ f
  64. #define W25Qx_TIMEOUT_VALUE 10008 a! O/ w8 K8 N0 V6 Y) _6 g+ X$ m" A

  65. . G! n$ o# J" A
  66. /**
    1 }& l' ~1 N% o. i+ i1 u
  67.   * @brief  W25Q128FV Commands  
    / G8 q  `" j" r9 f* c9 P& M/ t8 v. G
  68.   */  
    / j4 N4 k2 N( q1 P
  69. /* Reset Operations */
    & }5 t& |1 j  c2 M! f( b  H
  70. #define RESET_ENABLE_CMD                     0x66  V8 e% [* _+ k; M4 _
  71. #define RESET_MEMORY_CMD                     0x99
    : k7 {: `" k4 d! F. f
  72. ! a# Q8 |9 g' j
  73. #define ENTER_QPI_MODE_CMD                   0x38
    - G  s. _' b9 I: a
  74. #define EXIT_QPI_MODE_CMD                    0xFF2 y7 r- p6 r( l! ]& V. u! a% Y
  75. $ G# S) ?+ G# o& [5 c( L) S* {) `
  76. /* Identification Operations */
    1 Z3 U  V+ v9 D
  77. #define READ_ID_CMD                          0x90
    ' k, S+ y7 C( z" w# f$ K" j0 ]
  78. #define DUAL_READ_ID_CMD                     0x92
    9 a( u5 r% B+ X0 m8 W+ ?
  79. #define QUAD_READ_ID_CMD                     0x94. s& X* d0 G/ \$ y1 s1 v2 T
  80. #define READ_JEDEC_ID_CMD                    0x9F
    8 }; X4 h4 p3 x1 s  Z! @

  81. % b4 ]' x+ t) k# j
  82. /* Read Operations */) z  |+ e" [, Y7 K
  83. #define READ_CMD                             0x03
    / z6 s$ m- z0 e6 T% B9 x4 b
  84. #define FAST_READ_CMD                        0x0B5 O* Z( f2 `7 t$ I8 z0 \+ k- u
  85. #define DUAL_OUT_FAST_READ_CMD               0x3B
    % {  ^. `2 [( p& i
  86. #define DUAL_INOUT_FAST_READ_CMD             0xBB1 Z1 P  Z, I! r- x
  87. #define QUAD_OUT_FAST_READ_CMD               0x6B* S* b* x: U( w, S7 C! `: x  z
  88. #define QUAD_INOUT_FAST_READ_CMD             0xEB
    # l7 D$ A& y# m1 D/ {$ C
  89. 9 Y( h( D3 `) T+ s
  90. /* Write Operations *// B" p/ f% K- [9 z1 W! R2 I+ b
  91. #define WRITE_ENABLE_CMD                     0x06* h2 Q! i; m+ y4 ~/ P) n$ R* R
  92. #define WRITE_DISABLE_CMD                    0x04+ k4 e5 \# F' v, z8 e3 e6 U! [" v% K
  93. 3 R5 a: M. v0 a& t2 x( b
  94. /* Register Operations */
    3 d1 B$ J8 t( _4 J
  95. #define READ_STATUS_REG1_CMD                  0x05
    ) `1 f6 z* ?5 n: _' w, \
  96. #define READ_STATUS_REG2_CMD                  0x35' F# J  q# N7 I9 V3 \; Z+ J
  97. #define READ_STATUS_REG3_CMD                  0x15! g6 J" G8 B' t" A( w0 O
  98. 0 Q, A# w3 [; H& k
  99. #define WRITE_STATUS_REG1_CMD                 0x01% d- ^. R0 h2 U( |
  100. #define WRITE_STATUS_REG2_CMD                 0x31  p6 y, T; K" \* r) b
  101. #define WRITE_STATUS_REG3_CMD                 0x11: t' Q# k+ k! b8 I# |' z5 n

  102. ( k9 _( h+ ~* r

  103. $ d6 o$ s" _' J5 G) }* N
  104. /* Program Operations */
    0 R3 {6 V8 u4 a4 r: `
  105. #define PAGE_PROG_CMD                        0x022 g  }/ d* ~5 I* B( ~7 G% B
  106. #define QUAD_INPUT_PAGE_PROG_CMD             0x323 A: ^# {. N  M0 [. R* o# D
  107. 7 E, h% \, f/ x$ o2 D5 V; q/ p
  108. ; X6 A; k! o7 `) W
  109. /* Erase Operations */- J" h+ s7 R" R
  110. #define SECTOR_ERASE_CMD                     0x20
    % S6 s% L; z/ Q( E+ O  D: F: W+ ]
  111. #define CHIP_ERASE_CMD                       0xC79 g5 v* f9 `) |8 G/ p5 P

  112. ' {" o6 s  ?  G+ h$ y% R& o
  113. #define PROG_ERASE_RESUME_CMD                0x7A
    , h/ ?. {% i: O( D
  114. #define PROG_ERASE_SUSPEND_CMD               0x75  `' P9 B' a4 ~0 Y+ \0 n( o

  115. $ Y2 L5 y0 t, I* W- |( S' j
  116. , m- ]/ F7 a+ C( K* B* }
  117. /* Flag Status Register */( [5 w5 I1 x: ~. K: e  f. ?
  118. #define W25Q128FV_FSR_BUSY                    ((uint8_t)0x01)    /*!< busy */8 e# y. P5 w5 d- t6 t. Z* {$ w2 i  H
  119. #define W25Q128FV_FSR_WREN                    ((uint8_t)0x02)    /*!< write enable *// r& w, e# ~  Z/ A
  120. #define W25Q128FV_FSR_QE                      ((uint8_t)0x02)    /*!< quad enable */
    & a$ c9 Y; |  b( \& x$ }7 i
  121. . o  @/ ]) x. Z: Z( B2 `

  122. . \. N' g" c$ Y
  123. #define W25Qx_Enable()                         HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET)
    # ~8 |. b1 [9 i+ F/ d7 x
  124. #define W25Qx_Disable()                 HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET), R# ~- c' k0 S# J" i
  125. 7 y1 G( W' M5 P( J- e6 R: K+ Z
  126. #define W25Qx_OK            ((uint8_t)0x00)/ L" y1 @  K. H8 B' h* V
  127. #define W25Qx_ERROR         ((uint8_t)0x01)
    - X0 Z8 X7 w2 R( t
  128. #define W25Qx_BUSY          ((uint8_t)0x02)
    8 W0 d5 j: i: |& H
  129. #define W25Qx_TIMEOUT                                ((uint8_t)0x03)
    4 y, B3 J2 i2 g: h' u

  130. 2 ~0 w! S. [7 Z, H" Q" Q9 r

  131. 4 z8 w% t1 `/ b0 I
  132. uint8_t BSP_W25Qx_Init(void);
    " c; p; r8 h6 A/ P
  133. static void        BSP_W25Qx_Reset(void);
    # ~" \, u- P' K5 |
  134. static uint8_t BSP_W25Qx_GetStatus(void);( t+ V. _1 _2 |6 Q0 |  C# g) D$ I7 }
  135. uint8_t BSP_W25Qx_WriteEnable(void);& S% L# \: z5 V, X3 `
  136. void BSP_W25Qx_Read_ID(uint8_t *ID);; V" h. |) \5 c  y# M4 r
  137. uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
    + O4 m+ m7 i$ U- z: O
  138. uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
    4 t1 P6 C. E$ p& M6 L+ f0 I+ [
  139. uint8_t BSP_W25Qx_Erase_Block(uint32_t Address);4 q9 p6 s& V/ t& q/ m
  140. uint8_t BSP_W25Qx_Erase_Chip(void);
    # ], @6 w( s- Q1 O. j2 l

  141. 0 Z: k# t& k! F& v2 f
  142. /**
    . ]- b- v# t# {8 t3 U/ D
  143.   * @}
    % L& x* X0 G. y
  144.   */
    ' S1 Q% t+ t  g9 M! Q9 y: w; s

  145. ! y! D0 N" C5 R5 T: ~/ w  O1 Z
  146. /** @defgroup W25Q128FV_Exported_Functions
    ! F, D8 y5 ?9 ~: P( a; |) n
  147.   * @{) ^5 q) r, R, M" ^6 ]
  148.   */
    9 L9 z+ A1 @. r3 w. F
  149. /**
    ' N" ~6 _! w* B+ b) ^
  150.   * @}  F1 |2 `5 |3 T2 a
  151.   */
    ( G; v2 @! M0 y& o
  152. 8 ], c5 r1 y' k3 h  D
  153. /**
    + {  ~" g; s- i  I$ g
  154.   * @}& m: \: \6 Z  }8 L6 Y* O, E. K
  155.   */
    7 e$ S9 f7 c. v, m

  156. % v3 c6 g3 d3 t; K/ [6 z
  157. /**1 t: S) Z- J! ~' l6 z
  158.   * @}
    1 x: t" H$ f, Q9 X# H7 a
  159.   */   Y+ I7 R" }' B' k, M& e

  160. ( x' u; P- I& n
  161. /**4 }/ ]9 @! m( x: _
  162.   * @}. ~3 z  T5 o+ F. C7 _# A% b. X
  163.   */+ z* B2 r' x0 R6 }( P. C

  164. 7 ~4 w& [" W9 z
  165. #ifdef __cplusplus0 G( c: q; l! ^, a' ]  w
  166. }) C% s/ k7 C+ l0 w, j. g
  167. #endif
    9 D% L* Z$ n3 r  s4 ~3 |1 Y
  168. - y# s3 T0 p7 o" B% \
  169. #endif /* __W25Qx_H */
复制代码
5 I! x1 n1 j4 \0 L% z5 |
案例
* E2 W' ]& N) N( i& y+ N向0扇区(0块0扇区),17扇区(1块1扇区),34扇区(2块2扇区)分别写入0x200的数据。
* V- J0 n8 H3 T! ]8 E: [2 W
" i5 s6 v) v1 g3 X9 p* L5 t; f头文件定义2 g2 H% `7 P" a+ Y4 K
  1. /* USER CODE BEGIN Includes */; {, d5 f* c, ~, j2 R
  2. #include "stdio.h"
    ' @1 ]) i1 q1 Y9 ?5 y
  3. # ~4 {/ s  p( M3 T' b
  4. #include "W25Qx.h"
    ) I$ ]5 w- A3 F/ {
  5. /* USER CODE END Includes */
复制代码

5 o" m7 M+ q5 R. c+ _7 j串口接收和flash数组定义% e/ Z# L: O8 s8 h2 y  i3 _" ^
  1. /* USER CODE BEGIN PV */
    2 O* V, q, l9 u; [0 ^
  2. #define BUFFERSIZE 255           //可以接收的最大字符个数       1 }0 ^( e$ a4 u* n2 P4 W' R
  3. uint8_t ReceiveBuff[BUFFERSIZE]; //接收缓冲区
    * i& g$ `" |+ k1 P9 O
  4. uint8_t recv_end_flag = 0,Rx_len;//接收完成中断标志,接收到字符长度9 q" g* ~! P! c1 J  V6 b

  5. ( ?& e( G* \4 n) x, m
  6. uint8_t wData1[0x200];% r9 Z! }" }# [4 Z0 _+ v" S
  7. uint8_t wData2[0x200];4 Z3 x; D4 u6 y! a. v
  8. uint8_t wData3[0x200];) s6 ^+ r/ w' E& F* n# Z/ {
  9. 7 _3 k& Y5 x! n9 s
  10. uint8_t rData1[0x200];
    $ d* }' K# G8 s/ b
  11. uint8_t rData2[0x200];
    1 {; B  k* h0 {* v3 C. ]
  12. uint8_t rData3[0x200];# R/ B1 O0 K4 {8 s1 v& N
  13. uint8_t ID[4];
    9 j: i$ z' c% t. J
  14. uint32_t i;& a/ ^* s# N, N$ y
  15. # F6 m+ T* A3 P& [1 r0 I
  16. uint8_t flag[1] ;. i6 u! ]2 S/ X) q( y
  17. int i_flag = 0;$ N* G9 v5 Y" `% T* s3 B
  18. /* USER CODE END PV */
复制代码

- Z+ ~6 r9 _4 \/ P, {" D/ ?1 d串口重定向
' u# w/ b1 ]9 y
  1. /* USER CODE BEGIN PFP */
      g+ g( U4 I8 \& [# g! U- ~5 f9 }
  2. void uart2_data(void);9 v% u( i) N4 h9 J+ [
  3. #ifdef __GNUC__                                                                        //串口重定向
    % ]! C: J! ~; X7 G: v2 E# r' d
  4. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)8 d$ ~& O6 h8 a
  5. #else& c' s1 C/ y( [  F
  6. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)! S! t8 U8 z: v# ~
  7. #endif
    & T" q$ C" D% y6 }/ V# L
  8. PUTCHAR_PROTOTYPE% o# v; G) \' e8 _; B9 F2 r
  9. {
    5 V8 p) @& A9 F% ^
  10.     HAL_UART_Transmit(&huart2 , (uint8_t *)&ch, 1, 0xFFFF);& Y3 Y( h6 {$ l4 ~
  11.     return ch;
    4 ^& A4 d5 g; I% F; q' A
  12. }
    9 {- a$ K3 g5 t0 Z8 j6 Q
  13. /* USER CODE END PFP */
复制代码
' e3 l0 j# h% J4 O( c
串口中断设置
( X* Y6 o& s3 C' \6 p, \" p0 y
  1. #include "stm32f1xx_it.c"文件中断外部变量引用:
    6 T/ U. X+ ?! i) F9 p5 |. u

  2. # I. E0 V2 H. n2 V6 c( P" e6 R" f  q
  3. /* USER CODE BEGIN 0 */
    4 z, z- m' S5 _# O3 j. p/ p
  4. #define BUFFERSIZE 255        //可接收的最大数据量
    . b% X# i' [$ y0 g& c% p' }7 E4 k
  5. extern uint8_t recv_end_flag,Rx_len,bootfirst;( E' a- c( |( X  r' f# B1 s( Y
  6. /* USER CODE END 0 */
复制代码
1 P# T9 z, Q- h* c. g
串口2中断函数:/ N2 w/ ?( A# ]" P
- d: l4 X8 F% X; V
  1. /**  S& P! ?) U  W( B( f* }4 R( }
  2.   * @brief This function handles USART2 global interrupt.; V: v7 t  c. Q; X) E3 u! Q
  3.   */
    0 m( ]9 t; Q! S# I* h" g. H' L: M1 i% t
  4. void USART2_IRQHandler(void)* V6 l- J* y  _% R0 s' \! o- v0 {$ g
  5. {
    " }3 u2 q) Y8 Z
  6.   /* USER CODE BEGIN USART2_IRQn 0 */5 h) G& q  m& l# e% I# s# ]2 B2 z

  7. 7 e. ^# C0 y6 v7 n
  8.   /* USER CODE END USART2_IRQn 0 */
    8 X1 O# h5 v5 t( T
  9.   HAL_UART_IRQHandler(&huart2);
    * o# j' c( g0 V( l
  10.   /* USER CODE BEGIN USART2_IRQn 1 */
    : I$ z+ F; o0 |" P  H% E" T3 {7 c
  11.         uint32_t temp;
    % i& a5 F$ X3 }5 m
  12.         if(USART2 == huart2.Instance)//判断是否为串口2中断
    0 d& [6 ^3 {8 `, @$ o

  13. ) Y  W; h1 [0 ^# I4 {& e
  14.         {      3 Z5 D& E; [" F6 n! M
  15.                 if(RESET != __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE))//如果为串口2' X2 u% @" y' [( `. {3 j- w
  16.                 {  a$ O, Y/ j+ Y# C* Z* N
  17.                         __HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除中断标志" R( g4 [$ q5 U7 ~9 t% ?
  18.       HAL_UART_DMAStop(&huart2);//停止DMA接收
    : @6 u( o" M! C- Q* `; F. Q! C
  19.                      temp  = __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//获取DMA当前还有多少未填充9 U+ W  t/ |( F8 o
  20.                       Rx_len =  BUFFERSIZE - temp; //计算串口接收到的数据个数6 k" U1 y8 j' k5 E3 M
  21.                       recv_end_flag = 1;
      W: I; r' e2 ]$ U7 U, Z
  22.              }
    * P1 U+ Y, Z3 S/ c. F' E% U( x
  23.         }
    : L* n6 i9 w* U! V. g' ]

  24. / E1 \* H# E3 c- \
  25.   /* USER CODE END USART2_IRQn 1 */" q8 V0 y$ R9 d( k+ M% Z
  26. }
    ; o! }- d( a2 k% ]1 y& t6 B1 _
复制代码

: C* Q* d) c; G9 [/ T! K" D# _主程序
( k) h9 S4 F, {) Z, r6 ?- }6 J读取ID和flash数据及擦除。) t# A7 h% A: X( G

8 _* A, n0 X# M( x: A
  1.   /* USER CODE BEGIN 2 */8 X4 j1 U6 k7 P2 Q6 k9 ]
  2.         printf("GD Nor Flash案例\n");, J1 {8 W  {3 n' L2 Q
  3.          __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//使能串口1 IDLE中断 ; ~  j1 O( I# Z2 o5 E
  4.         / b, H( q! ^5 j$ D7 D* j7 J
  5.         /*##-1- Read the device ID  ########################*/ ) {( g. F7 r4 q0 s9 d
  6.         BSP_W25Qx_Init();//初始化W25Q128! @) g5 ]  i0 z* Q5 k; Y/ G
  7.         BSP_W25Qx_Read_ID(ID);//读取ID3 y1 \" @+ p6 X$ y  o0 s
  8. : k0 r# }, E+ G* j; I
  9.         if((ID[0] != 0xC8) | (ID[1] != 0x16)); r" C6 o0 K4 ]  Q6 c( S! v
  10.         {
    ( D( z7 L# D9 [- ]- Z
  11.                 Error_Handler();//如果 ID不对打印错误
    2 F* S6 k( A8 L  B' f- {
  12.         }
    , ^5 Q% ~; z& x4 g
  13.         else//ID正确,打印ID' l" T+ n* i6 x
  14.         {; z0 _& Y7 b0 ^& [! N
  15.                 printf("W25Q64 ID : ");, u+ H# z1 m2 |! ?3 j+ Q  N
  16.                 for(i=0;i<2;i++)4 m# Q1 ~  C7 d
  17.                 {
    5 b$ z+ F+ A# H) P, r
  18.                         printf("0x%02X ",ID);2 n: i1 _& w5 k& \, D
  19.                 }
    5 o' X6 ]) f" p' ~  r
  20.                 printf("\r\n\r\n");
    " w* Y; m' P( A( ~3 E3 X. f
  21.         }& p; m* a9 ^6 O

  22. ; C" m2 S3 q! E+ x6 M! M9 ^% F1 |
  23. " M+ Y) \3 g2 p
  24. /**************************读取第0扇区数据**************************************************************/, G, O' N& p# |: k+ r

  25. & p0 c& X# n  z! E
  26.         /*##-3- Read the flash     ########################*/ 7 L1 `4 [/ i0 G2 @3 E
  27.         /*读取数据,rData读取数据的指针,起始地址0x00,读取数据长度0x200*/1 y% T  Z& G7 a. G. \0 y
  28.         if(BSP_W25Qx_Read(rData1,0x0,0x200)== W25Qx_OK)
    ; L* u7 X! z: }8 B9 a
  29.                 printf("读取原始的0个扇区数据成功!\n");
    " b8 N3 v9 x1 M, h
  30.         else
    " `7 e5 E) a( _3 q1 o% [
  31.                 Error_Handler();7 ^/ u; o7 C) w( d: n
  32.         /*打印数据*/        
    " s$ j* @4 o/ a2 y+ ?, C6 ^( U3 ^
  33.         printf("读取原始的0个扇区数据为: \r\n");
    1 B0 q$ @& |: ~' P0 B4 C
  34.         . ?3 j7 e" D; y+ @. O- z3 d0 u! q
  35.         for(i =0;i<0x200;i++)
    1 \1 J+ _% j  ~
  36.         {- K0 H* {5 w6 l7 j1 ~' K
  37.                 if(i%20==0)/ x6 w- C) m; D6 I  ]" Z5 [
  38.                         printf("\n0扇区第%d到%d的数据为:\r\n",i,i+19);. J% P  ^  e, }" |  S: t
  39.                                 printf("0x%02X  ",rData1);
    : W$ i8 C5 }" \1 p. g# Y" d: p
  40.         }
    0 ^% u5 o' F/ W/ O

  41. ' G7 \4 K% `1 U$ I  U
  42.         printf("\n");0 R6 v$ R: N  b" F
  43. & O7 G$ E7 M+ |0 o3 A2 L
  44.         ' p8 i( W6 K4 t6 c. @5 W
  45. /**************************读取第17扇区数据**************************************************************/
    " F& @5 O, T. P5 q
  46.         
    8 V& c: T  D: Z% D# a( s$ h" w
  47.         /*##-3- Read the flash     ########################*/
    , ~# ?& i" F) w; c+ |# O1 x
  48.         /*读取数据,rData读取数据的指针,起始地址0x1000,读取数据长度0x200*/, e2 p- S/ S1 \8 m! A( u+ C' n7 @
  49.         if(BSP_W25Qx_Read(rData2,0x11000,0x200)== W25Qx_OK)
    5 _* N0 `0 i2 g" q/ F, G
  50.                 printf("读取原始的17个扇区数据成功!\n");/ P0 c& Q7 i9 A# D9 b  o5 V: V
  51.         else
    1 w" S5 @5 z  P- D
  52.                 Error_Handler();
    / U0 g# x  w- M  @0 h1 e
  53.         /*打印数据*/        0 e1 V5 y+ p& |% C+ i" _4 d
  54.         printf("读取原始的2个扇区数据为:");& K4 e0 {- K% l! N1 L( C
  55.         
      P2 P% Q- h; h( |% z; W
  56.         for(i =0;i<0x200;i++)
    , H4 K) w: B9 N
  57.         {9 C, S' S  n: j5 @% c& n
  58.                 if(i%20==0)
    : W5 H; }: N) m& |2 M- D0 J
  59.                         printf("\n17扇区第%d到%d的数据为:\r\n",i,i+19);# A2 ~- M' V! m0 g" e
  60.                                 printf("0x%02X  ",rData2);
    4 M9 ?9 U$ K* \- s) ^4 e) z
  61.         }
    . l4 X( p! D" P' }( u7 V
  62. 0 W- i1 @/ j5 D" m+ S
  63.         printf("\n");        
    % p$ c7 }' V2 m3 a; h% t: \
  64.         8 T" G$ V0 D% D! m* Q
  65.         
    # D* V* d* @6 _
  66. /**************************读取第34扇区数据**************************************************************/1 }: \* k1 f; k# R- w: U: K
  67.         
    5 c$ K' M. ^: ]+ W. `$ A
  68.         /*##-3- Read the flash     ########################*/
    0 @. w8 t" B2 y0 M
  69.         /*读取数据,rData读取数据的指针,起始地址0x2000,读取数据长度0x200*/
    # F/ O# M9 K8 d3 j6 v# K
  70.         if(BSP_W25Qx_Read(rData3,0x22000,0x200)== W25Qx_OK)
    $ l; q4 k) ^% ]" r! [/ b- \
  71.                 printf("读取原始的34个扇区数据成功!\n");3 }7 _* U+ T  r' H6 L* N
  72.         else
    6 g% U7 b6 I' w% H, k7 Z' c
  73.                 Error_Handler();
    8 i$ X3 Y2 y. O/ o
  74.         /*打印数据*/        
    " l* l# }, b( \3 O
  75.         printf("读取原始的34个扇区数据为: ");
    3 t; a6 ?4 f" |3 {$ F( i+ k
  76.         & e  u0 o* j% |$ ~/ L
  77.         for(i =0;i<0x200;i++)
    % K& O/ h" P1 |3 y" ^
  78.         {
    / A6 L  Z# E1 k& e1 j0 ]( y  J
  79.                 if(i%20==0)
    8 o/ ~, A0 `; x, v0 u0 q
  80.                         printf("\n34扇区第%d到%d的数据为:\r\n",i,i+19);& Y* _5 O, t. h# ^# F# [
  81.                                 printf("0x%02X  ",rData3);
    7 r9 N( a, y3 Z+ y* n
  82.         }
    ' G) y9 e/ \0 u$ o/ H/ T2 w& }
  83. ; M5 Y5 C- v! p# o
  84.         printf("\n");        ; g% Y" j, [8 _' K- `
  85.         
    6 u( p3 S9 S- B! e5 m0 _2 d( w
  86.         ) C; y  p. W) B6 R4 o
  87.   {2 @: e0 y# I/ v& b. m+ x0 Z
  88. /**************************清除第0扇区数据为0**************************************************************/7 l' F% g: N+ K$ E9 d: q
  89. % X  B8 j6 R" ]+ j" f

  90. ) F2 V* q9 G4 L/ U
  91.         
    7 t( V" B1 c& a, f0 o
  92.         /*##-2- Erase Block ##################################*/
    . V% s& h( T( a# d
  93.         if(BSP_W25Qx_Erase_Block(0) == W25Qx_OK)- |6 S9 x3 P$ `. O
  94.                 printf(" QSPI Erase Block ok\r\n");* R" _9 c7 v3 g2 k) U
  95.         else
    % E) K  g0 y8 c% X& B" h7 \
  96.                 Error_Handler();
    2 R# ^) P. I) r& ~! h3 l
  97.         
    " ~+ W& s  Y/ ^2 m  V4 j0 _
  98.         /*##-2- Written to the flash ########################*/
    3 c5 b' k1 J. u8 D
  99.         /* fill buffer */. B. M) T5 {: J. R$ q
  100.         printf(" 初始化数据,清零第0扇区前0x200的数据!\r\n");, H. H0 L; z6 n! h
  101.         for(i =0;i<0x200;i ++)
    ( i- ~, i4 t8 X8 a
  102.         {
    2 M2 S- F  w) `% j- y9 ]4 V  s
  103.                         wData1 = 0;; l' ^8 ?2 ]/ r6 r8 @# K4 C
  104.                   rData1 = 0;
    & V0 a9 k4 W: K
  105.         }
    + V6 Z) B$ \! n7 [+ ~4 ]
  106.         /*写入数据,wData写入数据的指针,起始地址0x00,写入数据长度0x200*// p. j: Y7 t: }9 g) Z
  107.         if(BSP_W25Qx_Write(wData1,0x00,0x200)== W25Qx_OK)
    * p1 i- R$ V( M6 h9 \
  108.                 printf("清零第0扇区前0x200的数据成功!\r\n");
    * P) i3 f6 k! j, U# `
  109.         else
    * E% D# M( ^$ Z/ O7 G( _
  110.                 Error_Handler();! q. f6 x9 {6 `2 m% g! C  C
  111. * I/ s# b& A: G; s$ U4 @
  112.         3 t. r/ j7 T) ]5 z. y
  113.         ) V4 M9 e! _$ T
  114.         
    * J" N: u+ R- [
  115.         /*##-3- Read the flash     ########################*/ + P* F7 T8 y( }& b
  116.         /*读取数据,rData读取数据的指针,起始地址0x00,读取数据长度0x200*/8 q7 S1 l. s8 i. b
  117.         if(BSP_W25Qx_Read(rData1,0x00,0x200)== W25Qx_OK)
    - M2 ~( W, x8 T( M0 M- t/ z, H7 W
  118.                 printf("读取第0扇区前0x200数据成功!\r\n\r\n");
    0 r$ R/ r% e7 C1 R" i, C. p
  119.         else
    6 l+ K! `! e- g: v
  120.                 Error_Handler();8 A# ~! Q; l& _
  121.         /*打印数据*/        
    0 k/ P5 k! }. |) i
  122.         printf("读取第0扇区前0x200数据为: \r\n");
    , O% B6 e& [( w; F0 s2 c6 W8 T' N
  123.         & G: ]# t( j  }% `$ a5 C8 u
  124.         for(i =0;i<0x200;i++)
    2 t! ~( }+ C: a0 F2 H
  125.         {
    ( P2 a9 a* h) t  x. F) i
  126.                 if(i%20==0): v% i' w, j9 D1 w
  127.                         printf("\n第%d到%d的数据为:\r\n",i,i+19);) ^5 H( N+ [7 G7 g: Z5 `2 k
  128.                                 printf("0x%02X  ",rData1);
    * ~% P: H6 Q* M
  129.         }2 T" y6 @5 f/ w+ y: q

  130. . u7 l3 a, R3 Y' X2 _
  131.         printf("\n");
    ( t5 p3 S4 _4 R$ ?. ^, ~: G+ B/ P

  132. + e1 a, P! m9 S5 T
  133. ' L# \* L, K  p, ]. H% b
  134. /**************************清除第17扇区数据为0**************************************************************/
    2 Y6 `6 w! b: i4 V
  135. * L: B. G5 l1 v2 }3 `

  136. ! R# K4 y+ z8 T
  137.         
    + F  H( u# u. o
  138.         /*##-2- Erase Block ##################################*/
    ( G- V( S6 W$ a  |! y1 Y# m5 G
  139.         if(BSP_W25Qx_Erase_Block(0x11000) == W25Qx_OK)
    - I; \5 s) W8 h
  140.                 printf(" QSPI Erase Block ok\r\n");" A1 p3 y% [" j
  141.         else# x* D/ l0 k2 x6 s$ s! r
  142.                 Error_Handler();0 n& m6 y- D; u! {( p
  143.         * p) h& {! C; h) r
  144.         /*##-2- Written to the flash ########################*/ 2 S8 n* S5 d8 H
  145.         /* fill buffer */
    . L6 n& ?2 J0 |
  146.         printf(" 初始化数据,清零第17扇区前0x200的数据!\r\n");/ d4 g$ }! L2 A: d3 P# X" D/ s2 J
  147.         for(i =0;i<0x200;i ++)6 t& m# V) l1 J: \
  148.         {
    & v. d, Q& I# I
  149.                         wData2 = 0;
    7 N1 @$ z1 O( y% _
  150.                   rData2 = 0;
    . \: J4 e6 y+ G9 Z( h2 r
  151.         }
    . b9 B% h$ ]3 Z) w  q
  152.         /*写入数据,wData写入数据的指针,起始地址0x1000,写入数据长度0x200*/
    . z9 Y3 O- ^; k2 v
  153.         if(BSP_W25Qx_Write(wData2,0x11000,0x200)== W25Qx_OK)
    4 t. e/ U0 \& i" s
  154.                 printf("清零第2扇区前0x200的数据成功!\r\n");3 u! r* W  I; h# X9 `2 K+ r
  155.         else
    + b: `, E4 B# p9 p
  156.                 Error_Handler();& C. ^$ C" q( r* Q: {

  157. & O/ a/ Q4 |. D% m4 {& \1 s9 K
  158.         
    2 I* m6 J  B- d' I' ]# u8 N0 y
  159.         
      c, ~( B" _9 w  D
  160.         
    3 f- X) z$ Y& T$ O
  161.         /*##-3- Read the flash     ########################*/
    3 j; }: S: l" Q
  162.         /*读取数据,rData读取数据的指针,起始地址0x00,读取数据长度0x200*/
    : X# ^* U2 K' d  g7 ^' G/ q" m
  163.         if(BSP_W25Qx_Read(rData2,0x11000,0x200)== W25Qx_OK)! j" }+ i" `# ]# v
  164.                 printf("读取第17扇区前0x200数据成功!\r\n\r\n");
    - {+ Z4 [* V! }2 H% y+ z
  165.         else$ H$ J; K7 i% r
  166.                 Error_Handler();
    7 {* l* y% g# h8 {! ~
  167.         /*打印数据*/        
    : S8 i. |/ Z, D- k  D* n  `& L
  168.         printf("读取第17扇区前0x200数据为: \r\n");' |( y/ w8 G# h% @' E( [
  169.         $ W, u; w3 i8 N5 o- d2 w
  170.         for(i =0;i<0x200;i++)! h! S$ g* ^* Q3 k( y
  171.         {
    # {+ Q: M" l8 z2 i5 }# `
  172.                 if(i%20==0)
    # l  ~* i4 p2 k0 h
  173.                         printf("\n第%d到%d的数据为:\r\n",i,i+19);
    : S3 i; U7 N+ y5 Q+ M
  174.                                 printf("0x%02X  ",rData2);
    & [+ ]2 q+ Z5 w. t% `/ X- h
  175.         }2 J9 u0 c& _( x1 o
  176. 3 |7 `# {; d9 X3 o1 x: z; R7 A# N4 z
  177.         printf("\n");
    - o/ ?0 n: a7 Q9 P/ Y0 m
  178. . H" M* _8 F1 C5 Y3 E/ e$ h% f+ _* T
  179. & Y4 `0 t, |# {' o) C8 Y( \6 }
  180. /**************************清除第34扇区数据为0**************************************************************/1 |; j  D& L7 J. J) r& j
  181. 2 {" ~; `  ^8 H, q: K; f

  182. " K; Q& O* Z: n2 [- g
  183.         ( G- l. u0 i8 f  e5 A
  184.         /*##-2- Erase Block ##################################*/ : S7 T+ ?! o. N( @% u9 J
  185.         if(BSP_W25Qx_Erase_Block(0x22000) == W25Qx_OK)6 V& C5 t! t. f. s
  186.                 printf(" QSPI Erase Block ok\r\n");- Q5 Q, e- e; K7 g
  187.         else5 `) j3 K. v7 {, p6 w2 C
  188.                 Error_Handler();
    5 d/ p+ K/ ^: A
  189.         ! A& t% m8 [) X5 t4 g
  190.         /*##-2- Written to the flash ########################*/ + X9 a9 C& V9 C: C, B
  191.         /* fill buffer */5 ^' O: T$ H3 F
  192.         printf(" 初始化数据,清零第34扇区前0x200的数据!\r\n");  L: t! y/ M# `2 \- ]
  193.         for(i =0;i<0x200;i ++)
    3 f; {* k/ ~  h1 H/ P' c6 l
  194.         {
    - g3 [. z9 A8 l6 J: }) }  U: C
  195.                         wData3 = 0;% m/ p9 r. a; T+ G( q6 B$ j5 ?
  196.                   rData3 = 0;9 j2 C2 R$ _9 V% M* g" @
  197.         }8 g' M! J; x$ \! }5 c! e
  198.         /*写入数据,wData写入数据的指针,起始地址0x22000,写入数据长度0x200*/
    3 c5 v2 g$ e3 S5 R
  199.         if(BSP_W25Qx_Write(wData3,0x22000,0x200)== W25Qx_OK). r/ d# @. z( S. Q* \5 @) c6 u
  200.                 printf("清零第34扇区前0x200的数据成功!\r\n");* I, ]7 E! V4 j
  201.         else
    ) G5 W# O. c, J! s6 B* F
  202.                 Error_Handler();; A8 O& v) K9 Y6 q1 c! L
  203. & R1 v( @3 {, o/ X! p% j
  204.         
    ; F# B6 v- y" L9 ?
  205.         6 m/ o  `1 F  t* E; Y$ M7 x5 `
  206.         
    3 P& q$ Q$ J/ S" ?! l
  207.         /*##-3- Read the flash     ########################*/ , \  {" {5 j4 ]3 c5 R0 A* x" N; i9 _
  208.         /*读取数据,rData读取数据的指针,起始地址0x00,读取数据长度0x200*/4 b# q  U' f  G) s
  209.         if(BSP_W25Qx_Read(rData3,0x22000,0x200)== W25Qx_OK)
    4 K# H( ?1 K: n$ h) Q: Y8 k
  210.                 printf("读取第34扇区前0x200数据成功!\r\n\r\n");% ~" E, S3 d/ C5 W
  211.         else2 D5 x- d9 r4 |" y( _) a/ O
  212.                 Error_Handler();9 m% I' F% {: o& ~( J3 b! t* r$ g
  213.         /*打印数据*/        
    # k; H% C: c$ d% w& Y( E1 M
  214.         printf("读取第34扇区前0x200数据为: \r\n");
    - Y/ U. y! k6 Z1 J6 ~9 e. L( q
  215.         - \, u$ @$ t+ V. Y5 K
  216.         for(i =0;i<0x200;i++)
    / v6 y, V6 T9 T1 S. @) t1 L% T
  217.         {
    6 ?8 d( B1 I; Z. ^% Z" |) |
  218.                 if(i%20==0)
    / _, S4 [1 @' [* c
  219.                         printf("\n第%d到%d的数据为:\r\n",i,i+19);
    , U( |6 {+ X, R  z# }
  220.                                 printf("0x%02X  ",rData3);7 ~# R1 e, E# U/ L* t
  221.         }
    ( E& s# [: N' c$ H: H4 J2 Y' b* G
  222. % u% z/ X+ J! o( |+ U: l0 b2 n
  223.         printf("\n");) H1 g+ x+ e- L/ v6 K2 j# U7 A
  224. % T' _4 \  o: X# C1 x! A5 P7 j
  225. 1 `0 D$ Y8 n; j3 r4 A; N
  226.   /* USER CODE END 2 */
复制代码
: X6 `$ o# L; i  ]+ }5 Q( f
主程序。3 b. O) X$ X% ?0 j

: Y$ r1 ~6 N' n6 x
  1.   /* Infinite loop */9 i+ ]' P. |- v8 [) R1 E
  2.   /* USER CODE BEGIN WHILE */& W4 N; z6 S% k! q% J4 R
  3.   while (1)
    - G8 f* Q' u* u4 q: X4 X1 K! p) |+ v4 W
  4.   {6 N, @- Y" z- f
  5.     /* USER CODE END WHILE */# \9 u+ d' u. ^! H/ l4 j5 P

  6. * x; m' g- B4 H4 P8 q0 b3 e% a0 m
  7.     /* USER CODE BEGIN 3 */$ N8 k  R- _6 i- e9 ?' R
  8.                 uart2_data();
    : \6 w) n5 ?: s8 ?1 L! q
  9.                 HAL_Delay(100);" ~1 [8 L+ R  y1 B9 }+ S
  10.                 : _/ W5 ]3 ?  Y# I) H- r
  11.   }% c$ S& X5 c* H
  12.   /* USER CODE END 3 */
复制代码
4 s: u; R7 n) P. g8 O
数据处理
9 l% p$ Z% l0 K+ I
  1. /* USER CODE BEGIN 4 */
    - ~1 r, J5 G- e; r  I; k% w
  2. void uart2_data(void)
    ( c) U5 V* a) q5 q
  3. {/ n, C' }: A. ~5 X/ i! D, n
  4.         if(recv_end_flag ==1)//接收完成标志
    7 [' \4 N" ]( b' U& f0 R
  5.         {
    : b1 c. a0 f& F5 ?3 d3 w9 t7 O
  6.         2 D0 _% l6 G+ |/ }8 c! g
  7. . [6 f3 y, \& A, w
  8. if(ReceiveBuff[0]==0x00)7 z3 e5 U1 X0 ^
  9.                 {
    1 R4 C& d5 S9 D! \% g. g' Z+ t
  10.                         printf("写入数据长度:%d\n",Rx_len-2);4 j2 S$ i$ Z% R, s+ L
  11.                         for(int i =0;i<Rx_len-2;i++)
    ) K, |! C+ l) \  k. `
  12.                         {' x" Y2 z) M5 x& u7 A- h6 ~
  13.                                 wData1[ (i+ReceiveBuff[1]) ] = ReceiveBuff[i+2];
    0 T7 s: b) V2 J6 j
  14. - R5 l  S6 f* P  L1 n
  15.                         }5 ]! I3 H6 B; f0 W' p. j
  16.                                 
    9 Z: H- X& G% ]2 Q- a* E  x5 p
  17. " }8 p  i0 P' }
  18.                 /*##-2- Erase Block ##################################*/ : T& S* l9 P- |
  19.                 if(BSP_W25Qx_Erase_Block(0) == W25Qx_OK)6 R, b" n  Z: }9 q( c+ H  D; p! M% }; }
  20.                         printf(" QSPI Erase Block ok\r\n");! o. y3 M: \+ i9 ], \
  21.                 else
    4 [9 ]8 U. }7 X3 k
  22.                         Error_Handler();( R! m% j4 u: u( b4 c6 [
  23. & W% ?0 ?. s8 J& v! }  O* u/ U
  24.                 0 V/ d8 ^- M: |& O( K2 v* R9 U
  25.                 /*写入数据,wData写入数据的指针,起始地址0x00,写入数据长度0x200*/8 j9 k, C. @% h( J% m
  26.                 if(BSP_W25Qx_Write(wData1,0x00,0x200)== W25Qx_OK)+ d- T4 v" f1 D
  27.                         * b. D' R7 ]# B& k7 [
  28.                         printf("扇区0数据成功~~~~~~~~~~~~~~~~~~~~~~~~~~!\r\n");. {5 d: V7 e7 P* J8 {# |8 z
  29.                 else; r6 \1 |/ H; \5 [: k# U
  30.                         Error_Handler();% }: Z- o5 o" C' c
  31.                         " _$ i' z6 E1 c) d8 a
  32.                 if(BSP_W25Qx_Read(rData1,0x00,0x200)== W25Qx_OK), J# z2 V1 g: F* ]9 @7 w" C
  33.                         printf("读取扇区0前0x200数据成功!\r\n\r\n");
    8 D6 C4 ~% v& R5 t0 M( |1 |
  34.                 else: }6 t; W% s! P! N# j! N
  35.                         Error_Handler();# R/ R5 H# E8 z3 e5 h0 b( @
  36.                 /*打印数据*/        
    4 g# o; a) [& {3 }, e- |
  37.                 printf("读取扇区0前0x200数据为: \r\n");
    : h; `) Q9 j/ ?6 P5 @
  38.         $ n9 H3 w' Y4 K( W$ K* r
  39.                 for(i =0;i<0x200;i++)
    9 I" ?. q. G6 O: U; H- `
  40.                 {- F' U3 N6 E  U
  41.                         if(i%20==0)
    - O/ Z% O$ a7 w
  42.                                 printf("\n第%d到%d的数据为:\r\n",i,i+19);
    & R9 j3 |2 @* H* c& N
  43.                                         printf("0x%02X  ",wData1);" P5 N% W* {, [; x' d
  44.                 }
    5 o  P) ?3 D* [& f/ f4 f
  45. 8 z3 ~7 x4 ]  Z% Q1 g5 i9 i8 i/ {
  46.                 printf("\n");" ]( j( i6 V. o1 w, G
  47.                 - ?3 H/ w) P: [2 a9 G/ ?, w7 v
  48.         }
    / @; j! E& Z! {4 y3 F3 ?5 C
  49.                 5 L; w. H( T! l+ X9 d: H
  50.         
    8 F5 c/ A  g# e8 [7 C
  51.         
    : _% S: p, z7 h# D4 E) K
  52.         else if(ReceiveBuff[0]==0x17)/ h: I! C0 J5 N1 f5 A, u. i
  53.         {% a) r% P# I/ B2 [4 x
  54.                         printf("写入数据长度:%d\n",Rx_len-2);* J8 W. @8 u2 W4 I" y2 w
  55.                         for(int i =0;i<Rx_len-2;i++)
    ( k3 ]9 f8 r/ |. t
  56.                         {) M3 Y- I4 [7 r
  57. //                                Data=ReceiveBuff[i+2];1 G* b. M+ L! u! C9 f) Y
  58.                                 wData2[ (i+ReceiveBuff[1]) ] = ReceiveBuff[i+2];
    . T* g/ q8 d5 `6 o
  59.                         }1 b: N) }; |7 @# u9 H4 m- ]
  60.                                 , {) Q% p: @, V
  61. ; E( Y. ~- l6 m" D
  62.                 /*##-17- Erase Block ##################################*/ 0 v: P6 P7 s0 z  g& y: l
  63.                 if(BSP_W25Qx_Erase_Block(0x11000) == W25Qx_OK)
    # b  q$ @" q7 L9 U  x$ g
  64.                         printf(" QSPI Erase Block ok\r\n");- l4 P2 T; ]. H
  65.                 else
    / x! N7 O7 ^& ~4 J0 r# R
  66.                         Error_Handler();
    & T% G3 c0 Y  B; i7 c
  67. ) X. P- [, W8 J  w0 {: u: r( d
  68.                 9 N/ @& S. h  ]6 d: b+ D- h8 g. s
  69.                 /*写入数据,wData写入数据的指针,起始地址0x11000,写入数据长度0x200*/$ K# ~7 R, V+ _$ y% |& \" K
  70.                 if(BSP_W25Qx_Write(wData2,0x11000,0x200)== W25Qx_OK)
    6 {+ z7 @* \7 t: V7 Y, W/ A
  71.                         5 }* S6 A5 Q$ w; \& C  t
  72.                         printf("扇区17数据成功~~~~~~~~~~~~~~~~~~~~~~~~~~!\r\n");
    . n. ^8 E" e# f* I$ ~8 K0 T5 |
  73.                 else$ }/ L/ }5 u2 M, y4 D3 U  M
  74.                         Error_Handler();
    2 L! j7 `: E5 c) e. r
  75.                         ( B6 W. N1 r% z
  76.                 if(BSP_W25Qx_Read(rData2,0x11000,0x200)== W25Qx_OK)
    * j0 V6 U  u1 K+ R
  77.                         printf("读取扇区17前0x200数据成功!\r\n\r\n");
    8 ]' E7 Y* i; ~% J
  78.                 else
    5 a- O6 O0 i' U" u6 t: T
  79.                         Error_Handler();
    + D- K# k# Z0 ^! Z
  80.                 /*打印数据*/        
    # |+ W( R( l1 B+ k; k
  81.                 printf("读取扇区17前0x200数据为: \r\n");; q- p/ `- Y/ [! }3 w4 a8 F2 d
  82.         
    " b. A8 x4 n+ R, `: `7 s
  83.                 for(i =0;i<0x200;i++)& o3 V7 t$ i% b2 j, k
  84.                 {" A% z! |' I; P8 ?8 H1 h
  85.                         if(i%20==0)3 I* Q8 G: ?  M# I2 `9 S
  86.                                 printf("\n第%d到%d的数据为:\r\n",i,i+19);, _7 W6 ~6 |+ A
  87.                                         printf("0x%02X  ",rData2);$ p% a' }* a0 G
  88.                 }
    + X9 Z9 v* t9 [5 M6 C( N
  89. / G7 b& c4 J' n5 l  @% M
  90.                 printf("\n");: c# P- }  L% D' X
  91.                
    : ^; l! ^# [5 P) K1 Q0 {0 ~
  92.         }                1 Z6 F. H! o0 ?0 ]: p- d" ?6 E6 E

  93. % B" E& V  V5 F8 H  Q3 @
  94. 8 y' a* o1 A7 s% G

  95. " Q' `- W7 C; `* t1 Y/ {9 u0 ^1 E
  96.         else if(ReceiveBuff[0]==0x34)$ c% c- a5 O/ e- M
  97.         {3 \+ i  L) B  W8 v- ?: H
  98.                         printf("写入数据长度:%d\n",Rx_len-2);
    6 |; s! |1 r& x, k. e7 a% ]% x
  99.                         for(int i =0;i<Rx_len-2;i++)& S3 n+ O& [( F" T+ p
  100.                         {
    8 P2 d2 ]* d" u' V4 t  ]
  101. //                                Data=ReceiveBuff[i+2];/ n3 U8 H  A) K& \4 m) e
  102.                                 wData3[ (i+ReceiveBuff[1]) ] = ReceiveBuff[i+2];
    $ \3 P- u$ U/ g+ P7 T& W
  103.                         }$ ]8 [+ n% @  F3 G
  104.                                 
    9 K& p/ H* Q" v1 r  w% }6 j
  105.   y* A* A- c; Y7 N  C" _
  106.                 /*##-22- Erase Block ##################################*/
      N; U$ i) |# y  r0 U$ H4 k
  107.                 if(BSP_W25Qx_Erase_Block(0x22000) == W25Qx_OK)9 d1 ], |- Y. u8 p! K# y
  108.                         printf(" QSPI Erase Block ok\r\n");- P3 k. R, C. y9 n; S" s/ _/ V! ?
  109.                 else* f/ K7 p5 e5 a5 R$ t! I
  110.                         Error_Handler();
    2 f+ D2 m8 z0 o

  111. , w7 w" c1 L' X
  112.                 " @7 O: W, q! {- S6 L0 ?* `
  113.                 /*写入数据,wData写入数据的指针,起始地址0x22000,写入数据长度0x200*/
    ) T  ^) Y# }. e$ g
  114.                 if(BSP_W25Qx_Write(wData3,0x22000,0x200)== W25Qx_OK)
    * P; `1 ^5 o! E4 K% R* G
  115.                         3 f& I1 v/ d6 A# e9 A
  116.                         printf("扇区34数据成功~~~~~~~~~~~~~~~~~~~~~~~~~~!\r\n");
    - F. R  @+ B* t7 g7 ]
  117.                 else; j  G* ^2 x+ z5 W8 Z  C( q$ U2 a7 ^
  118.                         Error_Handler();
    6 {' |  o; h6 R: ]" o7 q+ P
  119.                         
    3 K7 L, E0 C  D, N
  120.                 if(BSP_W25Qx_Read(rData3,0x22000,0x200)== W25Qx_OK)( q8 I* A9 @4 M- H9 i1 Q3 Z/ I
  121.                         printf("读取扇区34前0x200数据成功!\r\n\r\n");
    / @  q: V9 @8 |: E3 k
  122.                 else
    4 B0 A! n4 P* x1 I/ ]) S3 `
  123.                         Error_Handler();6 U; {( [+ Y9 M7 m3 o
  124.                 /*打印数据*/        
    - n8 i2 y0 h" i; Z( [9 ?
  125.                 printf("读取扇区34前0x200数据为: \r\n");0 ]4 `& Y) R& n, k; {1 N
  126.         
    1 P' e  w8 o2 ]
  127.                 for(i =0;i<0x200;i++)9 j* \/ u  I; y2 R, p  b. Y
  128.                 {  A- O" q+ ^" l* |
  129.                         if(i%20==0)$ K- `; h$ J( Y+ ?  ]7 X
  130.                                 printf("\n第%d到%d的数据为:\r\n",i,i+19);) S8 P* {3 G; w  Y" V: p
  131.                                         printf("0x%02X  ",rData3);
    ) I4 a# Z# n3 W' w! G/ n
  132.                 }8 |7 R& Z; J8 R! S0 a3 I) p

  133. & C4 v+ {; y3 J% r: ], X; n1 ]
  134.                 printf("\n");
    " @" Q% ~8 f* M2 b2 h' P# s$ @- R
  135.                
    + N' y7 Y! Z' D7 Z9 ]. b
  136.         }        
    7 n. k( U7 D# ?. Q* a, p6 w' d! b" s

  137. 8 X1 V6 `. H- I4 c- e
  138. + R: q; m: V+ S1 p
  139. 5 c/ ?( Q" M& f' T3 `( X; Q
  140.                
    * n4 x" c" m0 b/ y( p; `# l- Y4 d
  141.                 else' d4 o) P7 u6 q! Q8 c' \4 F
  142.                         printf("输入错误!");& p- K% y2 s9 ^6 r; j! s9 w1 b

  143. : G% G! S; {: r
  144.     for(int i = 0; i < Rx_len ; i++) //清空接收缓存区
    3 u; {# R$ j* Y7 ^1 d# [
  145.     ReceiveBuff=0;//置0
    ! n$ W/ I3 W; g$ l+ v
  146.     Rx_len=0;//接收数据长度清零
    6 t; Q3 E& r! z) ^  ]" ]
  147.     recv_end_flag=0;//接收标志位清零
    7 M0 C, S& ^8 P) K, Y0 j$ ]4 p
  148.                 //开启下一次接收- z+ n+ Q+ q6 y
  149.     HAL_UART_Receive_DMA(&huart2,(uint8_t*)ReceiveBuff,BUFFERSIZE);
    ! {1 y6 C$ P( {3 s
  150.     }; @8 s, \5 q6 ?" V6 c

  151. ( }5 o  k0 p' Y, S4 A
  152. }
    9 I% A9 L, B% b) K. U' n" j
  153. 8 q; O8 h* ~$ B; y  v. r
  154. /* USER CODE END 4 */
复制代码
: h) R; @6 j7 s! B
演示/ p' w) c7 ]1 k$ [2 f7 B7 S0 N/ \
W25Q64芯片型号的ID为0XEF17,下方读取为0XC816,所以读取成功。
1 s9 T4 L% v( ?4 Y% `4 z8 q- `. ~  [
724107be5c7743688035f34171618ec0.png * F1 h+ E# H& U) R0 y% y
) J$ p3 ^+ V) B+ u% P  y# s) n
开机会打印出0,17,34扇区的前0x200个数据。
5 D3 T0 e- n! ^% x, x7 E. d. \

6 X. V* b2 F/ t# c1 R1 o 23708128edc5478382c20fa961eff4e8.png + R% f: |, A4 [5 a+ s, G5 ]7 O
: G1 C, `( H0 b* Q3 \8 A8 t
打印完原始数据之后将数据全部清零,清零完成如下图所示。/ }( E5 q4 U0 M) L' u) Z) D8 k% C* }

& C- F" ^" j2 o* y! a
0ac9a59d0a6f4138bbc3ea3e3e3c612f.png
# T+ ]( U9 t0 t) P$ B) X: H, \2 J$ u" ^5 b, [- U: G, Y
串口定义了ReceiveBuff[0]的数据为写入什么扇区,ReceiveBuff[0]为1写入扇区1,ReceiveBuff[0]为2写入扇区2,ReceiveBuff[0]为3写入扇区3,若为其他数据,则打印输入错误;ReceiveBuff[1]则为写入的位置。0 k- h- I8 }2 I# D
输入:00 05 01 02 03 04# d: w$ W6 O7 a6 X- z5 a' B7 Y
向扇区0的的05号位置开始写入数据01 02 03 04。# Z3 E2 s' a$ y5 I8 D- W1 K% h1 X

5 B' w) r! Y+ e# h0 O7 t) }
bc97fcddb01b4e3182345641d2fa28f2.png
; [' Z* |7 v7 G+ S9 l1 o  ?5 W2 V* i* ?2 A3 v5 P/ g8 `6 X
输入:00 28 11 12 13 14 15" p: m4 e7 w" e
向扇区0的的40(28是十六进制)号位置开始写入数据11 12 13 14 15。1 Q- J8 \0 ~) [" I- }
4 O  c% ~5 Y$ d( J: k
4770ed6a70c849228eba1429605c74a7.png
7 X+ b- P# X' d$ C
' v6 ]/ k/ N+ G  I% X% H" \( W2 S输入:17 10 aa bb
$ i% G3 x( T9 I4 G( e1 t7 z向扇区17的的16(10是十六进制)号位置开始写入数据aa bb。
& D5 H4 @' S/ k9 E  |
; Q" V* ^2 h& `, q' X9 B/ W
a3cb95aa3c694c7f90bf8d8b85a3d321.png % j$ @* b- K0 _6 Q" T& v# K& P

# s5 o/ P8 h0 ~/ u! q8 o& U1 j————————————————* Q% E2 _" X4 O! f
版权声明:记帖. J9 e* _& r6 n0 F& b

# @! D; |  [% o" N1 T: Y) q' U# T8 j7 t" O5 R1 i
" t. v; D9 ]& t- t0 v; Z3 v  @
收藏 评论0 发布时间:2022-10-20 19:14

举报

0个回答

所属标签

相似技术帖

官网相关资源

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