本帖最后由 zjh20070904 于 2022-5-3 17:10 编辑
#技术资源#
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;
/*! * *@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个字数据的结果从地址0x08008000开始,写入5000个字数据,最后1个字数据的地址是:0x0800CE1C 过程 | | 第1次赋值往Flash中写入5000个字后,从Flash中读取的数据 | | 第2次赋值往Flash中写入5003个字后,从Flash中读取的数据 | | | |
3.2 写5000/5003个字节数据的结果从地址0x08008000开始,写入5000个字节数据,最后1个数据的地址是:0x08009387 过程 | | 第1次赋值往Flash中写入5000个字节后,从Flash中读取的数据 | | 第1次赋值往Flash中写入5003个字节后,从Flash中读取的数据 | | | |
4 注意点(1)计算擦除page数量时: ①如果字节数不是page的倍数,需要注意多出来的数据会写在下一个page中,因此要多擦除1个page ②数据是字时,计算要擦除的page数量时,需要在字个数乘以4的基础上计算 (2)代码中调用的驱动函数是写word,在写字节数据时,需要注意: ①需要将数据按照小端模式将4个字节数据转化为1个字 ②遇到数据个数不是4的整数时,不要忘记将剩下的数据写入Flash中 (3)代码中等待写Flash状态时用的是死等,撰写不是很严谨,实际应用中可以使用“超时等待退出,并返回错误”
|