打印
[APM32F1]

Flash——如何将大量字节、字数据写入Flash中

[复制链接]
772|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
flash, AG, ui, PA, fm
本帖最后由 zjh20070904 于 2022-5-3 17:10 编辑

#技术资源#
1 概述
APM32F103xEFlash只能按照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个字数据的结果
从地址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状态时用的是死等,撰写不是很严谨,实际应用中可以使用“超时等待退出,并返回错误”





使用特权

评论回复
沙发
麻花油条| | 2022-5-5 11:45 | 只看该作者
非常棒,收藏

使用特权

评论回复
板凳
JimN| | 2022-5-6 15:51 | 只看该作者
刚好有客户用到,推荐给他们

使用特权

评论回复
地板
suncat0504| | 2022-5-7 14:43 | 只看该作者
挺好的,非常有帮助。可以使用flash作为eeprom来使用

使用特权

评论回复
5
zjh20070904|  楼主 | 2022-6-13 19:27 | 只看该作者
suncat0504 发表于 2022-5-7 14:43
挺好的,非常有帮助。可以使用flash作为eeprom来使用

嗯,配合读取的动作,功能上可以模拟一个简易的EEPROM,电气特性上模拟太复杂了,还需要很多代码。

使用特权

评论回复
6
zjh20070904|  楼主 | 2022-6-13 19:29 | 只看该作者
JimN 发表于 2022-5-6 15:51
刚好有客户用到,推荐给他们

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:极海半导体
简介:珠海极海半导体有限公司是一家致力于开发工业级/车规级微控制器、模拟与混合信号IC及系统级芯片的集成电路设计型企业。极海团队拥有20年集成电路设计经验和嵌入式系统开发能力,可为客户提供核心可靠的芯片产品及方案,实现准确感应、安全传输和实时控制,助力客户在智慧家居、高端消费电子、工业控制、汽车电子、智慧能源以及通信设施等领域的拓展创新。

29

主题

68

帖子

0

粉丝