完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
STM8 In Application Programming
IAP编写的三个要点:
要编写IAP程序首先需要解决的问题是程序在运行过程中,当发生异常时,如何保证程序正常的跳转到相应的异常服务函数(不论程序是运行在bootloader还是application)。 但STM8没有类似NVIC之类的中断控制器管理中断向量的地址,STM8的向量表固定在0x008000,因此在IAP中需要重定位向量表来实现(为了bootLoader和application都可以使用中断,因此,选择将向量表重定位到RAM中) 规划内存分布 针对于STM8L052C6(2K RAM/32K FLASH) FLASH分布 [tr][/tr]
在0xC000开始的前128个字节,放置着application的向量表 RAM分布 [tr][/tr]
利用RAM的特性(rwx),当bootloader运行时,放置bootloader的向量表,当application运行时,放置application的向量表。 详细的分布规则,请参考config目录下的lnkstm8l052c6.icf文件 链接脚本语法请参考IARforSTM8/stm8/doc目录下的EWSTM8_DevelopmentGuide.pdf文件 重定位STM8中断向量表 由于STM8的向量表固定在0x008000~0x008080的位置,想要实现重定位向量表,则必须在固定的向量表中填入真正的向量表地址,方法如下:(参考src目录下的stm8l15x_interrupt.s文件) /* * The interrupt vector table. */ SECTION `.intvec`:CONST define_vector MACRO DC8 0x82 DC24 _interrupt_1 ENDM PUBLIC __intvec EXTERN __iar_program_start __intvec: DC8 0x82 DC24 __iar_program_start ;; RESET 0x8000 DC8 0x82 DC24 0x0004 DC8 0x82 DC24 0x0008 DC8 0x82 DC24 0x000C DC8 0x82 DC24 0x0010 DC8 0x82 DC24 0x0014 DC8 0x82 DC24 0x0018 DC8 0x82 DC24 0x001C DC8 0x82 DC24 0x0020 DC8 0x82 DC24 0x0024 DC8 0x82 DC24 0x0028 DC8 0x82 DC24 0x002C DC8 0x82 DC24 0x0030 DC8 0x82 DC24 0x0034 DC8 0x82 DC24 0x0038 DC8 0x82 DC24 0x003C DC8 0x82 DC24 0x0040 DC8 0x82 DC24 0x0044 DC8 0x82 DC24 0x0048 DC8 0x82 DC24 0x004C DC8 0x82 DC24 0x0050 DC8 0x82 DC24 0x0054 DC8 0x82 DC24 0x0058 DC8 0x82 DC24 0x005C DC8 0x82 DC24 0x0060 DC8 0x82 DC24 0x0064 DC8 0x82 DC24 0x0068 DC8 0x82 DC24 0x006C DC8 0x82 DC24 0x0070 DC8 0x82 DC24 0x0074 DC8 0x82 DC24 0x0078 DC8 0x82 DC24 0x007C 汇编语法请参考IARforSTM8/stm8/doc目录下的EWSTM8_AssemblerReference.pdf文件 说明: 以TRAP中断为例,当发送TRAP中断时,PC指针首先指向0x008004地址(FLASH/硬件自动完成)去取指,取到的指令操作码为 82 00 00 04,这段操作码对应的指令为INT 0x000004,操作为将目标地址(0x000004)加载到PC寄存器中,效果等于PC指针指向0x000004地址(RAM)去取指,同样的,在0x000004地址处(RAM)存放着指令操作码82 00 b8 db,其中在0x00b8db地址处(FLASH)存放着真正的TRAP中断服务程序,当PC指针指向0x00b8db地址后,从而执行TRAP中断服务函数。 在RAM中放置bootloader的向量表 typedef void (INTERRUPT *interrupt_handler_t)(void); struct interrupt_vector { unsigned char interrupt_instruction; unsigned char reserve; interrupt_handler_t interrupt_handler; }; struct interrupt_vector isr_handler[32] @".memvectab" = { {0x82, 0x00, __iar_program_start}, {0x82, 0x00, TRAP_IRQHandler}, {0x82, 0x00, NMI_IRQHandler}, {0x82, 0x00, FLASH_IRQHandler}, {0x82, 0x00, DMA1_CHANNEL0_1_IRQHandler}, {0x82, 0x00, DMA1_CHANNEL2_3_IRQHandler}, {0x82, 0x00, RTC_CSSLSE_IRQHandler}, {0x82, 0x00, EXTIE_F_PVD_IRQHandler}, {0x82, 0x00, EXTIB_G_IRQHandler}, {0x82, 0x00, EXTID_H_IRQHandler}, {0x82, 0x00, EXTI0_IRQHandler}, {0x82, 0x00, EXTI1_IRQHandler}, {0x82, 0x00, EXTI2_IRQHandler}, {0x82, 0x00, EXTI3_IRQHandler}, {0x82, 0x00, EXTI4_IRQHandler}, {0x82, 0x00, EXTI5_IRQHandler}, {0x82, 0x00, EXTI6_IRQHandler}, {0x82, 0x00, EXTI7_IRQHandler}, {0x82, 0x00, LCD_AES_IRQHandler}, {0x82, 0x00, SWITCH_CSS_BREAK_DAC_IRQHandler}, {0x82, 0x00, ADC1_COMP_IRQHandler}, {0x82, 0x00, TIM2_UPD_OVF_TRG_BRK_USART2_TX_IRQHandler}, {0x82, 0x00, TIM2_CC_USART2_RX_IRQHandler}, {0x82, 0x00, TIM3_UPD_OVF_TRG_BRK_USART3_TX_IRQHandler}, {0x82, 0x00, TIM3_CC_USART3_RX_IRQHandler}, {0x82, 0x00, TIM1_UPD_OVF_TRG_COM_IRQHandler}, {0x82, 0x00, TIM1_CC_IRQHandler}, {0x82, 0x00, TIM4_UPD_OVF_TRG_IRQHandler}, {0x82, 0x00, SPI1_IRQHandler}, {0x82, 0x00, USART1_TX_TIM5_UPD_OVF_TRG_BRK_IRQHandler}, {0x82, 0x00, USART1_RX_TIM5_CC_IRQHandler}, {0x82, 0x00, I2C1_SPI2_IRQHandler} }; 同时,在链接脚本中,将.memvectab这个section 放置在RAM的0x000000地址处。 STM8启动过程 在上面两部分中介绍的,在RAM的0x00~0x80地址处会在不同阶段时放置bootloader和application的两张向量表,因此必然涉及到两张向量表的互相覆盖。 在STM8启动时,会执行__iar_program_start这个函数(此函数由IAR提供),这个函数负责建立C运行时环境和数据的拷贝,因此,在这个阶段会将bootloader真正的向量表从FLASH拷贝到RAM的0x00 ~ 0x80地址处(由链接脚本指定),当需要跳转到application时,运行以下代码将application的向量表拷贝到RAM的0x00 ~ 0x80地址处然后跳转: void reload_interrupr_vectortable(void) { uint8_t *check = (uint8_t *)APPLICATION_ADDRESS; if(*check == 0x82) { uint8_t *src = (uint8_t *)APPLICATION_ADDRESS; uint8_t *dst = (uint8_t *)VECTAB_RELOAD_START; uint16_t cnt = sizeof(isr_handler); /* disable interrupt, interrupt will be enable in application */ sim(); platform_peripherals_deinit(); /* reload interrupt vector table(application) from flash to memory */ for(; cnt > 0; cnt--) { *dst++ = *src++; } /* reset stack pointer (lower byte - because compiler decreases SP with some bytes) */ asm("LDW X, SP "); asm("LD A, $FF"); asm("LD XL, A "); asm("LDW SP, X "); asm("JPF $C000 "); /* APPLICATION_ADDRESS */ } } 通过汇编指令asm("JPF $C000")跳转到application的起始地址处,开始运行application。 当复位时,会重新执行__iar_program_start函数,将bootloader的向量表再次拷贝到RAM的0x00~0x80地址处,覆盖application的向量表。 至此,IAP编写的难点都已解决。 附连接脚本 / // Example ILINK command file for // STM8 IAR C/C++ Compiler and Assembler. // // Copyright 2017 HinsShum. // // $Revision: 1623 $ // / /*-Symbol-*/ define symbol __intvec_start__ = 0x000000; define symbol __region_TINY_start__ = 0x000000; define symbol __region_TINY_end__ = 0x0000FF; define symbol __region_ROM_start__ = 0x008000; define symbol __region_ROM_end__ = 0x00BFFF; /* 16K bootloader flash region */ define symbol __region_RAM_start__ = 0x000000; define symbol __region_RAM_end__ = 0x000FFF; /* 4K RAM region */ define symbol __RAMCACHE_start__ = 0x000100; /*-Memory Regions-*/ define memory mem with size = 16M; define region TinyData = mem:[from __region_TINY_start__ to __region_TINY_end__]; define region ROM_region = mem:[from __region_ROM_start__ to __region_ROM_end__]; define region RAM_region = mem:[from __region_RAM_start__ to __region_RAM_end__]; / define block CSTACK with size = _CSTACK_SIZE, alignment = 1 {}; define block HEAP with size = _HEAP_SIZE, alignment = 1 {}; define block INTVEC with size = 0x80, alignment = 4 { ro section .intvec }; define block INTVECMEM with size = 0x80, alignment = 4 { rw section .memvectab }; define block RAMCACHE with size = 0x40, alignment = 1 {}; define block MD5API with size = 0x06, alignment = 2 { ro section .md5_api }; initialize by copy { rw section .*.textrw, rw data, zi }; do not initialize { rw section vregs, rw section .noinit }; // Keep section keep { section .memvectab }; keep { block RAMCACHE }; keep { section .md5_api }; // Placement place at start of ROM_region { block INTVEC }; place in ROM_region { ro code, ro data }; // includes ro code and data place at end of ROM_region { block MD5API }; // provide md5 api to application place at address mem: __intvec_start__ { block INTVECMEM }; place in TinyData { rw section .vregs }; place at address mem: __RAMCACHE_start__ { block RAMCACHE }; place in RAM_region { rw code, rw data, rw section .*.textrw }; place in RAM_region { zi }; place in RAM_region { block HEAP }; place at end of RAM_region { block CSTACK }; / |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1568 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1513 浏览 1 评论
939 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
669 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1561 浏览 2 评论
1851浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
620浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
506浏览 3评论
511浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
492浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 04:21 , Processed in 0.733485 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号