踩坑STM8s IAP——Bootloader与App互相跳转

背景介绍:
开发环境 STVD,芯片型号STM8S208C8T6
很多步骤网上都讲了,但是有一个重点步骤 - 工程配置没讲,让我摸索了好久

按STM8S208xx芯片手册指导
踩坑STM8s IAP——Bootloader与App互相跳转_第1张图片

我 分别用两个不同工程各自实现IAP和APP功能,由于是小系统,空间还比较充足,计划用2k空间(0x8000 - 0x9FFF)来存放IAP,剩余的空间(0xA000 - 0x17FFF)存放APP。

其中重点设置这两个工程的存放地址,和编写不同的中断向量表
IAP部分:
工程配置截图:
1、存储IAP中断向量表起始地址(0x8000开始 128个字节)
2、存储IAP代码区域起始地址
3、在STVD->Project->Settings->Linker选项卡下,选择目录Category下的Input,在Ram下新建Section,Option填-ic,表示可移至RAM。
踩坑STM8s IAP——Bootloader与App互相跳转_第2张图片
IAP因为只用于刷写flash,尽量不用中断,中断向量表可以上网下一个,我这里也贴一份我的吧,然后记得在某个头文件做个宏定义:

#define APP_START_ADDR				0x00A000ul

并在stm8_interrupt_vector.c把头文件包含进去,比如#include “Includes.h”

/*	Redirected interrupt vector table
 *	Copyright (c) 2008 STMicroelectronics
 */

#include "Includes.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
	unsigned char interrupt_instruction;
	interrupt_handler_t interrupt_handler;
};
#if 0
@far @interrupt void NonHandledInterrupt (void)
{
	/* in order to detect unexpected events during development,
	   it is recommended to set a breakpoint on the following instruction
	*/
	return;
}
#endif

extern void _stext();     /* startup routine */
struct interrupt_vector const UserISR_IRQ[32] @ APP_START_ADDR;

//redirected interrupt table
struct interrupt_vector const _vectab[] = {
    {0x82, (interrupt_handler_t)_stext}, /* reset */
    {0x82, (interrupt_handler_t)(UserISR_IRQ+ 1)}, /* trap  */
    {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 */
};

APP部分:
工程配置截图:
1、存储APP中断向量表起始地址(0xA000开始 128个字节)
2、存储APP代码区域起始地址
踩坑STM8s IAP——Bootloader与App互相跳转_第3张图片
APP中断向量表可以直接上管下例程拿一个来用

/* BASIC INTERRUPT VECTORS TABLE FOR STM8 devices
 * Copyright (c) 2014 STMicroelectronics
 */

#include "main.h"
#include "stm8s_it.h"

typedef void @far (*interrupt_handler_t)(void);

struct interrupt_vector {
	u8 interrupt_instruction;
	interrupt_handler_t interrupt_handler;
};

//struct interrupt_vector const UserISR_IRQ[32] @ APP_START_ADDR;

struct interrupt_vector const _vectab[] = {
	{0x82, (interrupt_handler_t)_stext}, /* RESET */
	{0x82, (interrupt_handler_t)TRAP_IRQHandler}, /* TRAP - Software interrupt */
	{0x82, (interrupt_handler_t)TLI_IRQHandler}, /* irq0 - External Top Level interrupt (TLI) */
	{0x82, (interrupt_handler_t)AWU_IRQHandler}, /* irq1 - Auto Wake Up from Halt interrupt */
	{0x82, (interrupt_handler_t)CLK_IRQHandler}, /* irq2 - Clock Controller interrupt */
	{0x82, (interrupt_handler_t)EXTI_PORTA_IRQHandler}, /* irq3 - External interrupt 0 (GPIOA) */
	{0x82, (interrupt_handler_t)EXTI_PORTB_IRQHandler}, /* irq4 - External interrupt 1 (GPIOB) */
	{0x82, (interrupt_handler_t)EXTI_PORTC_IRQHandler}, /* irq5 - External interrupt 2 (GPIOC) */
	{0x82, (interrupt_handler_t)EXTI_PORTD_IRQHandler}, /* irq6 - External interrupt 3 (GPIOD) */
	{0x82, (interrupt_handler_t)EXTI_PORTE_IRQHandler}, /* irq7 - External interrupt 4 (GPIOE) */
	
#if defined(STM8S208) || defined(STM8AF52Ax)
	{0x82, (interrupt_handler_t)CAN_RX_IRQHandler}, /* irq8 - CAN Rx interrupt */
	{0x82, (interrupt_handler_t)CAN_TX_IRQHandler}, /* irq9 - CAN Tx/ER/SC interrupt */
#elif defined(STM8S903) || defined(STM8AF622x)
	{0x82, (interrupt_handler_t)EXTI_PORTF_IRQHandler}, /* irq8 - External interrupt 5 (GPIOF) */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq9 - Reserved */
#else /*STM8S207, STM8S105 or STM8AF62Ax or STM8AF626x*/
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq8 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq9 - Reserved */
#endif /* STM8S208 or STM8AF52Ax */
	{0x82, (interrupt_handler_t)SPI_IRQHandler}, /* irq10 - SPI End of transfer interrupt */
	{0x82, (interrupt_handler_t)TIM1_UPD_OVF_TRG_BRK_IRQHandler}, /* irq11 - TIM1 Update/Overflow/Trigger/Break interrupt */
	{0x82, (interrupt_handler_t)TIM1_CAP_COM_IRQHandler}, /* irq12 - TIM1 Capture/Compare interrupt */
  
#if defined(STM8S903) || defined(STM8AF622x)
	{0x82, (interrupt_handler_t)TIM5_UPD_OVF_BRK_TRG_IRQHandler}, /* irq13 - TIM5 Update/Overflow/Break/Trigger interrupt  */
	{0x82, (interrupt_handler_t)TIM5_CAP_COM_IRQHandler}, /* irq14 - TIM5 Capture/Compare interrupt */
	
#else /*STM8S208, STM8S207, STM8S105 or STM8S103 or STM8AF62Ax or STM8AF52Ax or STM8AF626x*/
	{0x82, (interrupt_handler_t)TIM2_UPD_OVF_BRK_IRQHandler}, /* irq13 - TIM2 Update/Overflow/Break interrupt  */
	{0x82, (interrupt_handler_t)TIM2_CAP_COM_IRQHandler}, /* irq14 - TIM2 Capture/Compare interrupt */
#endif /*STM8S903*/
	
#if defined(STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \
    defined(STM8S005) ||  defined(STM8AF52Ax) || defined(STM8AF62Ax) || defined(STM8AF626x)
	{0x82, (interrupt_handler_t)TIM3_UPD_OVF_BRK_IRQHandler}, /* irq15 - TIM3 Update/Overflow/Break interrupt */
	{0x82, (interrupt_handler_t)TIM3_CAP_COM_IRQHandler}, /* irq16 - TIM3 Capture/Compare interrupt */
#else
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq15 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq16 - Reserved */
#endif /*STM8S208, STM8S207, STM8S105 or STM8AF62Ax or STM8AF52Ax or STM8AF626x*/
	
#if defined(STM8S105) || defined(STM8S005) || defined(STM8AF626x)
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq17 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq18 - Reserved */
#elif defined (STM8AF622x)
	{0x82, (interrupt_handler_t)UART4_TX_IRQHandler}, /* irq17 - UART4 Tx complete interrupt */
	{0x82, (interrupt_handler_t)UART4_RX_IRQHandler}, /* irq18 - UART4 Rx interrupt */
#else	
	{0x82, (interrupt_handler_t)UART1_TX_IRQHandler}, /* irq17 - UART1 Tx complete interrupt */
	{0x82, (interrupt_handler_t)UART1_RX_IRQHandler}, /* irq18 - UART1 Rx interrupt */
#endif /*STM8S105 or STM8AF626x */
	{0x82, (interrupt_handler_t)I2C_IRQHandler}, /* irq19 - I2C interrupt */

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

	{0x82, (interrupt_handler_t)UART3_TX_IRQHandler}, /* irq20 - UART3 Tx interrupt */
	{0x82, (interrupt_handler_t)UART3_RX_IRQHandler}, /* irq21 - UART3 Rx interrupt */
#elif defined(STM8S105) || defined(STM8S005) || defined(STM8AF626x)
	{0x82, (interrupt_handler_t)UART2_TX_IRQHandler}, /* irq20 - UART2 Tx interrupt */
	{0x82, (interrupt_handler_t)UART2_RX_IRQHandler}, /* irq21 - UART2 Rx interrupt */

#else /* STM8S103, STM8S903, STM8AF622x */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq20 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq21 - Reserved */
#endif /* STM8S208, STM8S207, STM8AF52Ax or STM8AF62Ax */

#if defined(STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8AF52Ax) || defined(STM8AF62Ax)
	{0x82, (interrupt_handler_t)ADC2_IRQHandler}, /* irq22 - ADC2 end of conversion interrupt */
#else /* STM8S105, STM8S103, STM8S903, STM8AF622x   */
	{0x82, (interrupt_handler_t)ADC1_IRQHandler}, /* irq22 - ADC1 end of conversion/Analog watchdog interrupts */

#endif /* STM8S208, STM8S207, STM8AF52Ax or STM8AF62Ax */

#if defined(STM8S903) || defined(STM8AF622x)
	{0x82, (interrupt_handler_t)TIM6_UPD_OVF_TRG_IRQHandler}, /* irq23 - TIM6 Update/Overflow/Trigger interrupt */
#else
	{0x82, (interrupt_handler_t)TIM4_UPD_OVF_IRQHandler}, /* irq23 - TIM4 Update/Overflow interrupt */
#endif /* (STM8S903) || (STM8AF622x) */
	{0x82, (interrupt_handler_t)EEPROM_EEC_IRQHandler},  /* irq24 - FLASH interrupt */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq25 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq26 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq27 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq28 - Reserved */
	{0x82, (interrupt_handler_t)NonHandledInterrupt}, /* irq29 - Reserved */

};

/******************* (C) COPYRIGHT 2014 STMicroelectronics *****END OF FILE****/

从IAP跳转到APP很简单,用以下汇编指令即可

	_asm("LDW X,  SP ");
	_asm("LD  A,  $FF");
	_asm("LD  XL, A  ");
	_asm("LDW SP, X  ");
	_asm("JPF $A000");

从APP跳回IAP也可以这样干,但是从一个产品角度来说最好让设备重启一下。我的逻辑大概是:
开机检测EPPROM里的升级标志;
-> 无需升级——IAP跳APP,汇编指令直接跳转;
-> 需要升级——升级完成后来个死循环,利用看门狗实现自动重启变成无需升级进入APP;
-> APP跳IAP,APP内接收到升级请求,进入死循环,利用看门狗实现自动重启进入升级。

死循环例子:
while(1)
{
	;
}

你可能感兴趣的:(嵌入式,嵌入式,单片机)