STM32F103制作FlashDriver的实现过程

发布时间:2024-04-16  

前言

在汽车行业控制器软件刷新流程中,一般会将Flash驱动单独进行刷写,目的是防止程序中一直存在Flash驱动的话,可能会造成对APP软件的异常操作,导致应用程序无法执行。


本文介绍STM32F103使用KEIL生成指定FlashDriver地址的hex文件,然后使用HexView命令行提取FlashDriver及Remapping flash地址到ram地址



本文参考github,SummerFalls大神的UDS_S32K144_FlashDriver


芯片内存定义

STM32F103RCT6,flash大小256k,一个扇区2k,SRAM:48KB;


实现过程

FlashDriver生成

段定义

由于我无法直接在Keil中导出指定ram地址的hex文件,所以采用先定义指定flash地址的flash驱动,后面通过hexview实现地址重映射


keil中的内存区域定义通过分散加载文件(.sct格式)实现,如下所示


; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************


LR_IROM1 0x08000000 0x00020000  {    ; load region size_region


 

  ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$$Sections)

   .ANY (+RO)

   .ANY (+XO)

  }

  



  RW_IRAM1 0x20000800 0x0000C000  {  ; RW data

   .ANY (+RW +ZI)

  }

}

LR_IROM2 0x08020000 0x00020000  {

 RW_IROM_flashdrvoffset 0x08020000 0x00000008{; load address = execution address

    *(.NVM_Driver_Section_offset)    

  

  }

 RW_IROM_flashdrv 0x08020008 0x000007F8{; load address = execution address

    *(.NVM_Driver_Section)    

  }

  }

此处设置了两个段,NVM_Driver_Section_offset用来设置函数偏移地址,NVM_Driver_Section用来设置函数地址


增加段的宏定义


#define NVM_DRIVER_SECTION __attribute__((section (".NVM_Driver_Section")))

#define NVM_DRIVER_SECTION_OFFSET __attribute__((section (".NVM_Driver_Section_offset")))

函数地址偏移量定义


__attribute__((used)) NVM_DRIVER_SECTION_OFFSET static const tFlashDriverAPIInfo gs_FlashDriverAPI  = {

    (tpfFLASH_DRV_EraseSector)      CAL_OFFSET(FLASH_ErasePage),

    (tpfFLASH_DRV_Program)          CAL_OFFSET(FLASH_ProgramWord),

};

分两个段,保证地址偏移量在生成的hex文件的前面


此处使用库函数中的FLASH_ErasePage和FLASH_ProgramWord函数。由于提取的函数最终是以数组的形式存在,以函数指针的方式进行调用,所以函数中不能存在全局变量或调用其他的函数。


需要将原库函数中的函数的调用函数使用宏定义的方式进行定义,使用do while语法实现。


擦除函数

__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ErasePage(uint32_t Page_Address)

{

  FLASH_Status status = FLASH_COMPLETE;


    FLASH_WaitForLastOperation(EraseTimeout,&status);

    if(status == FLASH_COMPLETE)

    { 

      /* if the previous operation is completed, proceed to erase the page */

      FLASH- >CR|= CR_PER_Set;

      FLASH- >AR = Page_Address; 

      FLASH- >CR|= CR_STRT_Set;

      /* Wait for last operation to be completed */

      FLASH_WaitForLastOperation(EraseTimeout,&status);

    /* Disable the PER Bit */

      FLASH- >CR &= CR_PER_Reset;

    }


  /* Return the Erase Status */

  return status;

}

上面的FLASH_WaitForLastOperation函数使用宏定义进行展开


#define FLASH_WaitForLastOperation(Timeout,pstatus)

do{

    uint32_t TimeoutCnt =  Timeout;

    *pstatus = FLASH_COMPLETE;

     FLASH_GetBank1Status(pstatus);

     while((*pstatus == FLASH_BUSY) && (TimeoutCnt != 0x00))

      {

        FLASH_GetBank1Status(pstatus);

        TimeoutCnt--;

      }

      if(TimeoutCnt == 0x00 )

      {

        *pstatus = FLASH_TIMEOUT;

      }

}while(0)

里面又用到一个FLASH_GetBank1Status函数


#define FLASH_GetBank1Status(pFLASH_Status)

do{

      *pFLASH_Status = FLASH_COMPLETE;

      if((FLASH- >SR & FLASH_FLAG_BANK1_BSY) == FLASH_FLAG_BSY)

      {

         *pFLASH_Status = FLASH_BUSY;

      }

      else

      {

         if((FLASH- >SR & FLASH_FLAG_BANK1_PGERR) != 0)

        {

          *pFLASH_Status = FLASH_ERROR_PG;

        }

        else

        {

          if((FLASH- >SR & FLASH_FLAG_BANK1_WRPRTERR) != 0 )

          {

            *pFLASH_Status = FLASH_ERROR_WRP;

          }

          else

          {

            *pFLASH_Status = FLASH_COMPLETE;

          }

        }

      }

}while(0)

写入函数

__attribute__((used)) NVM_DRIVER_SECTION FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)

{

  FLASH_Status status = FLASH_COMPLETE;

  __IO uint32_t tmp = 0;


  FLASH_WaitForLastOperation(ProgramTimeout,&status);

  if(status == FLASH_COMPLETE)

  {

    /* if the previous operation is completed, proceed to program the new first 

    half word */

    FLASH- >CR |= CR_PG_Set;

  

    *(__IO uint16_t*)Address = (uint16_t)Data;

    /* Wait for last operation to be completed */

      

      FLASH_WaitForLastOperation(ProgramTimeout,&status);

 

    if(status == FLASH_COMPLETE)

    {

      /* if the previous operation is completed, proceed to program the new second 

      half word */

      tmp = Address + 2;


      *(__IO uint16_t*) tmp = Data > > 16;

    

      /* Wait for last operation to be completed */

      

      FLASH_WaitForLastOperation(ProgramTimeout,&status);

        

      /* Disable the PG Bit */

      FLASH- >CR &= CR_PG_Reset;

    }

    else

    {

      /* Disable the PG Bit */

      FLASH- >CR &= CR_PG_Reset;

    }

  }         

   

  /* Return the Program Status */

  return status;

}

其中用到的函数也已经改为宏定义


编译后的map

gs_FlashDriverAPI                        0x08020000   Data           8  main.o(.NVM_Driver_Section_offset)

    FLASH_ErasePage                          0x08020009   Thumb Code   186  stm32f10x_flash.o(.NVM_Driver_Section)

    FLASH_ProgramWord                        0x080200c3   Thumb Code   250  stm32f10x_flash.o(.NVM_Driver_Section)

函数需要偶数地址对齐


hexview中显示:

b4fb74aa38d5fa138a88000215209b09_wKgaomSGy56AV_C0AADPpNk3RoM307.jpg

手动测试

__align(4) uint8_t flash_erase_buf[]={

  0x30,0xB5, 0x6C, 0x49, 0x04, 0x46, 0x4F, 0xF4,

 0x30, 0x22, 0xCD, 0x68, 0x04, 0x20, 0x13, 0x46, 0xED, 0x07, 0x09, 0xD1, 0xCB, 0x68, 0x5B, 0x07,

 0x01, 0xD5, 0x02, 0x20, 0x30, 0xBD, 0xCB, 0x68, 0xDB, 0x06, 0x18, 0xD5, 0x03, 0x20, 0x30, 0xBD,

 0xCD, 0x68, 0x04, 0x20, 0xED, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x1C, 0xE0, 0xCD, 0x68,

 0x6D, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x06, 0xE0, 0xCD, 0x68, 0xED, 0x06, 0x03, 0xD5, 0x03, 0x20,

 0x01, 0x2B, 0x11, 0xD0, 0x30, 0xBD, 0x01, 0x2B, 0x0E, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x0B, 0x69,

 0x43, 0xF0, 0x02, 0x03, 0x0B, 0x61, 0x4C, 0x61, 0x0B, 0x69, 0x43, 0xF0, 0x40, 0x03, 0x0B, 0x61,

 0xCB, 0x68, 0xDB, 0x07, 0x0C, 0xD1, 0x01, 0xE0, 0x05, 0x20, 0x30, 0xBD, 0xCA, 0x68, 0x52, 0x07,

 0x01, 0xD5, 0x02, 0x20, 0x17, 0xE0, 0xCA, 0x68, 0xD2, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0,

 0xCB, 0x68, 0x04, 0x20, 0xDB, 0x07, 0x02, 0xD0, 0x52, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xCB, 0x68,

 0x5B, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xCB, 0x68, 0xDB, 0x06, 0x00, 0xD5, 0x03, 0x20,

 0x01, 0x2A, 0x00, 0xD1, 0x05, 0x20, 0x0A, 0x69, 0x41, 0xF6, 0xFD, 0x73, 0x1A, 0x40, 0x0A, 0x61,

 0x30, 0xBD

};

 

__align(4) uint8_t flash_write_buf[]={

  0xF8, 0xB5, 0x00, 0x92, 0x3C, 0x4A, 0x06, 0x46, 0x04, 0x20, 0xC3, 0x02,

 0xD4, 0x68, 0x1D, 0x46, 0xE4, 0x07, 0x09, 0xD1, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5, 0x02, 0x20,

 0xF8, 0xBD, 0xD4, 0x68, 0xE4, 0x06, 0x18, 0xD5, 0x03, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x04, 0x20,

 0xE4, 0x07, 0x02, 0xD0, 0x6D, 0x1E, 0xF9, 0xD1, 0x1B, 0xE0, 0xD4, 0x68, 0x64, 0x07, 0x01, 0xD5,

 0x02, 0x20, 0x06, 0xE0, 0xD4, 0x68, 0xE4, 0x06, 0x03, 0xD5, 0x03, 0x20, 0x01, 0x2D, 0x10, 0xD0,

 0xF8, 0xBD, 0x01, 0x2D, 0x0D, 0xD0, 0x04, 0x28, 0xFA, 0xD1, 0x14, 0x69, 0x44, 0xF0, 0x01, 0x04,

 0x14, 0x61, 0x31, 0x80, 0xD5, 0x68, 0x1C, 0x46, 0xEF, 0x07, 0x41, 0xF6, 0xFE, 0x75, 0x09, 0xD1,

 0x01, 0xE0, 0x05, 0x20, 0xF8, 0xBD, 0xD4, 0x68, 0x64, 0x07, 0x21, 0xD4, 0xD4, 0x68, 0xE4, 0x06,

 0x23, 0xD4, 0x13, 0xE0, 0xD7, 0x68, 0x04, 0x20, 0xFF, 0x07, 0x02, 0xD0, 0x64, 0x1E, 0xF9, 0xD1,

 0x2F, 0xE0, 0xD7, 0x68, 0x7F, 0x07, 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD7, 0x68, 0xFF, 0x06,

 0x00, 0xD5, 0x03, 0x20, 0x01, 0x2C, 0x24, 0xD0, 0x04, 0x28, 0x23, 0xD1, 0xB6, 0x1C, 0x09, 0x0C,

 0x00, 0x96, 0x31, 0x80, 0xD1, 0x68, 0xC9, 0x07, 0x09, 0xD1, 0xD1, 0x68, 0x49, 0x07, 0x01, 0xD5,

 0x02, 0x20, 0x17, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x14, 0xD5, 0x03, 0x20, 0x12, 0xE0, 0xD1, 0x68,

 0x04, 0x20, 0xC9, 0x07, 0x02, 0xD0, 0x5B, 0x1E, 0xF9, 0xD1, 0x0A, 0xE0, 0xD1, 0x68, 0x49, 0x07,

 0x01, 0xD5, 0x02, 0x20, 0x03, 0xE0, 0xD1, 0x68, 0xC9, 0x06, 0x00, 0xD5, 0x03, 0x20, 0x01, 0x2B,

 0x00, 0xD1, 0x05, 0x20, 0x11, 0x69, 0x29, 0x40, 0x11, 0x61, 0xF8, 0xBD, 0x00, 0x20, 0x02, 0x40,

 

};

 

typedef void (*flash_erase_handler)(uint32_t u32addr);

typedef void (*flash_write_handler)(uint32_t u32addr, uint32_t u32data);


flash_erase_handler flash_erase = (flash_erase_handler)(flash_erase_buf + 1); 

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>