你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM8L IAP 使用说明

[复制链接]
STMCU小助手 发布时间:2022-2-18 22:07
前言
本篇主要介绍 STM8Lxxxx 如何实现在应用程序中编程(In-application programming)。

1. IAP user Flash 分配框图及中断向量表重定向

KGK$NG_(UVZZMIEBBX$X9PM.png

注意:
1 和 2 为 IAP 代码空间。为客户自己的 bootloader 代码,应用程序中更新 Flash 的代码。
3 和 4 为客户应用程序代码,实现产品具体操作功能。
中断向量表 1 中除了 Reset,其他存放的是指向中断向量表 2 的地址;中断向量表 2 中放的是具体的 APP 中断处理程序入口地址。发生中断后 PC 指针先指向中断向量表 1,然后再指向中断向量表 2,最后到具体的中断处理函数处。客户应用程序起始位置(上图是 0x9000)可以根据客户需要设置,比如可以改 0x9000 为 0xA000(如果客户的bootloader 程序超过 0x9000 但没有超过 0xA000 可以这样设置)。

_~G{G_YFVQFXEOQSHB8AW2O.png

2. IAP 对中断向量表重定向的说明
STM8 的中断向量位置是固定的,大部分是 0x8000 开始处。IAP 程序中需要手工处理中断向量表。并且 boot 程序不能使用任何中断(IAP 程序中的中断跳转(中断向量表 1)会使 PC 指到 0x900x 处,如果此时 APP 没有程序,程序就会出错。),程序中的所有中断(向量表 1)的处理最终都要跳转到用户程序的中断向量表 2 处。
IAP bootloader 参考程序为 STSW-STM8006。
下面以 STVD 工程 Cosmic 为例进行说明。
…\STSW-STM8006\AN2659-IAP_using_user-bootloader\Project\STM8L_User-Bootloader_example\STVD\CosmicStm8_interrupt_vector.c: 下面的中断向量表 1 位于 0x8000 到 0x8080 地址空间。
假设发生了 0x8001 中断,指针经硬件定向到了 0x8001,在 0x8001 里存储的是跳转到 0x9001 代码,然后程序跳转到 0x9001 位置去执行,而 0x9001 中的代码是跳转到具体的中断函数处。(具体代码中使用函数指针来实现)
0x82 为操作码,意思是跳转到后面的地址去执行。如下例:
1%`}X4ZYU0XW%K[C85CC6PJ.png


  1. //*********IAP bootloader 程序中的 中断向量表 1 **************************
  2. extern void _stext(); /* startup routine */
  3. struct interrupt_vector const UserISR_IRQ[32] @ MAIN_USER_RESET_ADDR;
  4. //redirected interrupt table
  5. struct interrupt_vector const _vectab[] = {
  6. {0x82, (interrupt_handler_t)_stext}, /* reset */ //note:向量表代码开始位置为
  7. 0x8000,0x82 后面的 24bits 存放 0x9000
  8. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 1)}, /* trap */ //note:代码位于
  9. 0x8001,0x82 后面的 24bits 存放 0x9001
  10. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 2)}, /* irq0 */
  11. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 3)}, /* irq1 */
  12. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 4)}, /* irq2 */
  13. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 5)}, /* irq3 */
  14. Step1 发生中断
  15. Step2 跳转到向量表 2
  16. Step3 跳转到具体的处理函数
  17. Step4 APP 软件发生中断
  18. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 6)}, /* irq4 */
  19. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 7)}, /* irq5 */
  20. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 8)}, /* irq6 */
  21. {0x82, (interrupt_handler_t)(UserISR_IRQ+ 9)}, /* irq7 */
  22. {0x82, (interrupt_handler_t)(UserISR_IRQ+10)}, /* irq8 */
  23. {0x82, (interrupt_handler_t)(UserISR_IRQ+11)}, /* irq9 */
  24. {0x82, (interrupt_handler_t)(UserISR_IRQ+12)}, /* irq10 */
  25. {0x82, (interrupt_handler_t)(UserISR_IRQ+13)}, /* irq11 */
  26. {0x82, (interrupt_handler_t)(UserISR_IRQ+14)}, /* irq12 */
  27. {0x82, (interrupt_handler_t)(UserISR_IRQ+15)}, /* irq13 */
  28. {0x82, (interrupt_handler_t)(UserISR_IRQ+16)}, /* irq14 */
  29. {0x82, (interrupt_handler_t)(UserISR_IRQ+17)}, /* irq15 */
  30. {0x82, (interrupt_handler_t)(UserISR_IRQ+18)}, /* irq16 */
  31. {0x82, (interrupt_handler_t)(UserISR_IRQ+19)}, /* irq17 */
  32. {0x82, (interrupt_handler_t)(UserISR_IRQ+20)}, /* irq18 */
  33. {0x82, (interrupt_handler_t)(UserISR_IRQ+21)}, /* irq19 */
  34. {0x82, (interrupt_handler_t)(UserISR_IRQ+22)}, /* irq20 */
  35. {0x82, (interrupt_handler_t)(UserISR_IRQ+23)}, /* irq21 */
  36. {0x82, (interrupt_handler_t)(UserISR_IRQ+24)}, /* irq22 */
  37. {0x82, (interrupt_handler_t)(UserISR_IRQ+25)}, /* irq23 */
  38. {0x82, (interrupt_handler_t)(UserISR_IRQ+26)}, /* irq24 */
  39. {0x82, (interrupt_handler_t)(UserISR_IRQ+27)}, /* irq25 */
  40. {0x82, (interrupt_handler_t)(UserISR_IRQ+28)}, /* irq26 */
  41. {0x82, (interrupt_handler_t)(UserISR_IRQ+29)}, /* irq27 */
  42. {0x82, (interrupt_handler_t)(UserISR_IRQ+30)}, /* irq28 */
  43. {0x82, (interrupt_handler_t)(UserISR_IRQ+31)}, /* irq29 */
  44. };
  45. //*********************************************************************************
复制代码

对 0x82 的描述在文件 PM0044 有如下描述: 0x82 为内部指令:

4~_4FRQ{VLJIRMG3EKE@NY6.png

在 main.h 里有下面的代码: MAIN_USER_RESET_ADDR 的地址为 0x9000。所以 APP 代码开始的位置在 0x9000,开始存放第二个中断向量表(中断向量表 2),此处为中断处理函数入口地址的重定向表。
  1. //*********************************************************************************
  2. //user application start (user interrupt table address)
  3. #define MAIN_USER_RESET_ADDR 0x9000ul
  4. //*********************************************************************************
复制代码

3. STVD 软件中,下图 Project/Settings 中对中断向量表位置的处理可以看到。中断向量表 1 是从 0x8000 开始存放(Vector file name and Vector addr.)。

NGU_2EH4@X){NDOP_8ASM[X.png

对“Vector file name”的定义为“stm8_interrupt_vector.c”;“Vector address”定义为“0x8000”地址。如下图。

1PDGVWV74809OW[}LT1HW.png

…\STSW-STM8006\AN2659-IAP_using_user-bootloader\Project\STM8L_User-Bootloader_example\STVD\Cosmic\Debug有文件“userbootloader.lkf”,有代码如下:(当这个文件中的设置同 STVD Project/Settings/Linker 对画框中的设置不一样时,优先使用对话框中的设置)
  1. //**********************************************************************************
  2. # Segment configuration - section reserved for STVD
  3. #<BEGIN SEGMENT_CONF>
  4. # Segment Code,Constants:
  5. +seg .const -b 0x8080 -m 0x7f80 -n .const -it
  6. +seg .text -a .const -n .text
  7. # Segment Eeprom:
  8. +seg .eeprom -b 0x1000 -m 0x400 -n .eeprom
  9. # Segment Zero Page:
  10. +seg .bsct -b 0x0 -m 0x100 -n .bsct
  11. +seg .ubsct -a .bsct -n .ubsct
  12. +seg .bit -a .ubsct -n .bit -id
  13. +seg .share -a .bit -n .share -is
  14. # Segment Ram:
  15. +seg .data -b 0x100 -m 0x4ff -n .data
  16. +seg .bss -a .data -n .bss
  17. +seg .FLASH_CODE -a .bss -n .FLASH_CODE -ic
  18. #<END SEGMENT_CONF

  19. # Interrupt vectors file - section reserved for STVD
  20. #<BEGIN VECTOR_FILE>
  21. +seg .const -b 0x8000 -k
  22. Debug\stm8_interrupt_vector.o
  23. #<END VECTOR_FILE>
  24. //*******************************************************************************
复制代码


4. User Flash 空间烧写方式
   Bootloader 程序可以烧写内部 Flash、EEPROM、RAM。适用于产品软件的更新。

AOYGVR~$X209`UJ)ZZGQQWG.png

5.对 _fctcpy 的说明,对 Flash 的大块区域编程的代码在 RAM 中运行的问题解决。
对 Flash 进行大块区域的编程的代码需要在 RAM 中运行,为了实现这个,需要一个自定义代码段,并将这个代码段放在RAM 中。在例程中定义了一个“.FLASH_CODE”段。 请查看下面代码红色区域。
  1. //*********************IAP 的 bootloader 程序*********************************
  2. #ifdef _COSMIC_
  3. #pragma section (FLASH_CODE) //定义 FLASH_CODE 代码段
  4. #endif /* _COSMIC */
  5. #ifdef _IAR_
  6. #pragma location = "FLASH_CODE"
  7. #endif /* _IAR_ */
  8. #ifdef _RAISONANCE_
  9. void Mem_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, u8 *Buffer) inra
  10. {
  11. u16 Count = 0;
  12. u32 StartAddress = 0;
  13. u16 timeout = (u16)0x6000;

  14. /* Set Start address wich refers to mem_type */
  15. if (MemType == FLASH_MEMTYPE_PROG)
  16. {
  17. StartAddress = FLASH_START;
  18. }
  19. else
  20. {
  21. StartAddress = EEPROM_START;
  22. }
  23. /* Point to the first block address */
  24. StartAddress = StartAddress + ((u32)BlockNum * BLOCK_SIZE);
  25. /* Standard programming mode */
  26. FLASH->CR2 |= (u8)0x01;

  27. /* Copy data bytes from RAM to FLASH memory */
  28. for (Count = 0; Count IAPSR & 0x40) != 0x00 || (timeout == 0x00))
  29. {
  30. timeout--;
  31. }
  32. }
  33. #endif /* STM8S208, STM8S207, STM8S105 */
  34. }
  35. #ifdef _COSMIC_
  36. #pragma section () //普通默认代码段
  37. #endif /* __COSMIC__ */
  38. //*******************************************************************************
复制代码

_fctcpy 功能:
COSMIC 中的函数_fctcpy 是将 Flash 中的代码拷贝到 RAM 中并运行。_fctcpy 寻找 linker 定义的描述符(此描述符是在 RAM中定义段的第一个字符),在 STSW-STM8006 中定义了一个段 FLASH_CODE (#pragma section (FLASH_CODE))。因此第一个字符是‘F’.

在 mian 函数中调用_fctcpy('F')的作用是把 FLASH_CODE 段拷贝到 RAM 中并运行。
FLASH_CODE 是一个可以移动的段,需要在 IAP “boot 程序链接配置”的 RAM 区添加。
在 RAM 中创建一个“.FLASH_CODE”段,并在 Option 中输入“-ic”;“.FLASH_CODE”表示在 RAM 中定义一个
FLASH_CODE 的段,程序可以从此地址运行。“-ic”表示标记这个段为可移动的段,可将 Flash 中的代码移植到此。
  1. void main(void)
  2. {

  3. _fctcpy('F'); //把 FLASH_CODE 代码拷贝到 RAM 中并运行

  4. }
复制代码

{_4YY@LF4LL)PYGCF({97XJ.png

可以在生成的*.map 文件中检查生成的段是否正确,示例代码中有如下的 map 文件
  1. //*******************************************************************************
  2. ---------------------------------------------------------------------------------

  3. Segments
  4. --------

  5. start 00008080 end 000080a2 length 34 segment .const
  6. start 00008104 end 00008be0 length 2780 segment .text
  7. start 00001000 end 00001000 length 0 segment .eeprom
  8. start 00000000 end 00000001 length 1 segment .bsct, initialized
  9. start 000080af end 000080b0 length 1 segment .bsct, from
  10. start 00000001 end 00000091 length 144 segment .ubsct
  11. start 00000091 end 00000091 length 0 segment .bit
  12. start 00000091 end 00000091 length 0 segment .share
  13. start 00000100 end 00000100 length 0 segment .data
  14. start 00000100 end 00000100 length 0 segment .bss
  15. start 00000100 end 00000154 length 84 segment .FLASH_CODE, initialized
  16. start 000080b0 end 00008104 length 84 segment .FLASH_CODE, from
  17. start 00000000 end 000004de length 1246 segment .info.
  18. start 00000000 end 00000e70 length 3696 segment .debug
  19. start 00008000 end 00008080 length 128 segment .const
  20. start 000080a2 end 000080af length 13 segment .init
  21. //*******************************************************************************
复制代码

“from”为存放代码的部分。“initialized”为执行代码的部分。
IAP 的 bootloader 和 APP 分开为两个独立的工程文件。上面的内容是针对 IAP 的 bootloader 的程序工程的处理说明(属于图 1 中的“1.中断变量表 1,复位后硬件 PC 指针从这里开始”和“2.客户程序中的 bootloader 代码” 段),下面来说说APP 工程段(图 1 中的 3 和 4 代码段)。

6. APP 工程说明。
在 APP 工程里,设置中断向量地址为 0x9000(上面以 0x9000 为例。如果从 0xA000 开始,就设置为 0xA000)。代码段的起始地址为 0x9080. 编译后生成的二进制文件就是需要通过 bootloader 烧写到 Flash 0x9000 之后地址的 APP 程序。

收藏 评论0 发布时间:2022-2-18 22:07

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版