Bootloader Design of PIC18 series MCU - 进阶篇

news2024/9/22 7:23:24

1.遭遇到问题

在:PIC18 Bootloader 设计基础 一文中,我们讨论了Bootloader与上层应用APP各自编译的方法。在ROM上的空间分配、以及跳转、中断的处理等内容。那篇文章包含了所有与PIC单片机Bootloader设计相关的技术问题。但是距离一个真正可用的Bootloader还有如下问题需要处理:

  • PBRQ01>升级文件如何从上位机传送至单片机
  • PBRQ02>升级文件本身是否需要处理为一个中间形式
  • PBRQ03>指令ROM的烧写如何进行

PIC提供的自定义的Bootloader可以用作设计参考。它的单片机部分的代码开源,还设计了一个上位机软件与之配合。因为考虑跨平台特性,这个软件是基于JRE的一个.jar程序。这种模式,很难适应云升级的模式。相关的链接参见:

https://www.microchip.com/en-us/tools-resources/develop/libraries/microchip-bootloadershttps://www.microchip.com/en-us/tools-resources/develop/libraries/microchip-bootloaders

这个厂商提供的bootloader系统,底层的代码是明的,在MCC中可以看到。现在需要想办法替换掉这个上位机软件。因为我们现在决定使用 Ymodem的语法与设备通讯,我们需要想办法把.hex文件(或者等价物)直接,或者通过其他设备、比如dtu之类的部件,透传到设备。

2.问题应对及编码

2.1升级文件的传输

我们打算使用485串口,然后通过Ymodem协议传输。

相关工作参见:YModem相关知识指引

2.2升级文件的形式

PIC单片机的指令文件,采用了Intel的.hex的格式。这个格式,MicroChip的变体,可以参见:

https://www.microchip.com/en-us/education/developer-help/learn-tools-software/mcu-mpu/mplab-ipe/sqtp-file-format-specification/intel-hexhttps://www.microchip.com/en-us/education/developer-help/learn-tools-software/mcu-mpu/mplab-ipe/sqtp-file-format-specification/intel-hex结构定义清晰,所以,似乎可以直接在这个基础上做。

2.3 烧写

  • Ymodem的有效载荷是1024字节。或者128字节。这样会面临Hex本身记录的分帧处理,会涉及到一级缓冲结构;
  • Hex文件本身的一笔笔记录并不与PIC单片机指令ROM的烧写规则相适应,需要一级缓冲机构。指令进行程序 rom写入时,必须要64Bytes一次性写入。
  • 直接以.hex传入的方法可以,但是需要确保.hex是顺序的。这部分代码我现在统合在一个称为Filter的函数内,下面给出代码:

2.3.1 顶层从485frame拆解出Intel Hex的记录:

这一级只用到了frame_cache缓冲:

//Bootloader App Update过程相关数据结构
#define FLASH_WRITE_BLOCK 64   //指令ROM必须按这个整倍数,对齐到内存整边界写入
#define HEX_MAX_RECORD 16      //HEX文件,单条记录的最大数据载荷长度
#define HEX_RECORD_STR_MAX (1+5*2+0x10*2) //用于流式解析,暂存不完整Hex Recorder的缓冲区长
struct _HexRecorderFilterObj
{
    uint16_t targetAddr; //Rom写入地址:需要对齐
    uint8_t write_block[FLASH_WRITE_BLOCK]; //注意類型,待写入Flash的缓冲区,bin格式
    uint8_t write_block_offset; 
    uint8_t frame_cache[HEX_RECORD_STR_MAX+1]; //字符格式,Hex recorder缓冲
    uint8_t frame_cache_offset;
#ifdef DEBUG_SHOW_HEX_DETAIL
    uint16_t debugCnt[4]; /*line, 0cnt, 1cnt, 4cnt*/
    uint32_t file_len;
#endif
}hexRecorderFilterObj;

//Bootloader App Update过程主入口
HAL_StatusTypeDef HexRecordFilter(uint8_t *buf, uint32_t len)
{
//:1057F00000000000FFFF0000EE2300007F3E0000DD
    do
    {
        if(hexRecorderFilterObj.frame_cache_offset>0)
        {
            if(hexRecorderFilterObj.frame_cache_offset>HEX_RECORD_STR_MAX)
            {
#ifdef DEBUG_SHOW_HEX_DETAIL            
                hexRecorderFilterObj.file_len+=hexRecorderFilterObj.frame_cache_offset;
#endif                
                hexRecorderFilterObj.frame_cache_offset = 0;
            }
            else if((*buf=='\r') || (*buf == '\n'))
            {
                //分幀后轉出解碼
                if(!Decode_a_hex_frame(hexRecorderFilterObj.frame_cache, hexRecorderFilterObj.frame_cache_offset))
                {
                    //return HAL_ERROR;
                }
#ifdef DEBUG_SHOW_HEX_DETAIL            
                hexRecorderFilterObj.file_len++;
#endif               
                hexRecorderFilterObj.frame_cache_offset = 0;
            }
            else hexRecorderFilterObj.frame_cache[hexRecorderFilterObj.frame_cache_offset++] = *buf;
        }
        else if(*buf == ':')
        {
            hexRecorderFilterObj.frame_cache[0] = *buf;
            hexRecorderFilterObj.frame_cache_offset = 1;
        }
        else
        {
#ifdef DEBUG_SHOW_HEX_DETAIL            
            hexRecorderFilterObj.file_len++;
#endif            
        }
        buf++;
        len--;
    }while(len>0);
    return HAL_OK;
}

2.3.2 Intel Hex文件单条记录的处理:

//識別到第0幀,繼續向後傳遞
bool Decode_a_hex_frame(uint8_t *frame, uint32_t len)
{
//:1057E000FFFFFF00FFFFFF00FFFFFF00FFFFFF00C5
    if(Hex2Byte(frame+1)*2+5*2+1 != len) return false;
#ifdef DEBUG_SHOW_HEX_DETAIL    
    hexRecorderFilterObj.file_len += len;
    hexRecorderFilterObj.debugCnt[0]++;
#endif    
    switch(Hex2Byte(frame+7))
    {
        case 0x01: 
#ifdef DEBUG_SHOW_HEX_DETAIL            
            hexRecorderFilterObj.debugCnt[2]++; 
#endif            
            break;
        case 0x04: 
#ifdef DEBUG_SHOW_HEX_DETAIL            
            hexRecorderFilterObj.debugCnt[3]++; 
#endif            
            break;
        case 0x00: 
#ifdef DEBUG_SHOW_HEX_DETAIL            
            hexRecorderFilterObj.debugCnt[1]++; 
#endif
            if(!DealHexFrame0(frame, len)) return false;
            break;
        default: 
#ifdef DEBUG_SHOW_HEX_DETAIL            
            HAL_Delay(1000);
            xlog("%d",len);
            HAL_Delay(1000);
            xlog(frame);
            HAL_Delay(1000);
#endif            
            return false;
    }
    return true;
}

bool DealHexFrame0(uint8_t *frame, uint32_t len)
{
    union
    {
        uint16_t tgtAddr;
        uint8_t b[2];
    }addr;
    addr.b[1] = Hex2Byte(frame+3);
    addr.b[0] = Hex2Byte(frame+5);
    uint8_t dataloadLen = Hex2Byte(frame+1);
    uint8_t dataloadCur = 0;
    do    
    {
        if(hexRecorderFilterObj.targetAddr!=0)
        {
            if((addr.tgtAddr>=hexRecorderFilterObj.targetAddr) 
                && (addr.tgtAddr-hexRecorderFilterObj.targetAddr<=FLASH_WRITE_BLOCK)
                && (hexRecorderFilterObj.write_block_offset<FLASH_WRITE_BLOCK))
            {
                while((hexRecorderFilterObj.write_block_offset<FLASH_WRITE_BLOCK)&&(dataloadCur<dataloadLen))
                {
                    hexRecorderFilterObj.write_block[hexRecorderFilterObj.write_block_offset++] = Hex2Byte(frame+9+(dataloadCur++)*2);
                }
            }
            else
            {
                hexRecorderFilterObj.write_block_offset = FLASH_WRITE_BLOCK;
            }
        }
        else
        {
            hexRecorderFilterObj.targetAddr = addr.tgtAddr + dataloadCur;
            hexRecorderFilterObj.write_block_offset = (hexRecorderFilterObj.targetAddr%64);
            if(hexRecorderFilterObj.write_block_offset)
            {
                hexRecorderFilterObj.targetAddr -= hexRecorderFilterObj.write_block_offset;
            }
            addr.tgtAddr = hexRecorderFilterObj.targetAddr;
            continue;
        }
        if(hexRecorderFilterObj.write_block_offset>=FLASH_WRITE_BLOCK)
        {
            if(FLASHIF_OK != FLASH_If_Write(hexRecorderFilterObj.targetAddr, hexRecorderFilterObj.write_block, FLASH_WRITE_BLOCK)) return false;
            hexRecorderFilterObj.targetAddr = 0;
            hexRecorderFilterObj.write_block_offset = 0;
        }
    }while(dataloadCur<dataloadLen);
    return true;
}

注意:到Flash_If_Write的部分,就可以和MCC生成的Memory读写代码做对接了。上面考虑了Hex文件的记录可能不会对齐到特定单片机指令ROM要求的地址边界;但是未考虑Hex记录乱序的问题。

3.结语

这是PIC单片机上Bootloader设计的全部内容。已经测试通过。从着手做,到第一次全部走通,我大概用了45个小时。预期是20个小时。超时225%。后续单机版,代码精简,考虑异常的本地升级的操作估计还有大概10~12个小时的工作量:

下面是时间消耗清单,单位是工时:

[13:00]完成了Bootloader和用户程序的分离,可以由Bootloader调用应用程序。

[18:00]YModem通过485传送单个文件调通。

[20:30]YModem大文件传送无误。

[26:00]YModem多文件传输无误。

[35:00]Hex分帧完毕,尺寸和帧号均与文件可以匹配。

[45:00]Hex帧解析处理完毕。程序下载到设备并成功完成跳转.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/728786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python接口自动化(二十一)--unittest简介(详解)

简介 前边的随笔主要介绍的requests模块的有关知识个内容&#xff0c;接下来看一下python的单元测试框架unittest。熟悉 或者了解java 的小伙伴应该都清楚常见的单元测试框架 Junit 和 TestNG&#xff0c;这个招聘的需求上也是经常见到的。python 里面也有单元 测试框架-unitt…

element table列表根据数据设置背景色

效果 页面代码 通过:cell-class-name动态绑定类名 <el-table :data"tableData" style"width: 100%" :cell-class-name"myclass"><el-table-column prop"date" label"日期" width"180"> </el-ta…

pytest测试框架的基本使用与介绍

pytest介绍 pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要特点有以下几点&#xff1a; 1、简单灵活&#xff0c;容易上手&#xff0c;文档丰富&#xff1b; 2、支持参数化&#xff0c;可以细粒度地控制要测试的测试用例&#xff1b; 3、能够支持简单的单元测…

Jenkins---jenkins生成Allure报告

目录 前言 Allure插件安装 生成Allure报告 遇到的问题 总结&#xff1a; 前言 前几天介绍了如何生成html报告&#xff0c;目前绝大部分公司都是用的allure报告&#xff0c;那么今天也介绍下如何通过jenkins生成allure报告。 Allure插件安装 jenkins中存在支持allure报告…

Pytorch从入门到精通:一、准备工作与查询函数

之前虽然做了不少计算机视觉的项目&#xff0c;但是如果让我从0还是用Pytorch开始写的话还是有一点难度。原因就在于没有系统的学习Pytorch&#xff0c;对于里面的不少模块都只知道使用&#xff0c;不知道原理&#xff0c;知道它能工作&#xff0c;但是不知道怎么样工作的。所以…

QT - 20230707

登录界面练习 #include "loginwindow.h"QIcon fetchIconWithName(QString name) {QString res "../login/images/" name;return QIcon(res); }LoginWindow::LoginWindow(QWidget *parent): QMainWindow(parent) {this->resize(600, 800);this->se…

小红书私信软件:把微信二维码联系方式隐藏在图片中推广引流找客源

小红书私信软件&#xff1a;把微信二维码联系方式隐藏在图片中推广引流找客源,小红书还能这么玩&#xff1f;小红书暑期聊天功能上新了&#xff0c;共享收藏夹、斗图神器&#xff0c;暑期表情&#xff0c;笔记表态....快去和好友一起解锁新功能吧&#xff01; #小红书 最近发现…

YOLOv5-第Y1周:调用官方权重进行检测

YOLOv5-第Y1周&#xff1a;调用官方权重进行检测 YOLOv5-第Y1周&#xff1a;调用官方权重进行检测一、前言二、我的环境三、下载源码四、运行代码五、视频检测八、总结 YOLOv5-第Y1周&#xff1a;调用官方权重进行检测 一、前言 &#x1f368; 本文为&#x1f517;365天深度学…

【Redis-工具类】自定义Redis工具类并使用其进行简单操作

【Redis-工具类】自定义Redis工具类并使用其进行简单操作 1&#xff09;自定义 Redis 工具类2&#xff09;工具类的简单使用 1&#xff09;自定义 Redis 工具类 package gaei.cn.x5l.x5lhive2cos.utils;import gaei.cn.x5l.x5lhive2cos.CosDataBackupHistory; import gaei.cn.…

AI智能化数据分析,赋能文旅直播发展新赛道

一、文旅直播发展背景 近期&#xff0c;旅游业市场呈现火热态势。暑期旅游市场预计迎来新一轮旅游小高峰&#xff0c;旅游业进入结构性复苏新阶段。而随着社交媒介的普及与旅游直播的兴起&#xff0c;全国多地文旅“出圈”形成热议。 对于文旅产业发展来说&#xff0c;高品质…

【如何在工作中保持稳定的情绪 --- 保持稳定情绪的7个工作技巧】

导语&#xff1a; 在现代工作环境中&#xff0c;保持稳定的情绪是一项至关重要的技能。当我们遇到挑战、压力和严峻的工作条件时&#xff0c;情绪的稳定性对于我们的工作效率和心理健康至关重要。本文将分享七个实用的工作技巧&#xff0c;帮助你保持稳定的情绪并提升工作质量…

面对chatGPT,冷静比鸡血更重要!

这段时间 chatGPT 也算是疯狂的吸引眼球了。 看起来广告费没白花&#xff0c;不管说的对不对&#xff0c;反正说它一定要用**“颠覆”“天花板”“惊艳”“抢大多数人的饭碗”**之类的词。 再大一点的描述就是&#xff1a;留给人类的时间不多了。扼腕叹息、杞人类生存空间而忧…

springboot项目开启https协议

1、在windows以管理员身份运行cmd,输入如下命令生成证书 keytool -genkey -alias myhttps -keyalg RSA -keysize 2048 -validity 36500 -keystore "D:/tmp/ssl/myhttps.keystore"注释 命令&#xff1a;keytool -genkey -alias testhttps -keyalg RSA -keysize 204…

蓝牙资讯|苹果Beats Studio Pro耳机曝光,支持苹果和谷歌的查找功能

国外科技媒体9to5Mac曝光苹果Beats Studio Pro耳机&#xff0c;这款耳机配备了 2 个定制的 40 毫米驱动单元&#xff0c;即便是在最高音量下&#xff0c;也能确保不会失真。Beats Studio Pro 还将配备集成的数字处理器&#xff0c;该处理器“优化最终频率响应&#xff0c;以获得…

Jetpack 架构组件你了解多少?

本文是我在学习Jetpack的过程中做的一些记录&#xff0c;如有错误&#xff0c;欢迎指正 本文包含了 ViewModel、Lifecycles、LiveData、Room、WorkManager 的相关用法&#xff0c;你可以通过目录直接跳转到你想了解的地方 ViewModel 简单介绍下 ViewModel&#xff1a;ViewMode…

DataWhale: LLM+KG

https://mp.weixin.qq.com/s/MIi1WrAwfmqnXGlkQq8DqQ

硬件性能 - 网络瓶颈分析

简介 本文章主要通过Linux命令查看网络信息、判断是否出现网络瓶颈等简单分析方法。 目录 1. 监控命令 sar 2. 带宽利用率 3. 网络延迟 4. 网络连接数 5. 模拟网络故障 1. 监控命令 sar sar 命令实时查看网络情况&#xff08;详细命令&#xff1a;Linux性能监控命令_sar …

靠着这份 Java 面试题跟答案,我从 14K 变成了 28K!

LZ 认为&#xff0c;对于 Java 面试以及进阶的最佳学习方法莫过于刷题博客书籍总结&#xff0c;前三者 LZ 将淋漓尽致地挥毫于这篇文章中&#xff0c;至于总结在于个人&#xff0c;实际上越到后面你会发现面试并不难&#xff0c;其次就是在刷题的过程中有没有去思考&#xff0c…

【QT】——事件处理系统

目录 1.事件介绍 2.QT事件的产生 3.事件处理函数 3.1鼠标事件 3.2键盘事件 3.3窗口重绘事件 3.4窗口关闭事件 3.5窗口大小变化事件 4. 重写事件处理函数 1.事件介绍 QT 程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发。QT 事件的发生和处理 成为程序运行的…

数据质量管理之ETL中的挑战与解决方案

摘要&#xff1a;在数据驱动的时代&#xff0c;数据质量管理是企业成功的关键因素之一。在ETL&#xff08;Extract, Transform, Load&#xff09;过程中&#xff0c;数据质量问题可能会导致数据失真、决策错误和业务损失。本文将探讨ETL中常见的数据质量挑战&#xff0c;并提供…