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

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

[复制链接]
STMCU小助手 发布时间:2022-5-4 23:00
一、Flash基本知识6 `  b9 x, ?* s: I/ k( v
1. Flash容量
9 P8 D" F; Q* O8 j6 o5 \
Flash根据容量大小可以分为以下三种:6 S* b, ^2 n5 j0 U+ Y
0 Q! S1 z; d, R" |! `
1、小容量产品:Flash大小为1-32KB(STM32F10X_LD)* U, Q. m5 ?1 U6 n7 u
2、中容量产品:Flash大小为64-128KB(STM32F10X_MD)
# U$ v, I# s* J! o7 B3、大容量产品:Flash大小为256KB以上(STM32F10X_HD)$ e" g+ Q$ t0 ^# W
2. ST库函数! U7 ?( X5 W0 U1 T
ST库中对Flash操作主要提供了以下几类操作API函数:
; m: g' }9 r* d; U) D
4 [. W% i+ t+ Y7 k" n# }2.1 Flash解锁、锁定函数: E$ u8 P& [1 o5 p9 L$ b; T
  1. void FLASH_Unlock(void);    //解锁函数:在对Flash操作之前必须解锁+ l7 N9 f9 G6 O. Y# r
  2. void FLASH_Lock(void);      //锁定函数:同理,操作完Flash之后必须重新上锁
复制代码

! P# e1 ]) T- z" S% b0 P9 E2.2 Flash写操作函数
; g* _" m) w: d0 [+ ]
  1. FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);             //32位字写入函数
    / {, \0 O) k$ Q/ }/ |( N
  2. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);         //16位半字写入函数" I$ M5 V- d! R, a, K
  3. FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);    //用户选择字节写入函数
复制代码
; P  R* _* C" _) ~4 G. r1 _8 c
注:这里需要说明,32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。0 v) N. ?1 Q( M  s2 b2 U  H
6 Y, v) r" O0 K- M/ j
2.3 Flash擦除函数$ T) w6 P1 C* e3 x. m* ^
  1. FLASH_Status FLASH_ErasePage(uint32_t Page_Address);        //擦除一页
    $ Y; g' g: y6 t, I8 A
  2. FLASH_Status FLASH_EraseAllPages(void);                                        //擦除所有页
复制代码

; s- v% G- Y$ t6 V2.4 获取Flash状态/ U5 @3 A& E% k/ Y7 s
  1. FLASH_Status FLASH_GetStatus(void);
复制代码

- Y( Q& m% M/ q5 m! Z% O获取Flash状态函数,主要是为了获取Flash的状态,以便于根据状态对Flash进行操作。该函数返回值是通过枚举类型定义的,在代码中可以看到FLASH_Status类型定义如下(具体含义看注释即可):
, Q4 I, N5 K% Z
) U3 F4 d& @/ L" i. o' V0 }1 K
  1. typedef enum {& b) ~2 g0 Q$ \
  2.     FLASH_BUSY = 1,       //忙
    , x8 _: o5 H7 y; A
  3.     FLASH_ERROR_PG,       //编程错误
    8 E0 p: o4 j, L* a% e
  4.     FLASH_ERROR_WRP,      //写保护错误
    + L7 \" h) j' Q& `0 ]9 y
  5.     FLASH_COMPLETE,       //操作完成( D) e+ ?) u$ B, K: P! h  F' U
  6.     FLASH_TIMEOUT         //操作超时5 }% U8 i' n6 B
  7. }FLASH_Status;
复制代码

3 m( R+ I5 g0 U2.5 等待操作完成函数

: ]4 B6 k0 _' a: p# @" ?- ?& K& V
  1. FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
复制代码

+ x8 L2 g4 a  R# y+ s注:在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。
6 S  S7 E) `2 C- w5 [/ q: ~4 M, f  f5 R7 p& L" \
二、Flash的写入和读取
; b4 N$ k2 L% t1 q2 s此次操作Flash使用的MCU是STM32F103C8T6,在数据手册中,可以看到STM32F103C8T6的flash起始地址是0x0800 0000,而STM32F103C8T6的Flash大小为64K,可以计算出STM32F103C8T6的Flash地址范围是:0x0800 0000——0x0800 FFFF。这里选取0x0800 F000作为读写操作的起始地址,对于C8T6这款MCU,操作这个起始地址应该算是很安全的范围了。
2 N' u7 t8 D) F( U1 ~# P5 i) H  Y( J
1.Flash的写入5 q8 }/ E0 f* g8 t4 d( l8 d, |, H
根据ST库提供的上述函数,我们可以自己编写Flash的写入操作代码如下:
1 c, f7 L* _' Q3 y! @3 ~; a' g8 w7 T* b
  1. #define STARTADDR 0x0800F000 //STM32F103C8T6适用; Y; `. o% c/ [' m; \/ O6 R# k- d

  2. ( p8 ]0 ?& r' M0 w  m* P% C
  3. /*
    * J+ d# W7 g  \4 m1 [
  4. * Name:            WriteFlashData& B6 I3 W3 p" j5 N1 M4 c
  5. * Function:        向内部Flash写入数据1 x7 H, }/ T6 V0 h# r( M1 S1 p/ K
  6. * Input:            WriteAddress:数据要写入的目标地址(偏移地址)
    * c  ~4 P3 O* M( `
  7. *             data[]:      写入的数据首地址
    + M( [% @0 ~4 S: H* U7 U" L  E1 u: R  ^
  8. *             num:         写入数据的个数- H$ r5 V8 x" p6 A6 K2 Q
  9. */( H, Y& J0 O+ ^& f
  10. void WriteFlashData(uint32_t WriteAddress, uint16_t data, uint32_t num)
    ( `$ u  h; ^) O: @
  11. {$ r& @  p5 @) `0 |+ }7 f) k
  12.         uint16_t sign =        0;        //标志位
    % D' }2 o0 W1 L. F% w8 c
  13.         
    / D7 P9 D* w  I* S& r
  14.         FLASH_Unlock();     //解锁Flash9 [, {" b* M7 ?$ y- ~
  15.         FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);  // 清除所有标志9 K! Z/ g7 W9 I$ ]! [" M
  16.         sign = FLASH_ErasePage(STARTADDR);        //擦除整页
    % y4 F3 s! K- }- P" k  l
  17.         if(sign == FLASH_COMPLETE)        //Flash操作完成
    & Y! F" I2 X& U7 R# D) B: r
  18.         {* {$ z$ Q; ^! p# u' P: P8 g
  19.                 for(uint32_t i=0;i<num;i++)
    / k8 O- x- d7 S: q6 S
  20.                 {9 G( u. c) }4 A6 V7 u$ Q
  21.                         FLASH_ProgramHalfWord(STARTADDR+WriteAddress+i*2, data<i>);        //写入数据7 U% q. l+ D0 u* ]) f2 S% Z4 W- L
  22.                 }
    : c: ]% q/ e4 \. G- a& M
  23.         }
    4 [) T* c4 P3 J7 k- B- |
  24.         FLASH_Lock();        //重新锁定Flash* \, r! m9 f3 h, o$ {
  25. }</i>
复制代码

0 }' _; R% s  M: j/ D2.Flash的读取

2 ~. d8 l  ^; g根据ST库提供的上述函数,我们可以自己编写Flash的读取操作代码如下:  g1 ~  C$ i6 \# y  P) l

; R1 @6 e9 |( D
  1. #define STARTADDR 0x0800F000 //STM32F103C8T6适用7 {3 a8 |9 k' j2 t' {
  2. /*/ b, a- N/ y0 C0 V( A7 N
  3. * Name:            ReadFlashData
    " d: I) n8 h+ _& Y9 Z
  4. * Function:        从内部Flash读取num字节数据! X, C& u9 H1 a
  5. * Input:            ReadAddress:数据地址(偏移地址)
    + q9 T7 X8 F. }
  6. *              dest_Data:  读取到的数据存放位置指针1 G' m4 ]8 s1 E) d/ @
  7. *              num:        读取字节个数
    0 z0 w4 y! ]% b& ~) B6 v) F
  8. */
    / O" \( o$ c) N2 Z! r
  9. void ReadFlashData(uint32_t ReadAddress, uint8_t *dest_Data, uint32_t num)
    / Y" J+ Q3 i, Y( T
  10. {
    / C+ ^4 [9 q1 l( M1 v
  11.         for(uint32_t i=0;i<num;i++)" A% u9 I7 A1 m' _% @1 w( y
  12.         {
    - n. q7 b7 X" A2 n0 Y2 @4 F" t7 l
  13. <i>                dest_Data=*(uint8_t*)(STARTADDR+ReadAddress+i);        //读取数据
    3 h5 q6 f7 J& C! V7 x1 A
  14.         }0 Y* o9 |; x  E' G1 J2 _
  15. }
    2 Q  ^& d" B1 t% K* Z5 L9 a
  16. </i>
复制代码

6 u- [4 W" {3 e6 X8 j
" M9 `/ T2 X3 q" O
赞 收藏 1 评论0 发布时间:2022-5-4 23:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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