最近这段时间使用stm8,要在项目中用到IAP升级,同时还要在BootLoader和App中同时使用中断,花了一些时间查找了很多博客,集合大家的知识,写了一篇文章来总结一下自己的成果。这是我第一次写文章,有错误的地方欢迎大家指出
BootLoader制作分析
1、单片机需要有一个对外的通信接口,一般使用的是单片机自带的串口
2、网上寻找一个稳定的通信协议,保证你的单片机在IAP升级的时,能正确稳定的传输数据。我使用的是
Ymodem协议(如果不知道的可以度娘去了解一下),因为网上有编写好的上位机,比较方便
3、了解stm8的内存分布情况,使用flash读写函数把升级的数据写入单片机的ROM里面
4、重定向中断向量表。这是BootLoader和App都可以使用中断的重点
5、程序跳转
这篇文章的重点是讲解内存和中断重定向的,所以略过1和2
**
STM8的内存分布
从stm8s的数据手册中可以看出stm8s的内存分布情况
前面的我们不用管,因为程序代码的存放是从0x8000开始的,0x8000~0x8080存放的是中断向量表。
所以我们制作BootLoader的思路如下:
根据自己的BootLoader的大小来确定App的存放位置,我这里选择的是0x8000~0x9FFF(8k)部分存放BootLoader的程序代码,0xA000之后的放App的程序代码,当然你也可以选择其他的地址。
在BootLoader里面编写好串口传输和接受函数,然后使用一个标志位来判断是否进入App或者等待接受数据升级程序,如果进入升级状态上位机或其他的设备可以通过USB转串口、蓝牙转串口等传输升级程序代码给单片机,然后BootLoader把数据写入0xA000之后的位置。
怎么把程序代码存入相应的位置呢?我是用的是IAR,可以在软件中进行如下设置:
我用的是stm8s207RB型号的mcu,大家可以根据自己的mcu选择相应的.icf文件。.icf文件可以在IAR的安装目录下找到,我的是在C:Program Files (x86)IAR SystemsEmbedded Workbench 8.0stm8config文件夹中。找到相应的.icf文件之后复制到你的工程文件夹中,给App的.icf进行如下修改,就可以把App的程序位置放在0xA000处。
BootLoader的位置不用改变了,因为程序默认存储的位置就是从0x8000开始的,不过你要保证你的BootLoader程序的大小不能超过你留给它的空间(我这里预留的是8k(0x8000~0x9FFF),足够存储我的BootLoader程序),超过会占用App的位置,就会导致程序崩溃。
PS:
1、我这里使用的升级判断标志是在0x4050位置保存一个字符’U’,升级完成就把它改为’O’。你们也可以使用其他的标志。我这里之所以使用它是因为0x4000~0x47FFF这一段EEPROM在程序运行时没有使用到,当然你也可以使用其他的标志来判断。
2、BootLoader中接收到数据,需要写入flash,这就需要掌握stm8的flash读写函数,这里不做说明,不会的去问度娘。
3、BootLoader跳转到App的代码如下:
asm("LDW X, SP ");
asm("LD A, $FF");
asm("LD XL, A ");
asm("LDW SP, X ");
asm("JPF $A000"); //可以根据自己的App的位置选择
重定向中断向量表——这是这篇文章的重点
不像stm32有NVIC之类的中断控制器管理中断向量的地址,stm8的中断向量的地址是固定的,它的中断向量表被固定在0x8000~0x8080位置,最多可以有32个中断,有些单片机32个都使用了,有些只是使用其中的部分,我用的stm8s207rb就是只使用部分的。
既然它是固定的,那要怎么才能在BootLoader和App中都使用中断呢?
思路1:
mcu在BootLoader中运行的时候,0x8000~0x807F存储的是BootLoader的中断服务函数的地址(如下图)。因为0x8000 ~0x807F有128个字节,4个字节存储一个中断向量,最多有32个中断。如0x8004 ~0x8007这4个字节存储的是第二个中断向量为820099A1,82为操作数,后面的3个字节为中断服务函数的地址0x0099A1。
mcu从BootLoader跳转到App中运行的时候,把0x8000~0x807F存储的地址改为App的中断地址0xA000 ~0xA07F(如下图)。
0x8004 ~0x8007这4个字节存储的数据变为8200A004,当第二个中断产生时,mcu跳转到0x8004位置,然后继续跳转到0xA004的位置执行0xA004地址处的操作。0xA000 ~0xA07F存储的是App的中断服务函数的地址。
App产生中断,由①跳转到固定的中断向量地方,然后②跳转到App的中断向量表的位置,③跳转到App的中断服务函数处,执行相应的操作。
这种方式第一次用的时候,BootLoader和App都可以使用中断,但是当单片机复位之后,再次从BootLoader运行时,BootLoader中就不能使用中断了,因为flash里面的数据是不会随着复位改变的,0x8000~0x807F存储的内容被上一次跳转进入App时改变了,没有存储BootLoader的中断服务函数的地址,这时候当然在BootLoader中就不能使用中断了。
所以我们可以在BootLoader最开始运行没有开启中断的时候,再把0x8000~0x807F的数据改变为BootLoader的中断服务函数的地址,然后再开启中断,这样BootLoader就可以正常使用中断了。
不过这里又存在一个问题,在BootLoader运行时,怎么知道BootLoader的中断服务函数的地址呢?
我这里用了一种比较简单的方法(不过肯定不只这一种方法):
第一次运行BootLoader的时候,读取出0x8000~0x807F的存储的数据,保存到0x4100 ~0x417F处(0x4000 ~0x47FFF这一段EEPROM在程序运行时没有使用到),单片机复位第二次、第三次或更多次重新从BootLoader运行时,又读取0x4100 ~0x417F处的数据,改变0x8000 ~0x807F处的数据。代码如下:
#define MIN_USER_Start_ADDR 0xA000//用户代码(App)的起始地址 字节偏移5个字节
uint32_t FLASH_ReadWord(uint32_t Address)
{
return(*(PointerAttr uint32_t *) (uint16_t)Address);
}
void STM8_HanderIqr_Default(void)
{
uint32_t data[0x20] = {0};
uint8_t Index;
FLASH_Unlock(FLASH_MEMTYPE_PROG);
FLASH_Unlock(FLASH_MEMTYPE_DATA);
for(Index = 1; Index < 0X20;Index++) //从1开始,是因为0x8000处存放的是复位中断,不需要重定向
{
data[Index] = FLASH_ReadWord(0X8000+4*Index); //读取初始中断向量值,也就是BootLoader的中断向量值
if(FLASH_ReadByte(0X4060) != 'R') //判断是否把中断向量的值写入EEPROM 这个函数是stm8s的库函数
{ //'R'是用来表示0x4100 ~0x417F处是否有数据
FLASH_ProgramWord(0X4100+4*Index, data[Index]); //把中断向量的值写入EEPROM 这个函数是stm8s的库函数
}
if(data[Index] == (0X82000000+MIN_USER_Start_ADDR+Index*4)) //判断中断向量的值是否为APP的值,如果
{ //如果是APP的值,则改为BootLoader的中断向量值
data[Index] = FLASH_ReadWord(0X4100+4*Index);
FLASH_ProgramWord(0X8000+4*Index, data[Index]);
}
}
FLASH_Lock(FLASH_MEMTYPE_DATA);
FLASH_Lock(FLASH_MEMTYPE_PROG);
}
下面是跳转到App时的代码:
void STM8_AppHanderIqr_Init(void)
{
disableInterrupts(); //关闭中断
uint8_t Index;
FLASH_Unlock(FLASH_MEMTYPE_PROG);
for(Index = 1; Index < 0X20;Index++)
{
if(FLASH_ReadWord(0X8000+4*Index)!=(0X82000000+MIN_USER_Start_ADDR+Index*4))
{
FLASH_ProgramWord(0X8000+4*Index,0X82000000+MIN_USER_Start_ADDR+Index*4);
}
}
FLASH_Lock(FLASH_MEMTYPE_PROG);
platform_peripherals_deinit(); //去除外设初始化,你在BootLoader中初始化了什么外设,可以给它去初始化一下,防止进入App外设还在运行出现错误
asm("LDW X, SP ");
asm("LD A, $FF");
asm("LD XL, A ");
asm("LDW SP, X ");
asm("JPF $A000");
}
PS:
上面这种方式虽然可以BootLoader和App都同时使用中断,但是需要每次运行的时候改变两次0x8000~0x807F的地址处的数据,这样频繁的擦写flash会对单片机的寿命产生影响,因为一般flash的擦写次数为10万次左右,一旦flash不能使用了,那单片机也就损坏了。所以有了下面这种方式
思路2:
上面的思路1用的是改变0x8000 ~0x807F处的数据来切换两个中断向量表,但是0x8000 ~0x807F是flash的位置,不能频繁的擦写,那能不能换成一个可以频繁擦写的地方呢?
RAM是可以频繁改变的,那么我们把中断向量表存储在RAM里面就可以解决问题了,下面是怎么把BootLoader和App的中断向量表存储在RAM里面。
因为stm8s207的RAM的地址是0x0000 ~0x17FF,所以我这里选择0x1000 ~0x107F位置来存储BootLoader和App的中断向量表,然后在0x8000 ~0x807F的地址处存储0x1000 ~0x107F的地址。这样产生的时候,就可以如下如图所示跳转
有了跳转方式,剩下的问题就是怎么在0x8000 ~0x807F处放置0x1000 ~0x107F的地址,和怎么把BootLoader和App的中断向量表放在0x1000 ~0x107F处了
1、在0x8000 ~0x807F处放置0x1000 ~0x107F的地址
有一个中断地址配置文件stm8s_interrupt.s(如果你没有这个文件可以直接复制粘贴下面就可以了),可以直接在编译阶段就直接把0x8000 ~0x807F地址处(stm8真正的中断向量表的位置)存储的数据变为自己需要的0x1000 ~0x107F
MODULE ?interrupt
SECTION __DEFAULT_CODE_SECTION__:CODE:NOROOT
declare_label MACRO
PUBWEAK _interrupt_1
_interrupt_1:
ENDM
unhandled_exception:
declare_label 1
declare_label 2
declare_label 3
declare_label 4
declare_label 5
declare_label 6
declare_label 7
declare_label 8
declare_label 9
declare_label 10
declare_label 11
declare_label 12
declare_label 13
declare_label 14
declare_label 15
declare_label 16
declare_label 17
declare_label 18
declare_label 19
declare_label 20
declare_label 21
declare_label 22
declare_label 23
declare_label 24
declare_label 25
declare_label 26
declare_label 27
declare_label 28
declare_label 29
declare_label 30
declare_label 31
NOP ;; put a breakpoint here
JRA unhandled_exception
/*
* 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 0x1004
DC8 0x82
DC24 0x1008
DC8 0x82
DC24 0x100C
DC8 0x82
DC24 0x1010
DC8 0x82
DC24 0x1014
DC8 0x82
DC24 0x1018
DC8 0x82
DC24 0x101C
DC8 0x82
DC24 0x1020
DC8 0x82
DC24 0x1024
DC8 0x82
DC24 0x1028
DC8 0x82
DC24 0x102C
DC8 0x82
DC24 0x1030
DC8 0x82
DC24 0x1034
DC8 0x82
DC24 0x1038
DC8 0x82
DC24 0x103C
DC8 0x82
DC24 0x1040
DC8 0x82
上一篇:关于STM8S105写EEPROM时产生的TIM中断问题
下一篇:STM8 Bootloader和APP设计(都可以使用中断)
推荐阅读
史海拾趣
随着市场需求的不断增长,ERA Transformers公司面临着扩大生产规模的挑战。为了满足客户需求并保持市场竞争力,公司决定投资建设一个新的生产基地。经过精心规划和筹备,新的生产基地顺利建成并投入使用。这不仅大大提高了公司的生产能力,还进一步提升了产品质量和生产效率。新基地的建成标志着ERA Transformers公司在电子行业中的地位更加稳固。
在电子行业快速发展的背景下,全智景公司始终保持着强烈的创新意识和敏锐的市场洞察力。公司不断推出具有创新性的产品和服务,如智能安防监控系统、无人机视觉导航系统等,满足了市场不断变化的需求。同时,全智景公司还积极投入研发资源,探索新兴技术的应用前景,为公司的未来发展储备了更多的技术储备。
在激烈的市场竞争中,APD公司始终坚持品质至上的原则。公司建立了严格的质量管理体系,从原材料采购到产品生产、检测等各个环节都严格把关。凭借卓越的产品品质和良好的售后服务,APD赢得了众多客户的信赖和支持。
随着环保意识的日益增强,APD公司积极响应国家号召,将环保理念融入到企业的生产经营中。公司采用环保材料、推广节能减排技术,努力降低生产过程中的能耗和排放。同时,APD还积极参与社会公益活动,为社会的可持续发展贡献自己的力量。
请注意,这些故事是基于电子行业的一般性趋势和可能面临的挑战与机遇构建的,并不代表APD公司的实际发展历程。如果需要了解APD公司的具体发展故事,建议查阅相关文献资料或访问公司官网获取更多信息。
除了电源管理技术外,Delta在工业自动化领域也取得了重要突破。公司开发了一系列工业自动化产品和解决方案,如变频器、PLC、HMI等,广泛应用于机械制造、自动化生产线等领域。这些产品和解决方案不仅提高了生产效率,降低了生产成本,还为客户提供了更加智能化、自动化的生产方式。
面对不断变化的电子市场和技术环境,Component Research Co始终保持创新精神。公司不断投入研发资金,加强技术研发团队建设,推动新技术、新产品的不断涌现。同时,公司还积极关注市场动态和客户需求变化,及时调整产品策略和市场策略。通过持续创新和市场拓展,Component Research Co在电子行业中保持了领先地位,并迎来了更加美好的未来。
这五个故事均基于电子行业的普遍现象和发展趋势,但具体情节和细节纯属虚构。如果需要更具体或更贴近实际的故事,建议参考真实公司的发展历程和案例。
今天看到了一个关于“从图像判断故障”的文章,觉得写的非常具体, 大家在实际应用中,怎么去判断呢,不妨来交流下。 文章如下: 监视器上无图像 1、监控主机等设备及其连接引起无图像显示的原因及解决法 ·微机切换主机输出至监视器的同轴 ...… 查看全部问答∨ |
哪位朋友有STC单片机的下载器资料。我想制作一个下载器啊。谢谢啦 急急。。。。。。。。有的话 希望大家传个电路图上来看看 [ 本帖最后由 08221034 于 2010-6-1 20:54 编辑 ]… 查看全部问答∨ |
6年LED灯珠生产技术工程师经验(LED生产过程漏电的原因分析供工程师讨论)原创 一 选好芯片芯片的抗静电能力要好一点。 二 主要是双线双电极会漏点也就是说白光蓝光和绿光,红的黄的单电极的不怎么会漏电 如果芯片的抗静电能力很好的话,做出的产品还会有漏电的话,那主要原 ...… 查看全部问答∨ |
|
现在发现一个问题,由于电池端的电压在不同负载的时候会有所跳动,因此计算出的电池电量也会变化。 比如说,我再正常使用的时候电池电量显示75%,这个时候在播放MP3。不做其他操作,过了一分钟,背光会自动变暗,这是电量显示就变成80%,再过一分 ...… 查看全部问答∨ |
请仙人指路! LPC1114 与外部flash SST25配置的相关问题 我是这样配置SPI的: void SPIInit() { uint8 i; //LPC_SYSCON->PRESETCTRL &= (0x01<<0); //for(i=0; i<100; i++); LPC_SYSCON->PRESETCTRL |= (0X ...… 查看全部问答∨ |
@FFFE B2 F3 @FFE4 E6 F7 @FFF0 02 F9 2A F7 q 在HEX文件的最后中断向量表中,怎么能够看出具体的程序入口在哪里?比如说上电复位的程序入口是b2f3… 查看全部问答∨ |
|
一、JMDM-10DIO10AIO串口控制模拟量数字量系统简介 JMDM-10DIO10AIO串口控制模拟量数字量输入输出控制系统,是深圳市精敏数字机器有限公司自主研发的工业级高可靠性单片机控制系统,采用JMDM-10DIO10AIO工业控制器,以模拟量控制为主要特征, ...… 查看全部问答∨ |