STM8L IAP 使用说明 前言 本篇主要介绍 STM8Lxxxx 如何实现在应用程序中编程 (In-application programming) 1. IAP user Flash 分配框图及中断向量表重定向 0x8000 0x8080 0x9000 中断向量表重定向 0x9080 图 1:IAP 代码在 User Flash 中的空间分配 注意 : 1 和 2 为 IAP 代码空间 为客户自己的 bootloader 代码, 应用程序中更新 Flash 的代码 3 和 4 为客户应用程序代码, 实现产品具体操作功能 中断向量表 1 中除了 Reset, 其他存放的是指向中断向量表 2 的地址 ; 中断向量表 2 中放的是具体的 APP 中断处理程序入口地址 发生中断后 PC 指针先指向中断向量表 1, 然后再指向中断向量表 2, 最后到具体的中断处理函数处 客户应用程序起始位置 ( 上图是 0x9000) 可以根据客户需要设置, 比如可以改 0x9000 为 0xA000( 如果客户的 bootloader 程序超过 0x9000 但没有超过 0xA000 可以这样设置 )
Step1 发生中断 Step2 跳转到向量表 2 Step4 APP 软件发生中断 Step3 跳转到具体的处理函数 图 2:IAP 代码的中断处理流程 2. IAP 对中断向量表重定向的说明 STM8 的中断向量位置是固定的, 大部分是 0x8000 开始处 IAP 程序中需要手工处理中断向量表 并且 boot 程序不能使用任何中断 (IAP 程序中的中断跳转 ( 中断向量表 1) 会使 PC 指到 0x900x 处, 如果此时 APP 没有程序, 程序就会出错 ), 程序中的所有中断 ( 向量表 1) 的处理最终都要跳转到用户程序的中断向量表 2 处 IAP bootloader 参考程序为 STSW-STM8006 可以在 www.st.com 或是 www.stmcu.com.cn 上下载 下面以 STVD 工程 Cosmic 为例进行说明 \STSW-STM8006\AN2659-IAP_using_user-bootloader\Project\STM8L_User-Bootloader_example\STVD\Cosmic Stm8_interrupt_vector.c: 下面的中断向量表 1 位于 0x8000 到 0x8080 地址空间 假设发生了 0x8001 中断, 指针经硬件定向到了 0x8001, 在 0x8001 里存储的是跳转到 0x9001 代码, 然后程序跳转到 0x9001 位置去执行, 而 0x9001 中的代码是跳转到具体的中断函数处 ( 具体代码中使用函数指针来实现 ) 0x82 为操作码, 意思是跳转到后面的地址去执行 如下例 : 0x82 INT1_E (8bits)(PCE) INT1_H (8bits)(PCH) INT1_L (8bits)(PCL) //*********IAP bootloader 程序中的中断向量表 1 ************************** extern void _stext(); /* startup routine */ struct interrupt_vector const UserISR_IRQ[32] @ MAIN_USER_RESET_ADDR; //redirected interrupt table struct interrupt_vector const _vectab[] = 0x82, (interrupt_handler_t)_stext, /* reset */ //note: 向量表代码开始位置为 0x8000,0x82 后面的 24bits 存放 0x9000 0x82, (interrupt_handler_t)(userisr_irq+ 1), /* trap */ //note: 代码位于 0x8001,0x82 后面的 24bits 存放 0x9001 0x82, (interrupt_handler_t)(userisr_irq+ 2), /* irq0 */ 0x82, (interrupt_handler_t)(userisr_irq+ 3), /* irq1 */ 0x82, (interrupt_handler_t)(userisr_irq+ 4), /* irq2 */ 0x82, (interrupt_handler_t)(userisr_irq+ 5), /* irq3 */
0x82, (interrupt_handler_t)(userisr_irq+ 6), /* irq4 */ 0x82, (interrupt_handler_t)(userisr_irq+ 7), /* irq5 */ 0x82, (interrupt_handler_t)(userisr_irq+ 8), /* irq6 */ 0x82, (interrupt_handler_t)(userisr_irq+ 9), /* irq7 */ 0x82, (interrupt_handler_t)(userisr_irq+10), /* irq8 */ 0x82, (interrupt_handler_t)(userisr_irq+11), /* irq9 */ 0x82, (interrupt_handler_t)(userisr_irq+12), /* irq10 */ 0x82, (interrupt_handler_t)(userisr_irq+13), /* irq11 */ 0x82, (interrupt_handler_t)(userisr_irq+14), /* irq12 */ 0x82, (interrupt_handler_t)(userisr_irq+15), /* irq13 */ 0x82, (interrupt_handler_t)(userisr_irq+16), /* irq14 */ 0x82, (interrupt_handler_t)(userisr_irq+17), /* irq15 */ 0x82, (interrupt_handler_t)(userisr_irq+18), /* irq16 */ 0x82, (interrupt_handler_t)(userisr_irq+19), /* irq17 */ 0x82, (interrupt_handler_t)(userisr_irq+20), /* irq18 */ 0x82, (interrupt_handler_t)(userisr_irq+21), /* irq19 */ 0x82, (interrupt_handler_t)(userisr_irq+22), /* irq20 */ 0x82, (interrupt_handler_t)(userisr_irq+23), /* irq21 */ 0x82, (interrupt_handler_t)(userisr_irq+24), /* irq22 */ 0x82, (interrupt_handler_t)(userisr_irq+25), /* irq23 */ 0x82, (interrupt_handler_t)(userisr_irq+26), /* irq24 */ 0x82, (interrupt_handler_t)(userisr_irq+27), /* irq25 */ 0x82, (interrupt_handler_t)(userisr_irq+28), /* irq26 */ 0x82, (interrupt_handler_t)(userisr_irq+29), /* irq27 */ 0x82, (interrupt_handler_t)(userisr_irq+30), /* irq28 */ 0x82, (interrupt_handler_t)(userisr_irq+31), /* irq29 */ ; //********************************************************************************* 对 0x82 的描述在文件 PM0044 有如下描述 : 0x82 为内部指令 :
在 main.h 里有下面的代码 : MAIN_USER_RESET_ADDR 的地址为 0x9000 所以 APP 代码开始的位置在 0x9000, 开始存 放第二个中断向量表 ( 中断向量表 2), 此处为中断处理函数入口地址的重定向表 //********************************************************************************* //user application start (user interrupt table address) #define MAIN_USER_RESET_ADDR 0x9000ul //********************************************************************************* 3. STVD 软件中, 下图 Project/Settings 中对中断向量表位置的处理可以看到 中断向量表 1 是从 0x8000 开始存放 (Vector file name and Vector addr.) 图 3:STVD 软件 Project/Settings 对 Vector file name 的定义为 stm8_interrupt_vector.c ; Vector address 定义为 0x8000 地址 如下图
图 4:IAP 程序工程的配置,STVD 软件 Project/Settings/Linker \STSW-STM8006\AN2659-IAP_using_user-bootloader\Project\STM8L_User-Bootloader_example\STVD\Cosmic\Debug 有文件 userbootloader.lkf, 有代码如下 :( 当这个文件中的设置同 STVD Project/Settings/Linker 对画框中的设置不一样时, 优先使用对话框中的设置 ) //********************************************************************************** # Segment configuration - section reserved for STVD #<BEGIN SEGMENT_CONF> # Segment Code,Constants: +seg.const -b 0x8080 -m 0x7f80 -n.const -it +seg.text -a.const -n.text # Segment Eeprom: +seg.eeprom -b 0x1000 -m 0x400 -n.eeprom # Segment Zero Page: +seg.bsct -b 0x0 -m 0x100 -n.bsct +seg.ubsct -a.bsct -n.ubsct +seg.bit -a.ubsct -n.bit -id +seg.share -a.bit -n.share -is # Segment Ram: +seg.data -b 0x100 -m 0x4ff -n.data +seg.bss -a.data -n.bss +seg.flash_code -a.bss -n.flash_code -ic #<END SEGMENT_CONF
# Interrupt vectors file - section reserved for STVD #<BEGIN VECTOR_FILE> +seg.const -b 0x8000 -k Debug\stm8_interrupt_vector.o #<END VECTOR_FILE> //******************************************************************************* 4. User Flash 空间烧写方式 Bootloader 程序可以烧写内部 Flash EEPROM RAM 适用于产品软件的更新 客户程序空间烧写 User Flash programming Byte/Work 编程 (1~4bytes) 优点 : 小区域编程,code 可以在 Flash 里执行 适合几个 bytes 的编程, 或是可以接受很慢的编程速度缺点 : 烧写 Flash 时,code 的执行停止 ( 几个 ms); 速度慢 块编程 ( 由具体 STM8 IC 确定 优点 : 大块区域编程, 速度快 缺点 :code 必须在 RAM 里执行, 需要拷贝代码到 RAM 里 拷贝可执行代码到 RAM 里 / 保存 RAM 代码 / 允许代码在 RAM 空间 / 编译代码使其能在 RAM 里运行 5. 对 _fctcpy 的说明, 对 Flash 的大块区域编程的代码在 RAM 中运行的问题解 决 对 Flash 进行大块区域的编程的代码需要在 RAM 中运行, 为了实现这个, 需要一个自定义代码段, 并将这个代码段放在 RAM 中 在例程中定义了一个.FLASH_CODE 段 请查看下面代码红色区域 //*********************IAP 的 bootloader 程序 ********************************* #ifdef _COSMIC_ #pragma section (FLASH_CODE) // 定义 FLASH_CODE 代码段 #endif /* _COSMIC */ #ifdef _IAR_ #pragma location = "FLASH_CODE" #endif /* _IAR_ */ #ifdef _RAISONANCE_ void Mem_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, u8 *Buffer) inram #else void Mem_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, u8 *Buffer) #endif /*_RAISONANCE_*/
u16 Count = 0; u32 StartAddress = 0; u16 timeout = (u16)0x6000; /* Set Start address wich refers to mem_type */ if (MemType == FLASH_MEMTYPE_PROG) StartAddress = FLASH_START; else StartAddress = EEPROM_START; /* Point to the first block address */ StartAddress = StartAddress + ((u32)blocknum * BLOCK_SIZE); /* Standard programming mode */ FLASH->CR2 = (u8)0x01; /* Copy data bytes from RAM to FLASH memory */ for (Count = 0; Count < BLOCK_SIZE; Count++) *((PointerAttr u8*)startaddress + Count) = ((u8)(buffer[count])); #if defined (STM8S208) defined(stm8s207) defined(stm8s105) if (MemType == FLASH_MEMTYPE_DATA) /* Waiting until High voltage flag is cleared*/ while ((FLASH->IAPSR & 0x40)!= 0x00 (timeout == 0x00)) timeout--; #endif /* STM8S208, STM8S207, STM8S105 */ #ifdef _COSMIC_ #pragma section () // 普通默认代码段 #endif /* COSMIC */ //******************************************************************************* _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 中的代码移植到此 void main(void) _fctcpy('f'); // 把 FLASH_CODE 代码拷贝到 RAM 中并运行 图 5.xxx IAP 工程中,RAM 区域.FLASH_CODE 段的定义 可以在生成的 *.map 文件中检查生成的段是否正确, 示例代码中有如下的 map 文件 //******************************************************************************* -------- Segments -------- start 00008080 end 000080a2 length 34 segment.const start 00008104 end 00008be0 length 2780 segment.text start 00001000 end 00001000 length 0 segment.eeprom start 00000000 end 00000001 length 1 segment.bsct, initialized start 000080af end 000080b0 length 1 segment.bsct, from start 00000001 end 00000091 length 144 segment.ubsct start 00000091 end 00000091 length 0 segment.bit start 00000091 end 00000091 length 0 segment.share
start 00000100 end 00000100 length 0 segment.data start 00000100 end 00000100 length 0 segment.bss start 00000100 end 00000154 length 84 segment.flash_code, initialized start 000080b0 end 00008104 length 84 segment.flash_code, from start 00000000 end 000004de length 1246 segment.info. start 00000000 end 00000e70 length 3696 segment.debug start 00008000 end 00008080 length 128 segment.const start 000080a2 end 000080af length 13 segment.init //******************************************************************************* 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 程序
重要通知 - 请仔细阅读 意法半导体公司及其子公司 ( ST ) 保留随时对 ST 产品和 / 或本文档进行变更 更正 增强 修改和改进的权利, 恕不另行通知 买方在订货之前应获取关于 ST 产品的最新信息 ST 产品的销售依照订单确认时的相关 ST 销售条款 买方自行负责对 ST 产品的选择和使用, ST 概不承担与应用协助或买方产品设计相关的任何责任 ST 不对任何知识产权进行任何明示或默示的授权或许可 转售的 ST 产品如有不同于此处提供的信息的规定, 将导致 ST 针对该产品授予的任何保证失效 ST 和 ST 徽标是 ST 的商标 所有其他产品或服务名称均为其各自所有者的财产 本文档中的信息取代本文档所有早期版本中提供的信息 2015 STMicroelectronics - 保留所有权利