动手写一个STM8的轻量级bootloader

发布者:平安心境最新更新时间:2020-01-07 来源: eefocus关键字:STM8  轻量级  bootloader 手机看文章 扫描二维码
随时随地手机看文章

STM8凭借其低廉的成本、超高的性价比获得了许多公司的青睐。而在产品中由于方便、安全等需求,往往要使用到IAP下载的方式对已经拿到产品客户进行软件升级(如果产品在批量生产后发现你的程序有问题,而不能IAP更新,那售后维护成本就高了)。 


而STM8S003等只有8K Flash的型号是不自带Bootloader的,且ST官方的Bootloader足足会占领4KB Flash空间,且还要考虑固件的保密性等因素,所以编写一个自己的轻量级的Bootloader尤为重要。


下面向大家分享一下本人在一个项目中写的一个Bootloader,最少只需占用0.5KB Flash空间!


【串口收发】

对于单片机而言,Bootloader最重要的功能就是把从串口发送过来的程序数据保存到MCU 的Flash上(即IAP下载),并跳转到所下载程序的起始地址并运行。所以串口功能必不可少。下面是我们用到的关于串口收发的函数(头文件添加stm8s.h,直接操作寄存器以节省Flash空间),MCU型号为STM8S003。


void UART1_SendByte(u8 data) //串口发一个字节

    UART1->DR=data;

    while (!(UART1->SR & 0x80));//等待发送完成

}

void UART_Init(void) //串口初始化函数

{     

    UART1->CR2 = 0;                       

    UART1->CR3 = 0;// b5,b4 = 00,1个停止位

    UART1->BRR2=0x00;

    UART1->BRR1=0x1a;

    //BRR2和BRR1设置串口波特率,这里设置的在2MHz默频下是4800的波特率

    UART1->CR2 = 0x2C; // b3 = 1,允许发送

    UART1->CR1 |= (0<<5);

}

void UART1_SendStr(u8* data)//发送字符串函数

{

    while (*data)

        UART1_SendByte(*data++);

}

u8 UART1_RcvB(void)//串口接收函数,以扫描(等待)方式

{

     while(!(UART1->SR & (u8)UART1_FLAG_RXNE));//等待接收到数据

         return ((uint8_t)UART1->DR);

}


有小伙伴就会问了,串口接收为何不用中断?因为STM8没有STM32那样的向量地址的偏移,因此你的APP(正式的程序)和Bootloader中只能有一个使用中断。当然也有同时都可以用中断的方法,但是本人愚见,觉得实现基本的下载升级功能用不着中断,添加中断还会增加Bootloader的代码量不是?不过如果真的需要,CSDN论坛有一篇《集合帖:STM8之支持中断方式的IAP技术实现》的帖子大家可以搜来看看。


【Flash的写入】

查阅Datasheet可以知道STM8S003 FLASH的起始地址是0x8000,到0x9fff结束共8KB,每64个字节在一个Block(块)。而我这里的Bootloader放在开头,即从0x8000开始,这样上电默认就进入bootloader。那么APP程序放在哪里呢,有空的地方就可以放~,比如你想把bootloader的存放空间预留1KB,那么你的APP就从0x8400开始存放,0x8400-0x9fff共7KB空间可供你编程。如果你IAP功能比较精简,没有数据加密、校验什么的,0.5KB就够,那么甚至可以把APP起始地址提到0x8200。 

下面是个写一个块的Flash的函数,因为写Flash时程序不能在Flash中执行,故函数在RAM中执行。


//写Flash函数,addr地址必须是每个Block的开头(0x40的倍数)

IN_RAM(void FLASH_ProgBlock(uint8_t *addr, uint8_t *Buffer))

{

    u8 i;    


    FLASH->NCR2 &= (uint8_t)(~FLASH_NCR2_NPRG);

    FLASH->CR2 |= FLASH_CR2_PRG;

    for (i = 0; i < 64; i++)//一个块共写64个字节

    {

        *((PointerAttr uint8_t*) (uint16_t)addr + i) = ((uint8_t)(Buffer[i]));

    }

}


在写Flash之前别忘了对Flash解锁


#define FLASH_RASS_KEY1 ((uint8_t)0x56)

#define FLASH_RASS_KEY2 ((uint8_t)0xAE)//宏定义添加


    FLASH->PUKR = FLASH_RASS_KEY1;//代码添加,解锁Flash程序区

    FLASH->PUKR = FLASH_RASS_KEY2;


最常见的IAP方式是在刚上电时等待一定时间检测有没有串口命令,有就进入下载模式,没有就跳到APP,以下是最基本的IAP实现:


int main(void)

{           

    u16 j = 0;

    u8 ch, high, low;

    u8 buf[64]; //接收缓冲区


    asm("sim"); //关闭总中断使能

    UART_Init();

    UART1_SendStr("STARTrn");//发送开机提示


    while (j < 50000)//等待循环这么长时间

    {

        if(UART1->SR & (u8)0x20)    //如果串口收到数据

        {

            ch = (uint8_t)UART1->DR;

            if(ch == 0xa5) break; //收到了0xa5,则进入下载模式

        }

        j++;

    }


    if (j == 50000)//循环是超时退出的

    {

        asm("JPF $8400");//跳到0x8400这个地址去执行APP。

    }      

    //unlock flash,解锁flash

    FLASH->PUKR = FLASH_RASS_KEY1;

    FLASH->PUKR = FLASH_RASS_KEY2;

    UART1_SendStr("prorn");

//发送开始编程提示

    while(1)

    {

        high = UART1_RcvB();

        low = UART1_RcvB();

        addr = (u8 *)((high << 8) | low);//先接收到本次数据16位的起始地址

        if (addr == 0)//如果收到的是0,就是下载结束了

        {

            UART1_SendStr("OK!rn");//发送下载完成提示给上位机

            FLASH->IAPSR &= FLASH_MEMTYPE_PROG; //锁住flash

            asm("JPF $8400");//跳转到0x8400执行刚下载完的APP

        }

        for (i = 0; i < 64; i++)

            buf[i] = UART1_RcvB();//接收64字节数据

        FLASH_ProgBlock(addr, buf);//将收到的数据写到相应地址的Flash

    }

}


上述程序使用IAR编译,仅用不到0.5KBFlash就实现了最基本的IAP功能,当然,下载程序需要使用协议与之匹配的上位机。


【中断向量重映射】

使用上述bootloader程序下载app程序后你会发现中断无法使用,因为STM8的默认中断向量地址是在0x8000-0x8080,stm8编译出的二进制文件会把向量表放在前0x80个字节。即如果在app中使用了中断,那么程序就会跳回bootloader程序中去了,解决这个问题的方是进行中断向量重映射。


在bootloader程序main.c文件的函数之外添加以下代码:


__root const long reintvec[]@".intvec"= 

{

0x82008080,0x82008404,0x82008408,0x8200840c, 

0x82008410,0x82008414,0x82008418,0x8200841c, 

0x82008420,0x82008424,0x82008428,0x8200842c, 

0x82008430,0x82008434,0x82008438,0x8200843c, 

0x82008440,0x82008444,0x82008448,0x8200844c, 

0x82008450,0x82008454,0x82008458,0x8200845c, 

0x82008460,0x82008464,0x82008468,0x8200846c, 

0x82008470,0x82008474,0x82008478,0x8200847c, 

};//当应用程序地址不是0x8400时则要相应改掉除第一个0x82008080以外的数值 


便完成了中断向量的重映射,这里映射到了0x8400-0x8480,即APP程序的中断向量表存放区。 

但是这时候你的IAR编译器会报错: 

这里写图片描述 

中断向量空间不够?当然,因为加入了重定向数组。


接下来进入IAR设置下,Linker的Config下,可以看到使用了inkstm8s003f3.icf 这个配置文件: 

这里写图片描述

我们用文本编辑器打开: 

这里写图片描述

这不就是报错的INTVEC size吗,把它从0x80改成0x100,并保存,再回IAR编译就完美通过了!


【APP程序的设置】

现在有bootloader了,APP存放的地址改变了,那么APP中一些关于地址的量也需要跟着改变,换句话说就是编译器编译出的地址也要变。所以你需要将上面改INTVEC size大小的那张图改成下面这样再对APP进行编译: 

这里写图片描述 

嗯,所有的0x8000都改成了0x8400(APP程序的起始地址),中断向量表占用空间为0x80。在这样设置、保存编译后,APP通过bootloader下载进去就可以用了。


【数据的校验】

前面我们的bootloader程序是收到字节便马上写入Flash,写完后直接运行,可是万一出现串口多收/漏收/错收或者是Flash写入失败的情况怎么办?那就…


void get_flash_verify(u8 *add)//发送校验码的函数

{

  u16 i;

  u8 ch;

  u8 verify = 0;


  for (i = 0; i < 64; i++)

  {     

      ch = *((PointerAttr uint8_t*) (uint16_t)add + i);//读取flash并累加

      verify += ch;

  }

  UART1_SendByte(verify);

}


此函数读取了add地址开始的64字节Flash的值,并将他们累加,相加完的和取低8位得到一个校验码,并将该码通过串口发送出去。此函数在单片机每次写完一个块的Flash后调用,上位机将这个码与自己的数据算出的值进行比对便实现了校验,如果校验不正确,上位机便可重新发送命令写该快。

关键字:STM8  轻量级  bootloader 引用地址:动手写一个STM8的轻量级bootloader

上一篇:stm8s 实践课程之IAP设计编码(bootloader实现)
下一篇:Bootloader升级方式一————擦、写flash在RAM中运行

推荐阅读最新更新时间:2024-11-12 09:18

关于stm8不能在线 debug的问题总结
问题描述: 1.之前自己建立一个stm8的工程A,使用stm8的库函数,可以在线单步调试。 2.后面又多了一个工程B,忘记了是新建的还是从工程A拷贝过来的了,反正一在线调试就会程序跑跑飞,也不是一开始就跑非的,前面几步还是可以正常走,走着走着就会跑飞了。 3.工程A和工程B的代码基本功能一样。 4.我的怀疑有两点,一个是工程配置的问题,还有一点就是代码不一致,引出的在线debug跑飞的情况。 问题解决: 1.我新建一个工程C,使用可以在线debug的A工程的代码 ,结果是可以在线单步调试; 2.于是我对比着工程C和工程B的代码,一点一点的合并(此过程相当痛苦。一个下午加一个晚上的时间)。终于水落石出了。
[单片机]
STM8单片机PWM应用
PD3复用功能是TIM2_CC2,正好可以用来测试PWM功能。本例程通过电位器调整PWM脉宽来调整接在PD3的LED1亮度。 #include void CLK_init(void) { CLK_CKDIVR = 0x08; // 16M内部RC经2分频后系统时钟为8M } void GPIO_init(void) { PD_DDR = 0x08; // 配置PD端口的方向寄存器PD3输出 PD_CR1 = 0x08; // 设置PD3为推挽输出 } void TIM2_init(void) { TIM2_CCMR2 = 0x70; // PWM模式 2 TIM2_CCER1 = 0x30; // CC2配置为输出 TIM2_
[单片机]
stm8 ADC模数转换
第一步:stm8 ADC简介 stm8的ADC1和ADC2是10位逐次比较型模拟数字转换器。A/D转换的各个通道可以执行单次和连续的转换模式。 stm8S103k5引脚图如下: stm8 可以看见它只有16/15/14/13引脚是ADC的引脚,分别是AIN0、AIN1、AIN2、AIN3。都是ADC1。 第二步:ADC相关寄存器说明 基本还是和前几节一样都是直接截图的数据手册。 第三步:具体实现 实现功能:PB0脚AIN0,当接3.3V电压时点亮LED,接地时LED熄灭,没有可调电阻和可调电源,就这么操作了。 #include IOSTM8S105K4.h #def
[单片机]
意法半导体新STM8和STM32手机应用软件优化微控制器选型
中国,2021年8月11日——为帮助开发者轻松快捷地找到适合项目的微控制器,意法半导体在主要应用商店和公司官网st.com发布了先进的手机应用。 STM8 Finder和STM32 Finder替代以前的ST MCU Finder手机应用,利用最新的应用软件设计技术,为用户提供稳健和便利的使用体验。新功能包括强大的搜索筛选器,让用户更细致地描述所需的外围设备。自适应图形界面能够根据智能手机或平板电脑的触屏以及屏幕方向自动优化显示效果,内容缓存支持离线搜索。此外,新的增量数据库管理功能在数据更新时可大限度地减少数据使用量和等待时间。 这两款应用软件可以查看STM8 8位微控制器、STM32 32位Arm®Cortex®
[嵌入式]
意法半导体新<font color='red'>STM8</font>和STM32手机应用软件优化微控制器选型
STM8 8位基本型定时器 TIM4
STM8S 的定时器 TIM4 由一个带可编程预分频器的 8 位可自动重载的向上计数器组成。 TIM4 的时钟源为系统主时钟 f MASTER ,因为 f MASTER 来源于 HSE、HSI、LSI,所以也相当于 TIM4 的时钟源可以为 HSE、HSI、LSI。 f MASTER 直接连接到 CK_PSC 时钟,然后经过预分频器分频,3 位可编程预分频器可以提供 1、2、4、8、16、32、64、128 的分频,生成 CK_CNT 时钟,以驱动向上计数器进行计数。计数时钟的频率为: fCK_CNT =f CK_PSC / 2(PSC ) 向上计数时,计数器从 0 开始计数,当计数值(TIM4_CNTR 寄存器的值
[单片机]
<font color='red'>STM8</font> 8位基本型定时器 TIM4
基于STM8的LCD界面点阵字库显示
本方案主控采用STM8S207C8T6,1.7寸128*64LCD显示屏,LCD驱动芯片采用UC1701(可兼容ST7565),字库显示采用高通GT20L16S1Y字库芯片, 以实现LCD界面上的显示。 以下分别是STM8S207C8T6,UC1701和GT20L16S1Y在原理图中的模块电路。 原理图是依据datasheet中的阐述所绘制,其中主控电路是使用了stm8s207c8t6芯片绘制的最小系统,显示屏部分是根据设置BM0和BM1来选择总线模式绘制的电路。这里我使用了SPI总线模式。而字库芯片本身就是SPI总线模式通信,直接根据规格书的电路例子使用即可。完成了电路部分,知道了总线模式,再结合数据手册就可以
[单片机]
基于<font color='red'>STM8</font>的LCD界面点阵字库显示
STM8单片机——按键检测电路设计
硬件环境采用STM8SF103,电压为3.3V。电路需要注意的是STM8SF103这系列的IO作为输入口时只能是上拉输入和悬浮输入,虽然是弱上拉,在VCC为3.3V电压时,仍然能够被拉升至3.0V左右。 所以按键检测电路IO口一端需要接地,而不是外接上拉。悬浮方式下IO仍然会有0.89V左右电压,读取对应的IO寄存器IDR,仍然处于逻辑高电平状态。 软件代码相对很简单,只需要将IO口设置成上拉输入即可。采用轮询代码如下: //初始化只需要设置IO口模式即可。 GPIO_Init(KEY2_PORT,KEY2_PIN,GPIO_MODE_IN_PU_NO_IT);//上拉输入,不产生中断 //按键检测部分 /* #def
[单片机]
<font color='red'>STM8</font>单片机——按键检测电路设计
STM8仿真调试快速入门
● ST Visual Develop的安装   到 ST 官方网站: http://www.st.com/stonline/products/support/micro/files/sttoolset.exe 下载安装。 ● ST Visual Develop之设置软件与建立、打开相关调试文件   ----使用Cosmic C语言,软件仿真   要用STVD的IDE下使用COSMIC C语言开发的话,首先要在STVD中对COSMIC STM8编译器进行设置。 如下图所示,运行ST Visual Develop 集成开发环境,选择菜单 Tools - Options ,在出现的对话框中选择 Toolset 选项卡。在 Tools
[单片机]
<font color='red'>STM8</font>仿真调试快速入门
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved