历史上的今天

今天是:2024年11月19日(星期二)

2019年11月19日 | STM8做IAP(Bootloader)时在RAM中执行Flash块擦写函数问题

发布者:eaff86 来源: eefocus关键字:STM8  IAP  Bootloader  RAM  Flash块擦写函数 手机看文章 扫描二维码
随时随地手机看文章

1、STM8的外设库驱动提供了很多代码,要求不高的话直接用库驱动即可


2、Flash块擦写速度快,但是必须要把函数放到RAM中执行(因为MCU的是NorFlash,普通的函数都是直接在Flash上执行的)


官方库如下


/**

  * @brief  Erases a block in the program or data memory.

  * @note   This function should be executed from RAM.

  * @param  FLASH_MemType :  The type of memory to erase

  * @param  BlockNum : Indicates the block number to erase

  * @retval None.

  */

IN_RAM(void FLASH_EraseBlock(uint16_t BlockNum, FLASH_MemType_TypeDef FLASH_MemType))

{

  uint32_t startaddress = 0;

  

#if defined(STM8S105) || defined(STM8S005) || defined(STM8S103) || defined(STM8S003) ||

    defined(STM8S001) || defined(STM8S903) || defined (STM8AF626x) || defined (STM8AF622x)

    uint32_t PointerAttr  *pwFlash;

#elif defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined (STM8AF62Ax) || defined (STM8AF52Ax) 

  uint8_t PointerAttr  *pwFlash;

#endif

  

  /* Check parameters */

  assert_param(IS_MEMORY_TYPE_OK(FLASH_MemType));

  if(FLASH_MemType == FLASH_MEMTYPE_PROG)

  {

    assert_param(IS_FLASH_PROG_BLOCK_NUMBER_OK(BlockNum));

    startaddress = FLASH_PROG_START_PHYSICAL_ADDRESS;

  }

  else

  {

    assert_param(IS_FLASH_DATA_BLOCK_NUMBER_OK(BlockNum));

    startaddress = FLASH_DATA_START_PHYSICAL_ADDRESS;

  }

  

  /* Point to the first block address */

#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined (STM8AF62Ax) || defined (STM8AF52Ax)

  pwFlash = (PointerAttr uint8_t *)(MemoryAddressCast)(startaddress + ((uint32_t)BlockNum * FLASH_BLOCK_SIZE));

#elif defined(STM8S105) || defined(STM8S005) || defined(STM8S103) || defined(STM8S003) ||

      defined(STM8S001) || defined (STM8S903) || defined (STM8AF626x) || defined (STM8AF622x)

    pwFlash = (PointerAttr uint32_t *)(MemoryAddressCast)(startaddress + ((uint32_t)BlockNum * FLASH_BLOCK_SIZE));

#endif /* STM8S208, STM8S207 */

  

  /* Enable erase block mode */

  FLASH->CR2 |= FLASH_CR2_ERASE;

  FLASH->NCR2 &= (uint8_t)(~FLASH_NCR2_NERASE);

  

#if defined(STM8S105) || defined(STM8S005) || defined(STM8S103) || defined(STM8S003) ||  

    defined(STM8S001) || defined(STM8S903) || defined (STM8AF626x) || defined (STM8AF622x)

    *pwFlash = (uint32_t)0;

#elif defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined (STM8AF62Ax) ||

  defined (STM8AF52Ax)

    *pwFlash = (uint8_t)0;

  *(pwFlash + 1) = (uint8_t)0;

  *(pwFlash + 2) = (uint8_t)0;

  *(pwFlash + 3) = (uint8_t)0;    

#endif

}

 

/**

  * @brief  Programs a memory block

  * @note   This function should be executed from RAM.

  * @param  FLASH_MemType : The type of memory to program

  * @param  BlockNum : The block number

  * @param  FLASH_ProgMode : The programming mode.

  * @param  Buffer : Pointer to buffer containing source data.

  * @retval None.

  */

IN_RAM(void FLASH_ProgramBlock(uint16_t BlockNum, FLASH_MemType_TypeDef FLASH_MemType, 

                        FLASH_ProgramMode_TypeDef FLASH_ProgMode, uint8_t *Buffer))

{

  uint16_t Count = 0;

  uint32_t startaddress = 0;

  

  /* Check parameters */

  assert_param(IS_MEMORY_TYPE_OK(FLASH_MemType));

  assert_param(IS_FLASH_PROGRAM_MODE_OK(FLASH_ProgMode));

  if(FLASH_MemType == FLASH_MEMTYPE_PROG)

  {

    assert_param(IS_FLASH_PROG_BLOCK_NUMBER_OK(BlockNum));

    startaddress = FLASH_PROG_START_PHYSICAL_ADDRESS;

  }

  else

  {

    assert_param(IS_FLASH_DATA_BLOCK_NUMBER_OK(BlockNum));

    startaddress = FLASH_DATA_START_PHYSICAL_ADDRESS;

  }

  

  /* Point to the first block address */

  startaddress = startaddress + ((uint32_t)BlockNum * FLASH_BLOCK_SIZE);

  

  /* Selection of Standard or Fast programming mode */

  if(FLASH_ProgMode == FLASH_PROGRAMMODE_STANDARD)

  {

    /* Standard programming mode */ /*No need in standard mode */

    FLASH->CR2 |= FLASH_CR2_PRG;

    FLASH->NCR2 &= (uint8_t)(~FLASH_NCR2_NPRG);

  }

  else

  {

    /* Fast programming mode */

    FLASH->CR2 |= FLASH_CR2_FPRG;

    FLASH->NCR2 &= (uint8_t)(~FLASH_NCR2_NFPRG);

  }

  

  /* Copy data bytes from RAM to FLASH memory */

  for(Count = 0; Count < FLASH_BLOCK_SIZE; Count++)

  {

    *((PointerAttr uint8_t*) (MemoryAddressCast)startaddress + Count) = ((uint8_t)(Buffer[Count]));

  }

}

默认IN_RAM是不打开,需要#define RAM_EXECUTION  (1)


这样就可以用库里的块擦写函数了


3、分析一下库的代码,发现


擦除和写入命令差不多:首先操作FLASH->CR2和FLASH->NCR2,然后在相应的Flash上写数据,擦除写4个0即可


于是自己重写一下驱动


typedef byte (* flashProgramCodeInRamFun)(byte cr2, byte ncr2, word BlockNum, byte length, byte *Buffer);

 

__ramfunc byte LaunchFlashCommand(byte cr2, byte ncr2, word BlockNum, byte length, byte *Buffer)

{

    uint16_t Count = 0;

    uint32_t addr;

    

    addr = BlockNum;

    addr *= FLASH_BLOCK_SIZE;

    addr += FLASH_PROG_START_PHYSICAL_ADDRESS;

 

    /* Unlock program memory */

    FLASH->PUKR = FLASH_RASS_KEY1;

    FLASH->PUKR = FLASH_RASS_KEY2;

        

    FLASH->CR2 |= cr2;

    FLASH->NCR2 &= (uint8_t)(~ncr2);

    

    for (Count = 0; Count < length; Count++)

    {

        *((PointerAttr uint8_t*) (uint32_t)addr + Count) = ((uint8_t)(Buffer[Count]));

    }

    

    while( (FLASH->IAPSR & (FLASH_IAPSR_EOP | FLASH_IAPSR_WR_PG_DIS)) == 0);

    

    /* Lock memory */

    FLASH->IAPSR &= (uint8_t)FLASH_MEMTYPE_PROG;

    

    return FLASH_NO_ERROR;  

}

 

byte PFlashEraseBlock(dword gAddr)

{

  static byte data[]={0,0,0,0};

  byte ret = 0;

  dword blockNum = (gAddr - FLASH_PROG_START_PHYSICAL_ADDRESS) / FLASH_SECTOR_SIZE;

  ret = ((flashProgramCodeInRamFun)DRIVER_ADDR)(FLASH_CR2_ERASE, FLASH_NCR2_NERASE, blockNum, 4, data);

 

  return ret;

 

byte PFlashProg(dword gAddr, byte len, byte *pDat)

{

  byte ret = 0;

  dword blockNum = (gAddr - FLASH_PROG_START_PHYSICAL_ADDRESS) / FLASH_SECTOR_SIZE;

  ret = ((flashProgramCodeInRamFun)DRIVER_ADDR)(FLASH_CR2_PRG, FLASH_NCR2_NPRG, blockNum, FLASH_SECTOR_SIZE, pDat);

 

  return ret;

}

(1)那么我想把地址直接传到LaunchFlashCommand中不用BlockNum行不行呢?


答案是分情况:如果参数是u16则完全没问题,适合32K以内的小容量MCU,如果是u32的参数则会出问题,程序跑飞


因此地址空间只有8000~FFFF=32K


(2)我想把函数放到固定地址上,参数是u16的BlockNum,不用__ramfunc 行不行?


答案也是分情况:如果在LaunchFlashCommand不用u32就可以,因此地址空间仍是32K


方法如下:


在icf中设置place at address mem: 0x0000CE00 { readonly section .funflash };


然后函数定义时:byte LaunchFlashCommand(byte cr2, byte ncr2, word BlockNum, byte length, byte *Buffer) @ ".funflash"


使用时手动将数据copy到ram中,长度在hex文件中查看


(3)为什么不能直接传u32的地址?为什么不用__ramfunc自己直接copy机器码,函数中使用u32就不行?


这问题我回答不上来,使用飞思卡尔的16位MCU也有类似的现象,自己指定函数地址,copy到ram,函数里如果使用u32则会出错。比较一下生成的hex文件,两种方式生成的机器码也不一样。


4、如何提取Flash驱动呢?


在汽车ECU上,OEM处于于安全考虑要求Flash的擦写函数不能保存在Flash中;执行Bootloader之前首先将Flash擦写函数(称之为驱动)发给MCU,MCU放到RAM里执行,用毕清空。


因此如何提取呢?


(1)查找map文件,找到LaunchFlashCommand的地址和长度

(2)仿真时,查看RAM窗口,找到LaunchFlashCommand部分的数据,选中复制

(3)将复制的数据做成s19或者hex文件


关键字:STM8  IAP  Bootloader  RAM  Flash块擦写函数 引用地址:STM8做IAP(Bootloader)时在RAM中执行Flash块擦写函数问题

上一篇:STM8S——Clock control(CLK)
下一篇:stm8s eeprom读写

推荐阅读

INICnet兼容汽车以太网,可以有效连接基于IP的车内通信 随着汽车内网络增加移动服务、跨域通信和自动驾驶应用,信息娱乐系统要求更灵活的解决方案来传输数据包、数据流和控制内容。现有的实现方式成本较高且不方便使用,或者带宽和数据分组能力有限,无法支持系统更新,满足网络互联要求。为了满足这一需求,Microchip Technology Inc.(美国微芯科技公...
据外媒报道,当地时间11月18日,汽车安全系统全球领导者奥托立夫(Autoliv)宣布,研发了一款新型前排中央安全气囊(front center airbag),以在发生侧面碰撞事故时,挽救乘员生命。当地时间11月19日,该款安全气囊将在犹他州奥格登技术中心举行的奥托立夫资本市场日(Capital Markets Day)上展出。(图片来源:奥托立夫)在任何道路碰撞事故中,头...
低压差 (LDO) 线性稳压器广泛应用于噪声敏感型应用已有数十年了。然而,随着最新的精密传感器、高速和高分辨率数据转换器 (ADC 和 DAC) 以及频率合成器 (PLL/VCO) 不断向传统的 LDO 稳压器提出挑战,以产生超低输出噪声和超高电源纹波抑制 (PSRR),噪声要求变得越来越难以满足。例如,在为传感器供电时,电源噪声会直接影响测量结果的准确性。开关稳压器通...
11 月 17 日讯,近日维信诺控股公司昆山国显光电主导制定的《柔性显示器件 第 4-1 部分:可穿戴柔性显示模块规范》和《有机发光二极管显示器件 第 4-1 部分:用于屏下摄像的显示模块规范》这两项行业标准获得立项。OLED 屏幕具备柔性、轻薄、容易集成等优势,已经被广泛应用于包含手机、智能穿戴等多个领域,故需要拥有创新技术积累和量产供货经...

史海拾趣

问答坊 | AI 解惑

《程序员》杂志,合适我们做嵌入式开发的么?

《程序员》杂志,最近要100期了,关注了一下。 不知道这本杂志,合适我们做嵌入式开发的么?有没有相关的WinCE嵌入式专题? 值得订阅么?…

查看全部问答∨

求 ps2鼠标和cpu的连线图!

求 ps2鼠标和cpu的连线图!   小弟过2天就要交毕业设计了,老师非得让我加个图.我的论文题目是基于嵌入式的PS/2鼠标接口设计.   拜托各位大哥大姐帮我下.   小弟不胜感激!在线等图.   把图发上 ...…

查看全部问答∨

手机模块没有返回结果,请问这是什么原因呢?

使用同样的AT指令分别在超级终端下和用代码方式发向手机模块,结果前者可以收到结果而后都却收不到。 请问这是什么原因呢?我估计是配置问题,像波特率等。你的看法呢?谢谢。 …

查看全部问答∨

串口开发小小心得

串口开发小小心得 本人新入行,写的也只是很肤浅的自己的一点点理解。欢迎批评指正,qq:15065328.email:zxiki@163.com。msn:zxiki@hotmail.com。如果这些经验能对您有所帮助,我将非常荣幸。欢迎转载(可能抬举自己了),但请把以上文字一并保 ...…

查看全部问答∨

STM32F103ZF有样品了吗

                                 STM32F103ZF, STM32F103ZG 现在有样品提供了吗?…

查看全部问答∨

请教怎么整一个能通过JTAG带源码级仿真调试的汇编框架?

整了很多天的STM32 汇编,想通过HJTAG 进行源码级调试,一直未成功。 有什么法子?还是HJTAG不支持STM32的源码级调试?真闷啊!…

查看全部问答∨

51单片机学习资料大放送

51单片机学习资料大放送 有软件有资料…

查看全部问答∨

stm32下载lcd程序,在人家电脑可以,我的不可以!!!

想不通,为什么我板子和数据线放在朋友电脑上,然后用mucisp烧录后,就有反应,在我电脑上只是lcd晾着 是不是有地方还要设置呢?从哪里发现? 有没有什么检查的方法…

查看全部问答∨

大家用过气压传感器没,推荐一下哪个好?

最近想玩一下测量海拔的,一般都是基于气压测量海拔。需要气压传感器。然后放大滤波采集再显示。请教下用过该类传感器的。哪个型号比较好。…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved