Flash的操作:
stm32大容量的flash不仅用来存储程序代码,还可用来存储一些数据和系统用户的参数。程序的代码一般保存在从flash开始区域,剩下的区域空间大小可以用来存储用户数据(大小取决于Flash的大小和代码占用空间的大小)。如果存储的数据很少可以用最后一页用于专门的存贮用户数据,这样可以防止和程序代码空间冲突。
1、STM32的Flash有读写次数和寿命的限制,所以不要放在循环中反复执行读写操作。
2、FLASH的读写均需要时间,设置等待周期是为了确保正确的读写。因为cpu的速度远远大于FLASH的操作速度。用库函数FLASH_SetLatency(FLASH_Latency_2)来设置。
3、开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的
用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
4、打开内部振荡器RCC_HSICmd(ENABLE);
5、STM32对Flash的操作必须遵循一定的步骤,必须先擦除再写入,擦除必须以PAGE(页)位单位,写(编程)必须以Word(两字节)为单位。
6、关于读保护和写保护:
配置了读保护之后,Flash中的代码和数据无法通过JTAG和RAM中的程序读出,起到了加密的作用。写保护是以页(或多页)为单位的,配置之后无法被擦除或修改,加强了代码的可靠性。
程序是从0x0800f800开始写入2个半字的数据,然后在MAIN函数中用串口返回:
void
{u16
u16
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
FLASH_ErasePage(0x0800f800);
for(cnt=0;cnt<</span>2;cnt++)
FLASH_ProgramHalfWord((0x0800f800
FLASH_Lock();
}
MAIN函数关于Flash操作的代码:
send_byte(i);//串口返回0x0800f802地址处的数据
因为之前想写一个字节老是出错,所以翻翻手册,果然看到不能写1个字节数据。而且还发现,flash写地址为奇数时也会出错。所以这份代码里面
写flash的地址只能是偶数。浏览过程中还发现,手册里面说写flash和擦除flash的时候会影响cpu的运行速度,没仔细看(真心不想看)。
1.
2.
3.
4
9.
10.
11.
12.
13.//
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.}
24.//
33.int
34.
35.
36.
37.uint16_t
38.uint16_t
39.
40.
41.
42.
43.secpos=iAddress
44.secoff=iAddress
45.secremain=FLASH_PAGE_SIZE-secoff;
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.}
90.
99.int
100.
101.
102.
103.
104.
105.
106.}
110.-------------------DataFlash.h----------------------------------
111.
112.#ifndef
113.#define
114.
115.
116.#include
117.#include
#if
123.
124.
125.#else
126.
127.#endif
132.int
133.int
134.
135.
136.#endif
///
实践过的代码:
void SetSysClockFromHSI(void) //设置高速内部时钟
{
// SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
// RCC system reset(for debug purpose) */
RCC_DeInit();
// Enable HSI */
RCC_HSICmd(ENABLE);//打开内部振荡器RCC_HSICmd(ENABLE);
// Enable Prefetch Buffer */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//开启FLASH预读缓冲功能,加速FLASH的读取
// 0 wait state from 0 to 24 MHz
// 1 wait state from 24 to 48 MHz
// 2 wait states above.
// Flash wait state */
if(RCC_PLLMul_Config <= RCC_PLLMul_6)// <=24 MHz
//#define FLASH_Latency_0
FLASH_SetLatency(FLASH_Latency_0);//设置代码延时值
else if(RCC_PLLMul_Config <= RCC_PLLMul_12)// <=48 MHz
//#define FLASH_Latency_1
FLASH_SetLatency(FLASH_Latency_1);
else
//#define FLASH_Latency_2
FLASH_SetLatency(FLASH_Latency_2);
//HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
// PCLK1 = HCLK */
RCC_PCLK1Config(RCC_HCLK_Div1);
// PLLCLK = 4MHz * RCC_PLLMul_Config */
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_Config);
//Enable PLL */
RCC_PLLCmd(ENABLE);
// Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
//Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// Wait till PLL is used as system clock source */
/
while(RCC_GetSYSCLKSource() != 0x08){}
}
/
u8 FLASH_WriteNByte(u32 addr, s16 *dat_buf, u8 no)
{
//Unlock the Flash Program Erase controller */
FLASH_Unlock(); // FLASH解锁
if(FLASH_GetFlagStatus(FLASH_FLAG_BSY) == SET) return FALSE; // 以确认没有其他正在进行的编程操作,则返回错误退出
// Clear All pending flags */
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清标志位
while(FLASH_GetFlagStatus(FLASH_FLAG_BSY) == SET);
FLASHStatus = FLASH_ErasePage(addr);
while(no && (FLASHStatus == FLASH_COMPLETE))
{
FLASHStatus = FLASH_ProgramHalfWord(addr, *dat_buf); // 以16bit宽度写入,内部包含设置FLASH_CR寄存器的PG位为1的步骤
addr += 2; //flash写地址为奇数时也会出错
dat_buf++;
no--;
while(FLASH_GetFlagStatus(FLASH_FLAG_BSY) == SET); // 等待写入结束
}
FLASH_Lock(); // FLASH上锁
while(FLASH_GetFlagStatus(FLASH_FLAG_BSY) == SET);
if(no == 0) return TRUE;
else return FALSE;
}
/
void FLASH_ReadNByte(u32 addr, s16 *dat_buf, u8 no)
{
u8 HalfWordN = 0;
while(no)
{
dat_buf[HalfWordN] = *(vs16*)(addr + HalfWordN * 2);//偏移量 FLASH为偶数地址
HalfWordN++;
no--;
}
}