stm32的学习—FLASH的操作和使用
2013-12-26 22:32阅读:
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 flash_write()
{u16 cnt = 0;
u16
data[2]={0x1234,0x5678};
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 +cnt*2),data[cnt]);
FLASH_Lock();
}
MAIN函数关于Flash操作的代码:
uint8_t i;
FLASH_SetLatency(FLASH_Latency_2);
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
flash_write();
i = *( uint32_t
*)(0x0800f802);//读取改地址的数据,赋值i
send_byte(i);//串口返回0x0800f802地址处的数据
因为之前想写一个字节老是出错,所以翻翻手册,果然看到不能写1个字节数据。而且还发现,flash写地址为奇数时也会出错。所以这份代码里面
写flash的地址只能是偶数。浏览过程中还发现,手册里面说写flash和擦除flash的时候会影响cpu的运行速度,没仔细看(真心不想看)。
1.
-DataFlash.c----------------------------------
2.
3. #include
'DataFlash.h'
4
uint16_t
Flash_Write_Without_check(uint32_t iAddress,
uint8_t *buf, uint16_t iNumByteToWrite)
{
9.
uint16_t i;
10.
volatile
FLASH_Status FLASHStatus =
FLASH_COMPLETE;
11. i =
0;
12.
13.//
FLASH_UnlockBank1();
14.
while((i <
iNumByteToWrite) && (FLASHStatus
== FLASH_COMPLETE))
15. {
16.
FLASHStatus = FLASH_ProgramHalfWord(iAddress,
*(uint16_t*)buf);
17.
i = i+2;
18.
iAddress = iAddress + 2;
19.
buf = buf + 2;
20. }
21.
22.
return
iNumByteToWrite;
23.}
24.//
33.int
Flash_Write(uint32_t iAddress, uint8_t
*buf, uint32_t iNbrToWrite) {
34.
/
35.
uint32_t secpos;
36.
uint32_t iNumByteToWrite =
iNbrToWrite;
37.uint16_t secoff;
38.uint16_t secremain;
39. uint16_t i =
0;
40.
uint8_t tmp[FLASH_PAGE_SIZE];
41.
42.
FLASH_UnlockBank1();
43.secpos=iAddress &
(~(FLASH_PAGE_SIZE -1 ))
;//扇区地址
44.secoff=iAddress &
(FLASH_PAGE_SIZE -1);
//在扇区内的偏移
45.secremain=FLASH_PAGE_SIZE-secoff;
//扇区剩余空间大小
46.
volatile
FLASH_Status FLASHStatus =
FLASH_COMPLETE;
47.
48.
if(iNumByteToWrite<=secremain)
secremain =
iNumByteToWrite;//不大于4096个字节
49.
50.
while(
1 ) {
51.
Flash_Read(secpos, tmp, FLASH_PAGE_SIZE);
//读出整个扇区
52.
for(i=0;i//校验数据
53.
if(tmp[secoff+i]!=0XFF)break;
//需要擦除
54. }
55.
if(i//需要擦除
56.
FLASHStatus =
FLASH_ErasePage(secpos);
//擦除这个扇区
57.
if(FLASHStatus !=
FLASH_COMPLETE)
58.
return -1;
59.
for(i=0;i//复制
60.
tmp[i+secoff]=buf[i];
61.
}
62.
Flash_Write_Without_check(secpos ,tmp
,FLASH_PAGE_SIZE);//写入整个扇区
63.
}
else {
64.
Flash_Write_Without_check(iAddress,buf,secremain);//写已经擦除了的,直接写入扇区剩余区间.
65.
}
66.
67.
if(iNumByteToWrite==secremain)
//写入结束了
68.
break;
69.
else {
70.
secpos += FLASH_PAGE_SIZE;
71.
secoff =
0;//偏移位置为0
72.
buf += secremain;
//指针偏移
73.
iAddress +=
secremain;//写地址偏移
74.
iNumByteToWrite -= secremain;
//字节数递减
75.
if(iNumByteToWrite>FLASH_PAGE_SIZE)
secremain=FLASH_PAGE_SIZE;//下一个扇区还是写不完
76.
else
secremain = iNumByteToWrite;
//下一个扇区可以写完了
77.
}
78.
79.
}
80.
81.
FLASH_LockBank1();
82.
return
iNbrToWrite;
83.}
90.
99.int
Flash_Read(uint32_t iAddress, uint8_t
*buf, int32_t iNbrToRead) {
100.
int
i = 0;
101.
while(i
< iNbrToRead ) {
102.
*(buf +
i) = *(__IO uint8_t*)
iAddress++;
103.
i++;
104.
}
105.
return
i;
106.}
110.-------------------DataFlash.h----------------------------------
111.
112.#ifndef
__DATAFLASH_H__
113.#define
__DATAFLASH_H__
114.
115.
116.#include 'stm32f10x.h'
117.#include 'stm32f10x_flash.h'
#if defined (STM32F10X_HD) ||
defined (STM32F10X_HD_VL) || defined
(STM32F10X_CL) || defined
(STM32F10X_XL)
123. #define
FLASH_PAGE_SIZE
((uint16_t)0x800)
124.
125.#else
126. #define
FLASH_PAGE_SIZE
((uint16_t)0x400)
127.#endif
132.int
Flash_Read(uint32_t iAddress, uint8_t
*buf, int32_t iNbrToRead) ;
133.int
Flash_Write(uint32_t iAddress, uint8_t
*buf, uint32_t iNbrToWrite);
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
((uint32_t)0x00000000) //< FLASH Zero Latency cycle
*/
FLASH_SetLatency(FLASH_Latency_0);//设置代码延时值
else if(RCC_PLLMul_Config <= RCC_PLLMul_12)// <=48
MHz
//#define FLASH_Latency_1
((uint32_t)0x00000001) //< FLASH One Latency cycle
*/
FLASH_SetLatency(FLASH_Latency_1);
else
//#define FLASH_Latency_2
((uint32_t)0x00000002) //< FLASH Two Latency
cycles */ FLASH两个延迟周期
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(FLASH_GetFlagStatus(FLASH_FLAG_BSY) ==
SET);
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--;
}
}
|字号
订阅