工程: InternalFlash.rar (3.93 MB, 下载次数: 3) 2019-10-14 08:40 上传 点击文件名下载附件 STM32 芯片内部的 FLASH 存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下: 其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中可以看到: 假如我们要下载的程序大小为4.05KB,则第0、1、2页用于保存我们的程序,我们需要掉电保存的数据只能保存在第3页至第255页这一部分空间内。我们最终要下载的程序大小可在工程对应的.map文件中看到。.map文件可以双击工程的Target的名字快速打开,如: 下面对STM32的内部FLASH进行简单的读写测试:STM32的内部FLASH读写测试过程图如下(省略异常情况,只考虑成功的情况): / d" I( p/ Z ]: [2 c示例代码:本例的关键代码如下:#define MAIN_CONFIG4 j3 x: B9 |; }" ^3 f- @ #include "config.h" + p( R; R D! Y" _; C# n$ J( g ' v7 ?9 Y% S' G) h1 I# M: ^/* STM32F103ZET6有256页,每一页的大小都为2KB */* l, k4 s* {- e' b+ Y( Z6 K #define ADDR_FLASH_PAGE_255 ((uint32_t)0x0807F800) /* Page255 2KB */ 9 ?2 ]; w2 D+ ~9 D/ z! l % [& T" h# ?& U! a& P2 ` \/* FLASH读写测试结果 */ ! V' J3 L3 s3 z( H! u: g1 A0 p#define TEST_ERROR -1 /* 错误(擦除、写入错误) */ 1 B1 c( p0 A. b9 h& q" \, o+ b#define TEST_SUCCESS 0 /* 成功 */ / Z$ c: `0 ^( h3 ^# m#define TEST_FAILED 1 /* 失败 */- l, y! S; ]1 P$ k: S9 h2 W5 E ! y- v6 I. M1 ^3 f) y, B8 | /* Flash读写测试buf */ 1 @& q- F# R' s7 h0 f#define BufferSize 6 * V/ k- v# u3 \6 f" @& V6 l# auint16_t usFlashWriteBuf[BufferSize] = {0x0101,0x0202,0x0303,0x0404,0x0505,0x0606};9 b: C- x8 S' X% r8 ]4 @: s uint16_t usFlashReadBuf[BufferSize] = {0}; - l, Z( s& K- |# t0 D7 Q% c' Z3 j- G2 i7 v$ v$ o- b /* 供本文件调用的函数声明 */ n, k) o0 X; q$ G4 _. kstatic int FlashReadWriteTest(void); 5 F' L B' T/ @% [ , ~/ u6 D+ T" g( X) {/ e! H /******************************************************************************************************* 5 T7 i0 x3 L! [* ]4 O! u3 G** 函数: main) J4 C# o8 ?6 s/ M; ~$ D& O9 M. h$ z! C **------------------------------------------------------------------------------------------------------ 1 z; F! X8 s0 b7 i** 参数: void: }" `5 y1 z+ @3 i ** 返回: 无( v; A+ b- U! v% a% T; n8 ? ** 说明: 主函数( e7 j, v( ^& s* E4 v ********************************************************************************************************// x" ^# k, o7 i( }( ~' M# n {# Z int main(void)+ Z+ J# T% U N j1 u1 K { 3 l( ]/ r% w0 H6 W% {7 _ /* 上电初始化 */ 6 K( y9 E; h7 n% @ SysInit();: x! Z9 _# n- N' v! K+ n3 g ( c0 @( F' \3 Q! ` /* 内部Flash读写测试 */' B! {; x! V) Z if (TEST_SUCCESS == FlashReadWriteTest())$ Z: O& r- s2 V { 9 {' v3 M) F- \# v printf("Flash test success!\n"); - k! O" y% l1 u) q- ~ }; }+ R5 c5 g# A$ p/ ~" R else/ T( N$ z! {5 ^( X0 b) k* k! W: N { ; X: P5 X$ a7 s4 ]8 R0 j printf("Flash test failed!\n"); U" V! ?( k3 Q A) P } 8 O0 i7 l7 C9 w: l* |3 q% I6 D 6 Z1 ]/ ~ D& J while (1) 9 ]' N+ K$ o* n c; k {}' Y2 k: J5 r: F# w0 {- b0 O }2 A8 v5 r. F0 |8 ` * j( u, f8 E$ W9 \, x [+ U' j /******************************************************************************************************* 3 @# ]3 D+ L/ M/ X) x8 v** 函数: FlashReadWriteTest, 内部Flash读写测试函数 8 U1 z9 Z2 w5 |# a& c+ h- ?9 c**------------------------------------------------------------------------------------------------------9 p: r/ M! y+ h. c9 u: J* w ** 参数: void! @9 T! M5 ?$ d) k$ j7 j* V a; w ** 返回: TEST_ERROR:错误(擦除、写入错误) TEST_SUCCESS:成功 TEST_FAILED:失败9 T" a# P" T B ** 说明: 无2 Z$ O; ?$ J" \2 e# P7 P; o$ N" X ********************************************************************************************************/ % _! n1 K- C) B8 M* {static int FlashReadWriteTest(void) $ _6 I2 Z' t* H* l7 Z' w8 j5 }{8 D6 L1 Y- c; `: P$ L% P uint32_t ucStartAddr;6 A5 b" k% N5 ~- [/ H+ D X0 l7 @ - ?4 P" W- A* r" ^& ~ /* 解锁 */, k4 ~ b" m7 p5 M' `% K# k FLASH_Unlock(); 7 `+ w7 o# `' Z1 l4 S) c ! x F) r& ~3 l: s6 c. B /* 擦除操作 */ : r$ C2 A8 t8 X3 r, O. i ucStartAddr = ADDR_FLASH_PAGE_255;0 g0 z# _' t5 p6 _& U if (FLASH_COMPLETE != FLASH_ErasePage(ucStartAddr)) 0 D' N3 D v0 ]. ^ { 8 r' Y/ A" E: t; v printf("Erase Error!\n"); - z/ A* `) y% A# K4 R8 p0 N return TEST_ERROR;8 G8 C, n9 q% B; V v3 m, H. v } + F P7 B+ ~9 w d( L else + x, }7 U* d+ H: T6 d0 Q! n { 9 c9 Q; `, O4 Z" `2 j3 q# o ucStartAddr = ADDR_FLASH_PAGE_255;. _3 r$ R: E* K. v) S4 p \ printf("擦除成功,此时FLASH中值为:\n");3 l5 _3 S$ X* A9 B( w for (int i = 0; i < BufferSize; i++) 8 a& F/ }, W, B { $ F; u3 |6 `* T# _' i usFlashReadBuf = *(uint32_t*)ucStartAddr;! v b$ l- i; M2 v& X4 t printf("ucFlashReadBuf[%d] = 0x%.4x\n", i, usFlashReadBuf);, P7 w8 F2 O% O' K ucStartAddr += 2;; L+ g* c3 [& u" D- H3 P8 d+ Q }- |$ q) H6 ~% V! a: W( I: V- Z }8 t5 h7 _! P- p# [4 Z # b1 a7 W6 h0 g. k2 ?9 f /* 写入操作 */ 4 N& M0 M ?# n' ? ucStartAddr = ADDR_FLASH_PAGE_255;7 r$ Y% _" N! P printf("\n往FLASH中写入的数据为:\n"); ) K" F8 Z8 r, O& {" ? for (int i = 0; i < BufferSize; i++) , s, ^! O3 `! i) R4 D, F' n& ^ { 0 k- a6 a, ^) @) n if (FLASH_COMPLETE != FLASH_ProgramHalfWord(ucStartAddr, usFlashWriteBuf)) 6 q9 R' }8 W9 q9 n7 Y { 6 ^$ Q; B" Z6 j" P5 |/ J% U1 t, s printf("Write Error!\n");! G2 U8 u) G, D2 q, P9 S return TEST_ERROR;/ m9 A4 k: @9 v |5 {5 g- |6 T }! h4 X+ U' v( l& b printf("ucFlashWriteBuf[%d] = 0x%.4x\n", i, usFlashWriteBuf); . T F# p2 E) H$ G$ m ucStartAddr += 2;+ n& A: H; \+ n6 `, s4 F }/ y" f" D6 n4 K+ J + m8 O4 @$ _" K, C1 F1 c /* 上锁 */7 _% Q: O/ U8 j0 M. k FLASH_Lock(); 5 M) Z, |4 X+ t3 A! d+ x ) C* Q2 E; n& x- D- d2 y /* 读取操作 */# M& h: I% r/ T# o+ Z+ }7 q ucStartAddr = ADDR_FLASH_PAGE_255;3 z; F0 d2 \3 R; I# s$ I; q printf("\n从FLASH中读出的数据为:\n"); / S A3 i& F5 w% ~6 T for (int i = 0; i < BufferSize; i++)) A* h" z: I- c { ' s. f) {$ p" X+ F+ V# b usFlashReadBuf = *(__IO uint16_t*)ucStartAddr; / N, I# G. l9 c; c' n7 r" ?, Y$ { printf("ucFlashReadBuf[%d] = 0x%.4x\n", i, usFlashReadBuf); . J9 f3 g" ?# R/ T. ^- i ucStartAddr += 2;/ M4 s& w) r* Z: m } 8 W& `7 D2 k% r6 ]7 a% t ' |6 k& L2 D8 D4 v" a. b* A /* 读出的数据与写入的数据做比较 */ ' z+ _& ?# K2 s. l, Y" S) [9 j for (int i = 0; i < BufferSize; i++) - ~ _) `$ t& D1 F8 G1 X6 F {5 o& n: k8 f: v if (usFlashReadBuf != usFlashWriteBuf)- [' X! {; X7 s5 ?% k/ @& l {/ b3 ~- L( k+ C return TEST_FAILED;9 A) Z$ u1 ~ K } 2 O" b* n- m" _ } ) n; q! F) a* q4 A' \ 2 V. s+ n7 T! b/ Y return TEST_SUCCESS;" P1 k3 ]2 K* z }( X8 `7 r# Y. d+ |$ E / A/ h: C3 W2 S; S4 Q j- F ( r( X9 P. F+ A$ ^/ `& j8 s$ J/*********************************************************************************************************, L6 A6 u( s7 H2 A7 \( k# m ** End Of File4 m. I% u, {$ W% K _, b" b; u' B& o ********************************************************************************************************/! e0 @( z1 C, A! v: | (1)进行解锁操作STM32 的闪存编程是由内嵌的闪存编程/擦除控制器(FPEC)管理 ,这个模块包含的寄存器如下: STM32 复位后, FPEC 模块是被保护的, 不能写入 FLASH_CR 寄存器; 通过写入特定的序列到 FLASH_KEYR 寄存器可以打开 FPEC 模块(即写入 KEY1 和KEY2) , 只有在写保护被解除后, 我们才能操作相关寄存器。 固件库中的函数为:void FLASH_Unlock(void);8 ~2 j* e# e5 ` (2)擦除将要写的页STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFF),否则无法写入,在 FLASH_SR 寄存器的 PGERR 位将得到一个警告。 STM32 的闪存擦除分为两种:页擦除和整片擦除。 也就是其最小擦除单位为1页,尽管你只需往某页里写10个字节数据或者更少的数据,你也必须先擦除该页(2*1024个字节)。我们这里使用按页擦除,固件库中按页擦除的函数为:FLASH_Status FLASH_ErasePage(uint32_t Page_Address);其返回值为枚举:typedef enum ) ^& S$ P; ^$ E; B{ ( K8 ^$ h2 L3 j, O+ @( n- ^ FLASH_BUSY = 1, /* 忙 */ 6 h0 {. y. }$ V% v4 ]: i$ ? FLASH_ERROR_PG, /* 编程错误 */* H7 K- j5 R7 Q FLASH_ERROR_WRP, /* 写保护错误 */ ' m, g4 x! b( [2 c( A FLASH_COMPLETE, /* 操作完成 */ ) m4 H# n. O! r+ P" E$ y FLASH_TIMEOUT /* 操作超时 */ ) f {5 E' m: H}FLASH_Status;: x$ h- \- x) V$ |8 Z (3)往上一步擦写成功的页写入数据STM32 闪存的编程每次必须写入16 位。虽然固件库中有如下三个写操作的函数:FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); 7 ^7 u+ ]% s5 i gFLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); r2 { G. e" v& E( t4 H FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);分别为按字(32bit)写入、按半字(16bit)写入、按字节(8bit)写入函数。32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。 写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。 7 m. W* F# g2 V) E# I(4)写入操作完成后进行上锁操作对FLASH进行写操作完成后要进行上锁操作,对应的固件库中函数为:void FLASH_Lock(void); R: y3 G0 V) s4 T4 B(5)读出数据固件库中并没有与读操作的函数。读操作其实就是读取FLASH某个地址的数据。 ! g& ]/ e" O2 O; [# L(6)对比写入的数据与读出的数据是否相等最后对比我们写入的数据与读出的数据是否完全一致,若一致则表明读写测试成功,否则失败。 : e, g/ y5 w% u$ z+ ~程序执行结果: 可见,读出的数据与写入的数据一致,表明读写测试成功。' J% ?1 q4 w. r1 x. z: ^ 最后STM32的内部FLASH读写步骤大致如上,有时候我们还需要封装一些读写函数,但步骤大都如上。写入数据之前需要先进行擦除操作。以上就是本次的笔记分享,如有错误,欢迎指出!& N( O/ m9 a8 s& ]3 m5 u2 U% m " L, }( G! H6 N% B) U# c% U) n 3 ]+ E5 d) r7 b 8 y$ _ a0 d) |# }5 R# H: ~
多谢支持