|
编译环境:我用的是(Keil)MDK4.7.2 stm32库版本:我用的是3.5.0, Y4 j7 z2 e C8 e# @ 一、本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料。. P8 h+ N6 X- s5 S1 } 对STM32 内部FLASH进行编程操作,需要遵循以下流程: Y5 @7 E/ L3 t" B FLASH解锁% c2 s' q K3 a" S; r1 }2 D, n0 B 清除相关标志位 擦除FLASH(先擦除后写入的原因是为了工业上制作方便,即物理实现方便)% E, p5 m0 C+ H, L* \7 \ 写入FLASH* o% T0 ~) m2 Z. M, T+ @ 锁定FLASH: A3 F ~9 k. J7 c* w% | 实例: #define FLASH_PAGE_SIZE ((uint16_t)0x400) //如果一页为1K大小 #define WRITE_START_ADDR ((uint32_t)0x08008000)//写入的起始地址 #define WRITE_END_ADDR ((uint32_t)0x0800C000)//结束地址# o" F' g+ |( o/ I2 {' A uint32_t EraseCounter = 0x00, Address = 0x00;//擦除计数,写入地址 uint32_t Data = 0x3210ABCD;//要写入的数据4 \; ~$ @6 f! `" m uint32_t NbrOfPage = 0x00;//记录要擦除的页数 volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH擦除完成标志*/ void main()3 Q8 F# z9 N/ e7 l, V" @+ } {# m; P# J/ N; q7 m/ ? /*解锁FLASH*/# l8 X0 S) {! {9 ?+ [$ [* l- m2 K/ e# }: ^ FLASH_Unlock();* l% M1 s9 P2 b* @ /*计算需要擦除FLASH页的个数 */ k ?) S. _ V5 o; x NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;0 |8 K) u7 c0 |( D4 R1 O* ?3 f /* 清除所有挂起标志位 */ FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); /* 擦除FLASH 页*/ for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)5 f! U& @ ~8 L9 A/ d( | { FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));8 E. e& U \0 t; g$ v! [" O/ I3 Q; O }# @2 ]; G2 l' M; q. P \ O' W /* 写入FLASH */- U! h$ _4 P* F& b2 S Address = WRITE_START_ADDR;7 t; S7 x: n. p while((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE)) { E( w6 }4 h Q' b7 W" b) ]) D FLASHStatus = FLASH_ProgramWord(Address, Data);" h6 { i9 P8 ^( V5 f2 O Address = Address + 4;7 D( P$ u# o7 p$ ?' A1 c }8 ~2 d# |- j; O9 E" T /* 锁定FLASH */7 B) B8 u1 ~2 v' }, Z" | FLASH_Lock(); b# U4 u3 Q' y4 l7 u* D }" t3 p' w5 @0 \, P 二、FLASH 擦除(以及防止误擦除程序代码) 1、擦除函数0 d) s3 F9 k! _+ V5 V FLASH_Status FLASH_ErasePage(u32 Page_Address)只要()里面的数是flash第xx页中对应的任何一个地址!就是擦除xx页全部内容!
防止误擦除有用程序代码的方法 方法一:首先要计算程序代码有多少,把FLASH存取地址设置在程序代码以外的地方,这样就不会破坏用户程序。原则上从0x0800 0000 + 0x1000 以后的FLASH空间都可以作为存储使用。如果代码量占了 0x3000, 那么存储在 0x0800 0000+ 0x4000 以后的空间就不会破坏程序了。 方法二:先在程序中定义一个const 类型的常量数组,并指定其存储位置(方便找到写入、读取位置),这样编译器就会分配你指定的空间将常量数组存入FLASH中。当你做擦除。读写操作时,只要在这个常量数组所在的地址范围就好。 const uint8_t table[10] __at(0x08010000) = {0x55} ;5 ~" a ~9 |. Y3 h& ~ MDK3.03A开始就支持关键字 __at() 。; u# X- ^% p% Z3 j* f, I 需要加#include <absacc.h> 方法三:在程序中定义一个const 类型的常量数组,无需指定其存储位置。只要定义一个32位的变量存储这个数组的FLASH区地址就行。 uint32_t address;//STM32的地址是32位的 const uint8_t imageBuffer[1024] = {0,1,2,3,4,5,6,7}; address = (uint32_t) imageBuffer;/*用强制类型转换的方式,可以把FLASH中存储的imageBuffer[1024]的地址读到RAM中的变量address 里,方便找到写入、读取位置*/ : L; W8 r) f6 J3 X+ s ` 方法四:利用写保护的方式(没研究明白)9 n0 w3 u) t7 t) C, ~; E 三、FLASH写入/ Z3 n8 z! z, I* @1 {0 @& |5 x/ l/ _ FLASH的写入地址必须是偶数(FLASH机制决定的FLASH写入的时候只能是偶数地址写入,必须写入半字或字,也就是2个字节或是4字节的内容)
8 c# @& A; p3 U; @1 Z2 {, Q5 Q z 四、FLASH 读取方法 *(uint32_t *)0x8000000;//读一个字' F* T! ?/ V7 F8 z *(uint8_t *)0x8000000;//读一个字节; *(uint16_t *)0x8000000;//读半字; 举例: uint8_t data; data = *(uint8_t *)0x8000000;//就是读取FLASH中地址0x8000000处的数据- \1 V H( u5 W: H* O8 X 五、几个有用的子函数$ G; L. K7 n! v+ R# @+ A /* 功能:向指定地址写入数据2 V1 ?0 U( K- z; U2 N 参数说明:addr 写入的FLASH页的地址/ _+ a& e$ ]8 @4 o% i6 M7 F) ?% \9 o9 } p 被写入变量的地址(数组中的必须是uint8_t类型,元素个数必须是偶数) Byte_Num 被写入变量的字节数(必须是偶数) */ void FLASH_WriteByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num) { uint32_t HalfWord;; _" v$ Q4 N6 |' u3 o1 D Byte_Num = Byte_Num/2; FLASH_Unlock();7 O7 p6 p- @1 K* W+ S' } FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASH_ErasePage(addr);" y$ I: O% t* j, Q; R while(Byte_Num --) { HalfWord=*(p++);9 I' {5 z" Y B5 n HalfWord|=*(p++)<<8;: H- D0 r, m# d7 j) l FLASH_ProgramHalfWord(addr, HalfWord);' ?% h0 p8 F8 X# i addr += 2; } FLASH_Lock(); } 例:, p3 \7 D( B3 L3 ]# e$ ] uint8_t data[100];6 S1 Z/ V1 |& i; \7 V FLASH_WriteByte(0x8000000 , data , 100);/*数组data的数据被写入FLASH中*/ /*7 _) V3 S. D% t/ L$ }+ C 功能:从指定地址读取数据 参数说明:addr 从FLASH中读取的地址3 g$ s: O* q0 B8 E p 读取后要存入变量的地址(数组中的必须是uint8_t类型)' ]% a) ^# A7 d6 h& y6 _1 \8 |# M* Y Byte_Num 要读出的字节数 S0 L0 s: x# ?9 t; P& z- y */ void FLASH_ReadByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num)5 |8 ]6 p- C1 p- M' c5 N( S9 [9 { { while(Byte_Num--) { *(p++)=*((uint8_t*)addr++);9 k( I4 J; J# h& e4 @/ ?1 Q }, H5 u' ]" z# F/ c3 D+ u5 B+ R7 Z }- G: R* [. }: H8 H 例:2 b. U0 B. ?8 X& \ uint8_t data[101]; FLASH_ReadByte(0x8000001 , data , 101);/*FLASH中的数据被读入数组data中*/ |
![]() |
| 好长啊 |
微信公众号
手机版