打印
[其他产品]

异常处理一例 - Bootloader开机自动升级

[复制链接]
1029|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
aoyi|  楼主 | 2023-7-19 16:58 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1.Misfunctional behavior
Bootloader开机后,会尝试与远端的自动程序升级终端握手。目前这个过程是这样的:接收到首帧后,首帧反馈信息不符合YModem协议:



Out之后的In不对,检查一下此时SecureCrt是否在等待回应:



yes, It still waiting...

2.分析
2.1 检查代码的可能位置
1.1.64已经可以看到收到发出了"C" 。这个"C",导致上位机发出 YModem首帧。相关代码:

void TryToLoadApp(void)
{
//等待時間
#define WAIT_TIME 1000
#define WAIT_SPAN 200
    int16_t RetryCnt = WAIT_TIME/WAIT_SPAN;
    if((EE_Key_1 == MAGIC_BYTE1) && (EE_Key_2 == MAGIC_BYTE2))
    {
        RetryCnt = 30000/WAIT_SPAN;
        //不清除,因爲這種狀態會被自然清理掉。
    }
    while(EUSART1_is_rx_ready()) getch(); //讀完緩衝區裏的所有遺留字符。

    do
    {
        while(!EUSART1_is_rx_ready())
        {
            putch('C');
            HAL_Delay(WAIT_SPAN);
            if((RetryCnt--)<=0) break;
        }

        if(!EUSART1_is_rx_ready())
        {
            if(IsAppExisted()) JumpToRealApp(); //default jump
        }
    }while(!EUSART1_is_rx_ready());
}

这个函数已经退出。明白了,在putch('c')之后,那个WAIT_SPAN的长延时不妥。115200的波特率,10/115200的延时,对方的数据就会来。这是86us。所以,这里的等待检测时间需要达到50us级。

修改=》内存空间超限。。。

2.2 为什么0x600以内的地址空间,编译工具无法使用?
post quesiton at Microchip's forum...

Microchip Forum Question about XC8-CC's
https://forum.microchip.com/s/topic/a5C3l000000Bpr8EAC/t391265

此问题已经有答案。我现在又多出来1.5KBytes左右的ROM空间可用。

2.3 将等待时间缩短至50us
现在15帧似乎回送成功了。但是还是多追加了几个"C"、"C"



2.4 根本机制发现,是代码速度跟不上485
最终开机代码改为如下模式:

void TryToLoadApp(void)
{
//等待時間
#define WAIT_TIME 1000 /*單位ms*/
#define WAIT_SPAN 50   /*單位us, DO NOT CHANGE!!! =115200BPS*/
#define OUTPUT_SPAN   (200*1000/WAIT_SPAN) /*單位WAIT_SPAN = 50us*/
    uint32_t RetryCnt = WAIT_TIME/WAIT_SPAN*1000;
    if((EE_Key_1 == MAGIC_BYTE1) && (EE_Key_2 == MAGIC_BYTE2))
    {
        RetryCnt <<=5;
        //不清除,因爲這種狀態會被自然清理掉。
    }
    while(EUSART1_is_rx_ready()) getch(); //讀完緩衝區裏的所有遺留字符。

    do
    {
        while(!EUSART1_is_rx_ready())
        {
            if((RetryCnt--)<=0) break;
            if((RetryCnt&0x7ff)==0) putch('C'); //about 200ms delay。。。
            HAL_usDelay(WAIT_SPAN);
        }

        if(!EUSART1_is_rx_ready())
        {
            if(IsAppExisted()) JumpToRealApp(); //default jump
        }
    }while(!EUSART1_is_rx_ready());

    uint8_t ymodemHeader[7] = {0x01, 0x00, 0xff, 'g', 'p', 'b', 't'};
    uint8_t idx=0;
    uint8_t dumb;
    uint16_t cnts=0;
    //嘗試讀取ymodem協議字符串
    if(EUSART1_is_rx_ready())
    {
        uint8_t nullLoop=0;
        while(1)
        {
            if(EUSART1_is_rx_ready())
            {
                dumb = getch();
                if(idx<7)
                {
                    if(ymodemHeader[idx++]!=dumb) idx|=0xf0;
                }
                cnts++;
            }
            else
            {
                HAL_usDelay(50);
                if(++nullLoop>100) break;
            }
        }
    }
    if(idx==0x07) EE_DUMB = ACK;
    else if(cnts>=128) EE_DUMB = NAK;
    else EE_DUMB = 0;
    xlog("idx=%d, cnts=%d, DUMB=%c", idx, cnts, EE_DUMB);
}

3.结论
为了解析人手工输入的命令并能够在开机时;并能够自动进入YModem接收模式,之前对这些特征字符串是这样解析的:
流式命令析取工具
https://mp.csdn.net/mp_blog/creation/editor/131644811

在嵌入式环境中,你始终要对时间要警醒——单片机可能无法在指定时间内完成你所设定的动作。那个命令析取工具,应付人手输入,应该可以,但是应付115200bps的485数字流,来不及。
————————————————
版权声明:本文为CSDN博主「子正」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/twicave/article/details/131676650

使用特权

评论回复
沙发
tpgf| | 2024-4-2 12:12 | 只看该作者
难道每次开机都要进行自动升级吗

使用特权

评论回复
板凳
八层楼| | 2024-4-2 12:46 | 只看该作者
是否需要自动判定是否需要进行升级呢

使用特权

评论回复
地板
观海| | 2024-4-2 13:18 | 只看该作者
如果升级失败了  之前的程序还能正常运行吗

使用特权

评论回复
5
guanjiaer| | 2024-4-2 13:50 | 只看该作者
在升级的过程中 新写入的程序和老程序是不是分开存储的呢

使用特权

评论回复
6
keaibukelian| | 2024-4-2 14:26 | 只看该作者
如果握手失败将会如何进行下一步呢

使用特权

评论回复
7
heimaojingzhang| | 2024-4-2 23:50 | 只看该作者
握手成功之后,远端会告诉当前客户端是否需要升级吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

101

主题

3307

帖子

3

粉丝