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

【经验分享】STM32F103:内部Flash的读写

[复制链接]
STMCU小助手 发布时间:2022-5-4 23:00
一、Flash基本知识0 h$ }8 o8 r4 a) g4 D7 x9 P
1. Flash容量

7 S6 e' N: p6 {9 Q( NFlash根据容量大小可以分为以下三种:
: d! G' x3 `4 M1 O; ^3 \2 R) t+ M: h" x- f- o
1、小容量产品:Flash大小为1-32KB(STM32F10X_LD): }0 b0 B% {+ x6 h/ g) f7 x0 L; K
2、中容量产品:Flash大小为64-128KB(STM32F10X_MD)
: X/ G( v0 b, O3、大容量产品:Flash大小为256KB以上(STM32F10X_HD)7 h) y* ?2 h/ I1 H1 o
2. ST库函数
% e" M+ s  ]# X, T$ `ST库中对Flash操作主要提供了以下几类操作API函数:1 l! R$ H6 {$ R6 h' V1 s. m! E7 N

9 f' S* o7 j$ @; O2.1 Flash解锁、锁定函数
& G% m  `8 z7 w! m0 h$ K
  1. void FLASH_Unlock(void);    //解锁函数:在对Flash操作之前必须解锁( N/ g% |  V* z, B& L$ _
  2. void FLASH_Lock(void);      //锁定函数:同理,操作完Flash之后必须重新上锁
复制代码
3 E4 n+ D  f" g& w  A
2.2 Flash写操作函数; ?4 x8 b) W& B9 w/ I) S; S
  1. FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);             //32位字写入函数8 }5 u) T: F# i$ B) v* U
  2. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);         //16位半字写入函数
    ( W4 x/ R9 B, t1 e
  3. FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);    //用户选择字节写入函数
复制代码

% C  I  k; [, `2 ]注:这里需要说明,32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。
: J2 b, j8 D6 ~, a& K/ y* e& M/ Y
2.3 Flash擦除函数
+ m& z$ \5 c! M( E( x/ }. |
  1. FLASH_Status FLASH_ErasePage(uint32_t Page_Address);        //擦除一页! J: Z$ k& \7 L- S# i: a! O
  2. FLASH_Status FLASH_EraseAllPages(void);                                        //擦除所有页
复制代码
- ]1 Q" ~1 ~5 p( S8 k! r/ `# i2 m
2.4 获取Flash状态5 j; J# \/ D+ D9 p2 q& m9 r
  1. FLASH_Status FLASH_GetStatus(void);
复制代码

% W0 T  ~- h. D( p: I) u获取Flash状态函数,主要是为了获取Flash的状态,以便于根据状态对Flash进行操作。该函数返回值是通过枚举类型定义的,在代码中可以看到FLASH_Status类型定义如下(具体含义看注释即可):
1 n: x9 E# O/ R+ z' s( s: \) x
3 y, n: ]+ m4 K/ _& }: y) L# @
  1. typedef enum {. W' T* C- ?4 l2 m( i( K  b9 J9 {
  2.     FLASH_BUSY = 1,       //忙
    ! e4 z8 y8 T( [+ @
  3.     FLASH_ERROR_PG,       //编程错误$ F( G( S. A1 @4 p7 a! o! H. n2 ?
  4.     FLASH_ERROR_WRP,      //写保护错误
    2 x: Y4 t1 e5 M! L9 q4 b# e, F
  5.     FLASH_COMPLETE,       //操作完成; v# P9 |$ S, U( {; N
  6.     FLASH_TIMEOUT         //操作超时
    1 _0 X$ i4 }% h! k, D- z0 N+ j
  7. }FLASH_Status;
复制代码

# m7 B3 X& ^. W: M2.5 等待操作完成函数

: O3 P4 @& u( x" E& q" p7 k0 a$ }
  1. FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
复制代码
5 S: O/ Q6 l- E% L; S
注:在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。8 F# {/ w, q( V; Z' r! a0 i3 e

3 N" @; D1 ~, W( {二、Flash的写入和读取* N6 n9 E6 Z, T: \
此次操作Flash使用的MCU是STM32F103C8T6,在数据手册中,可以看到STM32F103C8T6的flash起始地址是0x0800 0000,而STM32F103C8T6的Flash大小为64K,可以计算出STM32F103C8T6的Flash地址范围是:0x0800 0000——0x0800 FFFF。这里选取0x0800 F000作为读写操作的起始地址,对于C8T6这款MCU,操作这个起始地址应该算是很安全的范围了。
5 a8 {5 o2 P2 p' c2 _! e+ ]3 o0 H" m0 d, V4 r7 T
1.Flash的写入
9 V$ [: A+ W% ?; p" k根据ST库提供的上述函数,我们可以自己编写Flash的写入操作代码如下:
0 K$ }) u; l2 D3 s
2 G8 g+ b" q. k
  1. #define STARTADDR 0x0800F000 //STM32F103C8T6适用
    , K$ g* Q% \# y2 R3 l1 W
  2. ) N9 v- l  G$ M1 E8 V9 J9 H
  3. /*
    / F* o/ G  b% g* M# z( |( d$ }
  4. * Name:            WriteFlashData* u  e1 N# t) ~) {$ U
  5. * Function:        向内部Flash写入数据9 |+ n- N8 g7 g
  6. * Input:            WriteAddress:数据要写入的目标地址(偏移地址)
    ' H+ j: y( L8 Q" q7 |  h
  7. *             data[]:      写入的数据首地址
    8 O3 _; e: W8 G6 `0 k! L
  8. *             num:         写入数据的个数; U  y0 _9 M. a0 G; N
  9. */3 f6 S! d) x9 Q" i$ O
  10. void WriteFlashData(uint32_t WriteAddress, uint16_t data, uint32_t num)" M" }! d7 S" l2 B& S) o" B2 s/ n
  11. {4 a' w5 I2 d! _/ y2 `3 J5 W
  12.         uint16_t sign =        0;        //标志位
    ( b- C" [# r: ]2 s& [& B$ @
  13.         6 @8 c- r3 D# P6 z9 Q6 p
  14.         FLASH_Unlock();     //解锁Flash; h7 G, ^% x) X& A# g! S9 G5 q1 i
  15.         FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);  // 清除所有标志( Y" A$ I! N; ^; G* e7 }- O
  16.         sign = FLASH_ErasePage(STARTADDR);        //擦除整页
    $ j0 F* F0 Z2 M5 x2 x
  17.         if(sign == FLASH_COMPLETE)        //Flash操作完成
    ' m! y9 ]  V( b, T( i/ n9 h
  18.         {1 m$ P' q7 I) u0 s0 M0 G- f( w4 d
  19.                 for(uint32_t i=0;i<num;i++)
    " J  F( p4 y5 K4 m$ `
  20.                 {# L; J/ l) B# n7 R  U
  21.                         FLASH_ProgramHalfWord(STARTADDR+WriteAddress+i*2, data<i>);        //写入数据0 L/ c; ^4 \; ^; w
  22.                 }
    ' V7 O# ~( W/ i% b
  23.         }
    5 _& d" p$ U2 q- `9 z7 ~- \$ q% E
  24.         FLASH_Lock();        //重新锁定Flash* T8 D1 W5 q/ u
  25. }</i>
复制代码

& |, h8 B, Y2 r% r- q2.Flash的读取
+ U- g3 Y0 \, [+ Q; ]
根据ST库提供的上述函数,我们可以自己编写Flash的读取操作代码如下:  J' U) a: }6 o& D0 r

" G: x0 \( L8 L/ E3 F8 _6 ]! J
  1. #define STARTADDR 0x0800F000 //STM32F103C8T6适用
    8 H8 m2 |: d! j* M' x7 y
  2. /*
    - m( R  J) L+ U, U5 g' e4 }
  3. * Name:            ReadFlashData& l0 ?3 H- Q3 r: A% z3 ]2 Z
  4. * Function:        从内部Flash读取num字节数据
    # R" D" g, t& |$ k( z
  5. * Input:            ReadAddress:数据地址(偏移地址)" i% _) o2 s  \
  6. *              dest_Data:  读取到的数据存放位置指针
    ! |4 ?' }. T4 Y: H5 I! i. z! N
  7. *              num:        读取字节个数. e4 V( U$ r7 X: C. ~# p
  8. */0 N$ \; {1 l  S/ A
  9. void ReadFlashData(uint32_t ReadAddress, uint8_t *dest_Data, uint32_t num)
    8 M" D4 [9 G) {) d6 R
  10. {
    # g6 I2 |) g* P6 j
  11.         for(uint32_t i=0;i<num;i++)
    6 Z7 w: |' j( {5 G2 N4 l5 \6 `% P
  12.         {
    & H( M6 r- a+ p: x+ S  y
  13. <i>                dest_Data=*(uint8_t*)(STARTADDR+ReadAddress+i);        //读取数据
    , `0 F% X  o) q5 ]  ?/ C
  14.         }7 N5 l, I+ {, y
  15. }
    4 w1 ]4 Y- {2 Q. D2 |  N
  16. </i>
复制代码

1 j9 Z& ]) v' s2 n+ x9 e
3 k# ?$ ^* a1 h! q( A* \4 Y9 l# o
收藏 1 评论0 发布时间:2022-5-4 23:00

举报

0个回答

所属标签

相似分享

官网相关资源

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