1 概述
APM32F103xE的Flash只能按照Halfword形式写入,在驱动库中只有写1个写HalfWord数据、1个写Word数据的函数,在现实应用中,有遇到将大量字节、字数据写入Flash的情况,下面记录了调试代码、现象、注意点。
2 参考代码及工程
#include "main.h"
#if defined (APM32F10X_HD)
#define FLASH_PAGE_SIZE ((uint16_t)0x800)
#else
#define FLASH_PAGE_SIZE ((uint16_t)0x400)
#endif
#define BANK1_WRITE_START_ADDR ((uint32_t)0x08008000)
#define BANK1_WRITE_END_ADDR ((uint32_t)0x0800C000)
enum {FAILED, PASSED};
volatile uint8_t MemoryProgramStatus = PASSED;
/*!
*@brief Main program
*
*@param None
*
*@retval None
*
*/
uint32_t gWordData[5010]={0};
uint8_t gByteData[5010]={0};
void Flash_WriteWord(uint32_t addr_start,uint32_t*p_data,uint32_t data_num)
{
FMC_STATUS_TFLASHStatus = FMC_STATUS_COMPLETE;
uint32_tpage_num=0,i=0,addr_temp=0,addr_end;
page_num= data_num*4/ FLASH_PAGE_SIZE;
if(data_num*4%FLASH_PAGE_SIZE!=0)
{page_num++;}
FMC_Unlock();
FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC | FMC_FLAG_PE |FMC_FLAG_WPE));
for(i =0; i<page_num; i++)
{
FLASHStatus = FMC_ErasePage(addr_start + (FLASH_PAGE_SIZE * i));
while(FLASHStatus!= FMC_STATUS_COMPLETE);
}
addr_temp= addr_start;
for(i=0;i<data_num;i++)
{
FLASHStatus = FMC_ProgramWord(addr_temp, p_data);
addr_temp = addr_temp + 4;
while(FLASHStatus!= FMC_STATUS_COMPLETE);
}
FMC_Lock();
//验证写入的数据是否正确
addr_temp = addr_start;
for(i=0;i<data_num;i++)
{
if((*(__IOuint32_t*) addr_temp) != p_data)
{
break;
}
addr_temp+= 4;
}
}
void Flash_WriteByte(uint32_t addr_start,uint8_t*p_data,uint32_t data_num)
{
FMC_STATUS_TFLASHStatus = FMC_STATUS_COMPLETE;
uint32_tpage_num=0,i=0,addr_temp=0,addr_end;
uint32_tword_data_temp=0,word_num=0,remainder_data_num=0,data_counter=0;
page_num= data_num/FLASH_PAGE_SIZE;
FMC_Unlock();
if(data_num%FLASH_PAGE_SIZE!=0)
{page_num++;}
FMC_ClearStatusFlag((FMC_FLAG_T)(FMC_FLAG_OC| FMC_FLAG_PE | FMC_FLAG_WPE));
for(i =0; i<page_num; i++)
{
FLASHStatus = FMC_ErasePage(addr_start + (FLASH_PAGE_SIZE * i));
while(FLASHStatus!= FMC_STATUS_COMPLETE);
}
addr_temp = addr_start;
word_num= data_num/4;
remainder_data_num=data_num%4;
/*
如果写进入的数据是0x00010203,那在Flash中按字节读取的数据是0x03 0x02 0x01 0x00
如果写进入的数据是0x03020100,那在Flash中按字节读取的数据是0x00 0x01 0x02 0x03
*/
data_counter=0;
for(i=0;i<word_num;i++)
{
word_data_temp = (uint32_t)*(p_data+data_counter);
word_data_temp = word_data_temp |(((uint32_t)*(p_data+data_counter+1))<<8);
word_data_temp = word_data_temp | (((uint32_t)*(p_data+data_counter+2))<<16);
word_data_temp = word_data_temp |(((uint32_t)*(p_data+data_counter+3))<<24);
data_counter=data_counter+4;
FLASHStatus = FMC_ProgramWord(addr_temp, word_data_temp);
addr_temp = addr_temp + 4;
while(FLASHStatus!= FMC_STATUS_COMPLETE);
}
word_data_temp=0x00;
if(remainder_data_num!=0)
{
for(i=0;i<remainder_data_num;i++)
{
word_data_temp= word_data_temp |( ((uint32_t)*(p_data+data_counter+i))<< (i*8));
}
for(;i<4;i++)
{
word_data_temp = word_data_temp | ((0xFF)<<(i*8));
}
FLASHStatus = FMC_ProgramWord(addr_temp, word_data_temp);
addr_temp = addr_temp + 4;
while(FLASHStatus!= FMC_STATUS_COMPLETE);
}
FMC_Lock();
//验证写入的数据是否正确
addr_temp = addr_start;
for(i=0;i<data_num;i++)
{
if((*(__IOuint8_t*) addr_temp) != p_data)
{
break;
}
addr_temp++;
}
}
int main(void)
{
uint32_ti=0;
for(i=0;i<5000;i++)
{
gWordData=i;
gByteData=(uint8_t)i;
}
//Flash_WriteWord(BANK1_WRITE_START_ADDR,gWordData,5000);
Flash_WriteByte(BANK1_WRITE_START_ADDR,gByteData,5000);
for(i=0;i<5003;i++)
{
gWordData=i*2;
gByteData=(uint8_t)i*2;
}
//Flash_WriteWord(BANK1_WRITE_START_ADDR,gWordData,5003);
Flash_WriteByte(BANK1_WRITE_START_ADDR,gByteData,5003);
while(1);
}
3 现象
3.1 写5000/5003个字数据的结果
从地址0×08008000开始,写入5000个字数据,最后1个字数据的地址是:0×0800CE1C
3.2 写5000/5003个字节数据的结果
4 注意点
(1)计算擦除page数量时:
①如果字节数不是page的倍数,需要注意多出来的数据会写在下一个page中,因此要多擦除1个page
②数据是字时,计算要擦除的page数量时,需要在字个数乘以4的基础上计算
(2)代码中调用的驱动函数是写word,在写字节数据时,需要注意:
①需要将数据按照小端模式将4个字节数据转化为1个字
②遇到数据个数不是4的整数时,不要忘记将剩下的数据写入Flash中
(3)代码中等待写Flash状态时用的是死等,撰写不是很严谨,实际应用中可以使用“超时等待退出,并返回错误”