stm8s_IAP_xmode串口升级

2019-07-18 20:24发布

本帖最后由 电脑小白 于 2018-7-18 15:56 编辑

重磅出击,全球独此一份代码。原子大大,求票票,求酷贴,求置顶。
PS: 此IAP是用超级终端工具通过串口发送bin文件进行升级操作的!
附件中有app的demo工程和bootloader工程源码。

新添加了:工程地址设置说明(设置地址很重要,要不然没法从bootloader跳到app里去运行)。见新的附件。
Copyright 2016-2020 Alex.Fang  All rights reserved.

Header:   stm8s105c6t6 IAP code
File Name: main.c
Author: Alex.Fang (www.openedv.com username=电脑小白)
Date: 2016-07-22


免责声明:
此代码你可以用来学习和交流。不得商用!应用此程序酿成事故由你自己承担!
本人不负责维护和支持此代码!如有疑问和看不懂别来烦我! ^_^
openedv论坛好友可以随便下载和转给他人参阅学习。
版权遵循 = GPL

开发环境为IAR的代码和范例:见39楼另一大神贡献的补充帖子。

main.c 代码内容:
[mw_shl_code=c,true]


/* Includes ------------------------------------------------------------------*/

#include <string.h>
#include <stdio.h>
#include "stm8s.h"
#include "stm8s_clk.h"
#include "main.h"
//#include "stm8s_wwdg.h"
#include "delay.h"
#include "flash.h"
#include "stm8s_flash.h"

#include "config.h"
#include "IO_config.h"

#include "crc16.h"
#include "xmodem.h"

#include "stm8s_uart2.h"

#include "uart2.h"
//#include "stm8s_tim2.h"

//#include "wwdg.h"

//#define NGI()     _asm("sim");    /* 禁止全局中断 */
//#define EGI()     _asm("rim");    /* 使能全局中断 */
//#define WFI()     _asm("halt");   /*进入到低功耗模 WFI */


/* Private defines -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

//address for GO command
//TFunction GoAddress;



void STM8_CLK_Init(void)
{
                CLK_DeInit();//复位时钟寄存器
    CLK_HSICmd(ENABLE);//HSI = 16MHz
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //f_psc = 16MHz/1
               
                //CLK_ClockSecuritySystemEnable();//开启时钟安全系统
    //enableInterrupts();
}


void system_init(void)
{
        STM8_CLK_Init();
        FLASH_DeInit();
        Init_GPIO();
        Init_UART2();

}


void main(void)
{        
  //_asm("sim");//关全部中断
        
        disableInterrupts();
        system_init();
        //_asm("rim");//开全部中断
        enableInterrupts();
        
        
        uart2_data(" ",4);
        uart2_data("Bootloader Start... ",21);        
        uart2_data("Ver=20160722_1.0 ",18);
        disableInterrupts();
        

        //unlock_PROG();        
  //unlock_DATA();
        
        //Print("goto app... ");
        //goto_app();        
        //Print("Failed! ");
        //waiting_time_count=200;
  Xmoden_STate = IDLE;
        //RS232_Tran_Chr(NAK);
        disp_menu();
  while (1)
  {
                RS232_ISR();
                RS232_Rec_Xmodem();
               
  }//end while
  
}


[/mw_shl_code]


xmode.c 代码如下:
[mw_shl_code=c,true]

uchar RS232_Rec;
uchar RS232_Rec_old;
uchar RS232_Rec_flag=0;
//uchar RS232_Trn_flag=1;

enum TXmoden_STate Xmoden_STate = IDLE;

uchar Xmodem_Buffer[135]; /* 128 for XModem  + 3 head chars + 2 crc + nul */
//uchar Xmodem_Buffer_Ptr=0;
//uchar ChkSum=0;
//uchar PSer=1,PT=0;
//uchar xerror;
uint16_t waiting_time_count=HOLDTIME;
uint32_t App_address=0;


/*******************************************************************************
** 函数名称 : check
** 功能描述 : 校验,CRC为真则为CRC校验,否则为校验和
** 入口参数 : <crc>[in] 选择是CRC校验还是SUM校验
**                          <buf>[in] 校验的原始数据
**                          <sz>[in]  校验的数据长度
** 出口参数 : 无
** 返 回 值 : 校验无误返回TURE,反之返回FALSE
** 其他说明 : 无
*******************************************************************************/
static int check(int crc, const unsigned char *buf, int sz)
{
        if (crc){
                unsigned short crc = crc16_ccitt(buf, sz);
                unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
                if (crc == tcrc)
                        return TRUE;
        }
        else{
                int i;
                unsigned char cks = 0;
                for (i = sz; i != 0; i--){
                        cks += *(buf++);
                }
                if (cks == *buf)
                      return TRUE;
        }
        return FALSE;
}


//----------------------------------------------------------
void RS232_ISR(void)
{
        Receive(&RS232_Rec,100);
        
        //Transmit(RS232_Rec);
        
        RS232_Rec_flag = 1;
}

//----------------------------------------------------------
void RS232_Tran_Chr(uchar chr)
{
    Transmit(chr);
}

void disp_menu(void)
{
        Print(" ----------bootloader---------- ");
        Print("1.download ");
        Print("2.goto app ");
        Print("------------------------------ ");
        Print("Please choose (1 or 2): ");
        Print("Timeout = [     ");
}

void disp_1(void)
{
        Print(" Press = 1 ");
        Print("Choose file...     ");
}

void disp_2(void)
{
        Print(" Press = 2 ");
        Print("Goto app...");
        delay_ms(20);
        goto_app();        
        Print(" Failed! ");
        waiting_time_count=HOLDTIME;
        Xmoden_STate = IDLE;
        disp_menu();
}


void RS232_Rec_Xmodem(void)
{
        uint8_t packetno = 1;
        uint8_t bufsz;
        uint8_t crc = 1;//启用CRC校验
        uint16_t i=0;
        //uint16_t j=0;               
               
                if(Xmoden_STate == IDLE){
                        if(waiting_time_count!=0){
                                waiting_time_count--;
                                RS232_Tran_Chr(8);
                                RS232_Tran_Chr(8);
                                RS232_Tran_Chr(8);
                                RS232_Tran_Chr(8);
                                RS232_Tran_Chr(8);
                                //RS232_Tran_Chr('[');
                                RS232_Tran_Chr(waiting_time_count/100%10+'0');
                                RS232_Tran_Chr(waiting_time_count/10%10+'0');
                                RS232_Tran_Chr(waiting_time_count%10+'0');
                                RS232_Tran_Chr(']');
                                RS232_Tran_Chr(' ');
                                
                                delay_ms(100);
                                
                        }
                        else {
                                
                                Print(" Timeout,goto_app! ");
                                delay_ms(20);
                                goto_app();        
                                Print(" Failed!");
                                waiting_time_count=HOLDTIME;
                                disp_menu();
                        }
                        if(RS232_Rec_flag)
                        {
                                if(RS232_Rec_old!=RS232_Rec){
                                        RS232_Rec_old=RS232_Rec;
                                        waiting_time_count=HOLDTIME;        
                                        if(RS232_Rec == 13){//回车
                                                disp_menu();
                                        }
                                        else if(RS232_Rec == '1'){
                                                disp_1();
                                                waiting_time_count=50;
                                                Xmoden_STate = WSTART;
                                                //RS232_Tran_Chr(NAK);
                                        }
                                        else if(RS232_Rec == '2'){
                                                disp_2();
                                        }
                                }
                          RS232_Rec_flag=0;        
                        }
                        return;
                }
               
    if(RS232_Rec_flag)
    {
                                RS232_Rec_flag=0;
                                
                                if((RS232_Rec == 'B')||(RS232_Rec == 'b')) {
                                        RS232_Rec=0;
                                        waiting_time_count=HOLDTIME;
                                        Xmoden_STate = IDLE;         //进入"空闲"状态
                                        disp_menu();
                                }
              else if(RS232_Rec==SOH){ //开始传输文件
                                  bufsz=128;
                                        App_address=MAIN_USER_RESET_ADDR;
                while(RS232_Rec==SOH){//接收到有效数据帧头
                          Xmodem_Buffer[0]=RS232_Rec;
                          for(i=0;i<132;i++){//接收一帧数据
                                                                Receive(&Xmodem_Buffer[i+1],10000UL);
                                                                //Receive_while(&Xmodem_Buffer[i+1]);
                          }
                                                        
                          if((Xmodem_Buffer[1]==(uint8_t)~Xmodem_Buffer[2])&&(packetno==Xmodem_Buffer[1])//包序号无误
                            &&(check(crc, &Xmodem_Buffer[3], bufsz))){//CRC校验无误
                            packetno++;
                                                                //
                                                                firmware_option();
                                                                App_address+=128;
                                                                //delay_ms(1);
                                              Transmit(ACK);                                                               
                                                        }
                          else {//要求重发
                                  Transmit(NAK);
                          }
                                                        
                                                        //delay_ms(10);
                                                        //Transmit(ACK);        
                                                               
                                                        waiting_time_count=1000;
                                      do {
                                              Receive(&RS232_Rec,1000);//读取下一帧数据的帧头
                                      }while((RS232_Rec!=SOH)&&(waiting_time_count--));
                                                        if(waiting_time_count==0)break;
                                                
                }
                                       
                                        Transmit(ACK);
                                        Receive(&RS232_Rec,10000);
                                        if(RS232_Rec==EOT){//文件发送结束标志  
                                          Transmit(ACK);
                                        }
                                        eraser_option();
                                        waiting_time_count=HOLDTIME;
                                        Xmoden_STate = IDLE;         //进入"空闲"状态
                                        disp_menu();
                                       
                          }
        else {
                                        if(waiting_time_count!=0){
                                                waiting_time_count--;
                                                delay_ms(100);
                                        }
                                        else {
                                                waiting_time_count=20;
                                                Transmit('C');//crc
                                                //Transmit(NAK);//sum
                                        }
                                }
    }
}
//本函数的调用方式如下:
//  Xmoden_STate = WSTART;
//  RS232_Tran_Chr(NAK);
//  while(Xmoden_STate != IDLE) RS232_Rec_Xmodem();
/*
void firmware_option(void)
{
        uint16_t i=0;
        uint16_t j=0;
  uint8_t FULL_status=0;               
        //uint8_t * p_str=pstr;
        FLASH_Unlock(FLASH_MEMTYPE_PROG);
        for(i=0;i<125;i++){
                if((Xmodem_Buffer[i+3]==CTRLZ)&&(Xmodem_Buffer[i+4]==CTRLZ)&&(Xmodem_Buffer[i+5]==CTRLZ))
                {
                        FULL_status=1;
                        j=i;
                        break;
                }
        }
        if(FULL_status==0){
           //App_address
                for(i=0;i<128;i++){
                        FLASH_EraseByte(App_address+i);
                        //delay_ms(1);
                        FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);        
                }                 
        }
        else {
                //App_address
                for(i=0;i<j;i++){
                        FLASH_EraseByte(App_address+i);
                        //delay_ms(1);
                        FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);        
                }
        }
        FLASH_Lock(FLASH_MEMTYPE_PROG);
}
*/
void firmware_option(void)
{
        uint16_t i=0;        
        //uint8_t * p_str=pstr;
        FLASH_Unlock(FLASH_MEMTYPE_PROG);
        //App_address
        for(i=0;i<128;i++){
                FLASH_EraseByte(App_address+i);
                //delay_ms(1);
                FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);        
        }
        FLASH_Lock(FLASH_MEMTYPE_PROG);
}

void eraser_option(void)
{
        uint16_t i=0;        
        //uint8_t * p_str=pstr;
        FLASH_Unlock(FLASH_MEMTYPE_PROG);
        //App_address
        while(FLASH_ReadByte(App_address-1)==CTRLZ){
                FLASH_EraseByte(App_address-1);
    App_address--;
        }
        FLASH_Lock(FLASH_MEMTYPE_PROG);
}







[/mw_shl_code]



串口IAP升级操作步骤说明1、准备工作   先拷贝升级所需要的文件到桌面。   (Win xp有自带的超级终端,怎么打开xp自带的超级终端这里不做介绍)    Win7win10需要自行下载超级终端软件。2、打开超级终端,如下图 1 1 3、打开后弹出新建连接对话框,点击cancel(不新建,若没有提前配置好的需要新建)。   如果从没有打开过超级终端,那么将会提示输入国家代号和拨号,如下:   国家代号输入:020   拨号:123(随便填)   分号:456(随便填)   拨号模式选择:脉冲拨号。
2 2 4、打开配置好的配置文件:File->open 3 3
5、找到driver文件夹下ttys9600.ht文件  (有时候需要自己去建立超级终端配置,,如何配置这里不做介绍) 4 4
6、进入升级模式   输入enter回车键,会自动返回当前mcu的版本号入下图。(查询当前mcu版本)   连续输入5次空格键将进入升级模式。(注意要30秒内要按下数字键1   升级模式返回如下显示:   Bootloader start...   1---下载bin文件 2---运行下载好的bin固件 5 5
7、键盘在timeout不等于0的时间内输入“1”。Timeout=0时会自动退出升级模式的。   输入1以后会进入发送固件模式。如下图:   选择要发送的bin文件。Transfer-->Send file... 6 6
8、发送升级bin固件   Protocol要选择为xmode.注意不是1k-xmodeBrowse找到driver下的bin固件。   点击send开始传输。
7 7

9、找到文件如下:
8 8
10、加载文件后,并选择好xmode协议传输。    点击send后将开始传输固件到mcu 9 9
11、传输文件过程。   10 10    11 11    12 12
12、文件传输完毕。自动进行30秒倒计时。30内没有按键按下将自动退出升级模式,执行刚更新的固件。此时间段内如果按下数字键2,将立即退出升级模式并执行刚更新的固件。 13 13 13、按下了数字键2后,退出升级模式如下图:按下1会提示:press=1按下2会提示:press=2出现“start...”提示,就是升级完成已经在运行新的固件了。 14 14 14、至此升级操作已经完成。
日期:2016-07-22   版本:V1.0






友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。