文章目录
一、介绍
1) Boot 升级简述
2)编写BootLoader注意事项
1.重定向中断向量表
2.Bootloader与Application的空间大小分配定义
3.程序跳转到APP
3)编写APP代码,实现升级中改写升级标志
二、功能实现
1)中断向量表
2)数据写入
3)程序实现
STM8L IAP升级
芯片:STM8L152 64K ROM 2K EEPROM 4KRAM 1页= 2块= 256字节
通讯方式:Uart
IDE: IAR for STM8
实现基于简单串口通信实现IAP升级,测试升级ok,因此写篇笔记记录一下整个过程。
一、介绍
1) IAP简介
所谓的IAP即应用程序中编程(In-application programming),即可以在产品出厂后,更新程序。既然可以更新程序,那么就要有程序负责这部分功能,这个程序就叫做BootLoader,而被更新的程序就叫做Application.
2)编写BootLoader注意事项
如果自己编写Bootloader,则需要注意几个方面:
1.中断向量表的重定向
参考文档《STM8L IAP 应用程序中编程指导.pdf》中的说明,点击下载,如下图
这里写图片描述
可以看到,当Application中发生中断的时候,会跳转到0x8000地址处,因此在Bootloader中需要将中断进行重定向,使之能够跳转到Application中的中断向量表中去。
2.Bootloader与Application的空间分配
boot:0x8000--0x8FFF
app:0x9000--0x17FFF
ICF 文件修改如下:
1.Boot程序的icf文件
define memory with size = 16M;
define region TinyData = [from 0x00 to 0xFF];
define region NearData = [from 0x0000 to 0x07FF];//RAM+בջ=2KB
define region Eeprom = [from 0x1000 to 0x13FF]; //ʁզǰʼַ֘
define region BootROM = [from 0x6000 to 0x67FF];
define region NearFuncCode = [from 0x8000 to 0x8FFF];//FLASH=32KB
define region FarFuncCode = [from 0x8000 to 0x8FFF];
define region HugeFuncCode = [from 0x8000 to 0x8FFF];
2.APP 程序的icf文件
define memory with size = 16M;
define region TinyData = [from 0x00 to 0xFF];
define region NearData = [from 0x0000 to 0x07FF];//RAM+בջ=2KB
define region Eeprom = [from 0x1000 to 0x13FF]; //ʁզǰʼַ֘
define region BootROM = [from 0x6000 to 0x67FF];
define region NearFuncCode = [from 0x9000 to 0xFFFF];//FLASH=32KB
define region FarFuncCode = [from 0x9000 to 0xFFFF];
define region HugeFuncCode = [from 0x9000 to 0xFFFF];
3.程序跳转
程序跳转可以分为Bootloader跳转到Application, Application跳转到Bootloader.
上电之后会先进入bootloader,然后再次跳转到app。
APP复位重启就可以重新进入boot。需要增加一个掉电不丢失的标志位。本次放到EEPROM 中
unsigned char ucBootStatusInEEPROM @0x1000;//16K
#define BOOT_APP_DFT2 0xFF
#define BOOT_APP_DFT1 0x00 //EEPROM默认状态
#define BOOT_APP_DONE 0x50 //APP区有完整的APP代码
#define BOOT_UPDATE 0x51 //APP区代码需要升级
#define BOOT_APP_NONE 0x52 //APP区代码不完整
void EEPROM_Write(unsigned char ucDat)
{
FLASH_Unlock(FLASH_MemType_Data); // unlock Flash
ucBootStatusInEEPROM=ucDat;
FLASH_Lock(FLASH_MemType_Data); // lock Flash
}
unsigned char EEPROM_Read(void)
{
return ucBootStatusInEEPROM;
}
//跳转函数
方法一:
void _ASM_JumpTo_App(void)
{
asm("LDW X, SP ");
asm("LD A, $FF");
asm("LD XL, A ");
asm("LDW SP, X ");
asm("JPF $9000");
}
方法二: asm("JP $9000");
3)APP实现升级重复测试
APP程序实现改写升级完成标志,以便重复测试升级功能
void main(void)
{
unsigned char Times = 0;
//内部时钟作为时钟源 16MHZ
CLK_HSICmd(ENABLE);
while( (CLK->ICKCR&0x02) != 0x02 );//stably
CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI);
CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);//内部时钟不分频
GPIO_LED_MakeOutHIGH();
GPIO_LED_On();
delay_init(16);
delay_ms(500);
GPIO_LED_Off();
Times = 0;
while(1)
{
#if 0
delay_ms(50);
GPIO_LED_Toggle();
Times++;
if(Times>100)
{
if(0x50==EEPROM_Read())
{
EEPROM_Write(0x51);
}
Times=100;
delay_ms(2000);
}
#else
delay_ms(800);
GPIO_LED_Toggle();
Times++;
if(Times>6)
{
if(0x50==EEPROM_Read())
{
EEPROM_Write(0x51);
}
Times=5;
delay_ms(2000);
}
#endif
}
}
二、功能实现
1)重新定义中断向量表
boot中没有采用中断函数,定时查询接收串口的数据
uint32_t FLASH_ReadWord(u32 Address)//读Flash指定地址
{
return(*(PointerAttr u32 *) (u16)Address);
}
//重新初始化STM8的中断向量表 把它重新定义到APP的中断向量中
void STM8_HanderIqr_Init(void)
{
disableInterrupts(); //关闭所有中断
u8 Index;
FLASH_Unlock(FLASH_MemType_Program);//解锁flash
for(Index = 1; Index < 0X20;Index++)
{
if(FLASH_ReadWord(0X8000+4*Index)!=(0X82000000+USER_APP_START_ADD+Index*4))
{
FLASH_ProgramWord(0X8000+4*Index,0X82000000+USER_APP_START_ADD+Index*4);
}
}//用户APP起始地址:0x9000-----USER_APP_START_ADD
FLASH_Lock(FLASH_MemType_Program);
}
2)数据写入FALSH中
我的写入测试,测试写入读取正常。注:FLASH 无需擦除就可以重复写入
void FlashTestOneByte(void)
{
uint32_t FlashAddress[15]={0xA000,0xB000,0xC000,0xD000,0xE000,0xF000,0x10000,0x11000,0x12000,0x13000,0x14000,0x15000,0x16000,0x17000};
uint32_t WFDWbuf[15]={0x10000001,0x10000002,0x10000003,0x10000004,0x10000005,0x10000006,0x10000007,0x10000008,0x10000009,0x10000010,0x10000011,0x10000012,0x10000013,0x10000014,0x10000015};
uint32_t