新浪博客

stm32的学习—FLASH的操作和使用

2013-12-26 22:32阅读:


Flash的操作:
stm32大容量的flash不仅用来存储程序代码,还可用来存储一些数据和系统用户的参数。程序的代码一般保存在从flash开始区域,剩下的区域空间大小可以用来存储用户数据(大小取决于Flash的大小和代码占用空间的大小)。如果存储的数据很少可以用最后一页用于专门的存贮用户数据,这样可以防止和程序代码空间冲突。

1STM32Flash有读写次数和寿命的限制,所以不要放在循环中反复执行读写操作
2FLASH的读写均需要时间,设置等待周期是为了确保正确的读写。因为cpu的速度远远大于FLASH的操作速度。用库函数FLASH_SetLatency(FLASH_Latency_2)来设
置。
3开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的
用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
4、打开内部振荡器RCC_HSICmd(ENABLE);
5STM32Flash的操作必须遵循一定的步骤,必须先擦除再写入,擦除必须以PAGE(页)位单位,写(编程)必须以Word(两字节)为单位。
6、关于读保护和写保护
配置了读保护之后,Flash中的代码和数据无法通过JTAGRAM中的程序读出,起到了加密的作用。写保护是以页(或多页)为单位的,配置之后无法被擦除或修改,加强了代码的可靠性。 读保护和写保护都是在自己的程序中配置的。你可以在第一次运行程序是配置相关选择字。

程序是从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--;
}

}

|
字号
订阅

我的更多文章

下载客户端阅读体验更佳

APP专享