历史上的今天
返回首页

历史上的今天

今天是:2025年05月17日(星期六)

2020年05月17日 | 【dsPIC33E】Bootloader(三)Bootloader下位机

2020-05-17 来源:eefocus

前面2节讲述了dsPIC33E的Flash存储结构以及Hex格式,接下来开始讲述如何编写Bootloader下位机和上位机。


本节讲述下位机的设计,考虑到执行效率和烧录时间,我们将主要解析工作放到上位机中,因为PC的执行速度远高于MCU。在上位机中,我们将Hex文件解析成一组一组的地址和数据组合,然后将一个地址和数据打包发送到Bootloader,Bootloader将其写入对应地址内。


我们先将地址空间分割成三段区域:


0x000000-0x0007FF: 第一段为起始跳转、复位和中断向量表


0x000800-0x0071FF: 第二段为Bootloader,此处预留0x6400长度,为了以后扩充,多预留了一点,后面再空一点点。


0x008000-0x02A800: 第三段为User App,注意最后一页(包含配置字)不要使用,擦除时会导致代码保护清零。


分别在Bootloader和AfterBootloader(即User App)项目中添加gld文件(从xc16安装文件夹下复制到项目目录下),修改对应的程序地址(修改program (xr)的起始地址和长度),这样编译时,会限制程序起始和结束地址。


以下我们将使用具体项目来说明,使用的芯片为dsPIC33EP256GP506


示例项目下载:https://download.csdn.net/download/u010875635/10819819

Bootloader中,最重要的就是2个功能,一是通信,二是Flash读写。由于不能使用中断,防止中断向量表与User App的冲突,通信都采用查询模式。开发板正好有现成的串口,本例采用串口通信,考虑到后面可能会使用CAN,因此核心数据长度为8bytes,串口本身校验功能差,我们再在前后分别增加2个字节,总计12个字节。


此例总共设有5中命令,兼容Bootloader和User App,分别为:EntryBootloader(User App中可用)、Reset、Data、DataEnd、CheckBootloader、Erase。


EntryBootloader,Bootloader不适用,User App中可用,由上过机发送过来的命令,用于在User App中复位到Bootloader,以便于进行代码烧写工作;Bootloader启动时会向上位机发送EntryBootloader回馈,表示进入Bootloader。


Reset,Bootloader中可用,上位机发送过来的命令,用于烧写完毕后,重启系统,User App启动时会向上位机发送Reset回馈表示已经于User App。


Data,接收到的为数据,由上位机发送过来,Bootloader将其写入flash。


DataEnd,上位机发送数据完毕,告诉Bootloader系统可以复位了。


CheckBootloader,上位机发送的命令,用于检查是否在Bootloader中,若在则回馈,若不再不回馈,上位机有超时判断。


Erase,上位机发送命令,下位机接收到命令后,会擦除所有用户程序相关的存储区,包括复位和中断向量表。


#include "McuDrivers/uart/uart.h"

#include "McuDrivers/system/system.h"

#include "McuDrivers/flash/DataRecord.h"

#include "McuDrivers/gpio/gpio.h"

#include "McuDrivers/timer/timer.h"

#include "Protocols/Bootloader.h"

#include "Protocols/UserAppFlash.h"

#include "McuDrivers/flash/InnerFlash.h"

 

 

uint8_t receiveData[12]={0},dataIndex=0;

 

void Uart_Tasks();

uint8_t Time_Tasks();

uint8_t Tick_Tasks();

 

int main(void) 

{    

    uint8_t run=1;

    

    System_Initialize_g();

 

    Uart_Initial_g(115200);

    System_Delay_MS_g(100);

 

 

    GPIO_LED_D4_Enable_g();

    GPIO_LED_D3_Enable_g();

    while(run)

    {

        Uart_Tasks(); //接收数据处理

 

        run = Tick_Tasks();

    }

    while(1)

    {

        Uart_Tasks(); //接收数据处理

    }

    return 0;

}

 

uint16_t countTick = 0;

uint8_t Tick_Tasks()

{

    countTick++;

    //晶振为80MHz

    //每隔800大约1ms

    if(countTick==800)

    {

        countTick=0;

        return Time_Tasks();

    }

    return 1;

}

 

uint16_t countTimer=0;

uint8_t Time_Tasks()

{

    countTimer++;

    if(countTimer==4000)

    {

        BOOTLOADER_GOTO_8000();

        return 0;

    }

    

    if(countTimer>4000)

        return 0;

    

    if(countTimer%500==0)

        GPIO_LED_D3_Toggle_g();

    

    return 1;

}

 

//串口接收任务

void Uart_Tasks()

{

    if(U2STAbits.URXDA==1)

    {

        uint8_t tmp = Uart_ReadByte();

        switch(dataIndex)

        {

            case 0:

                if(tmp==g_Bootloader_Receive_StartFlag[0]) //起始标识1

                {

                    receiveData[0] = g_Bootloader_Receive_StartFlag[0];

                    dataIndex = 1;

                }

                else

                    dataIndex = 0;

                break;

            case 1:

                if(tmp==g_Bootloader_Receive_StartFlag[1]) //起始标识2

                {

                    receiveData[1] = g_Bootloader_Receive_StartFlag[1];

                    dataIndex = 2;

                }

                else

                    dataIndex = 0;

                break;

            case 10:

                if(tmp==g_Bootloader_Receive_EndFlag[0])

                {

                    receiveData[dataIndex] = g_Bootloader_Receive_EndFlag[0];

                    dataIndex = 11;

                }

                else

                    dataIndex = 0;

                break;

            case 11:

                if(tmp==g_Bootloader_Receive_EndFlag[1])

                {

                    receiveData[dataIndex] = g_Bootloader_Receive_EndFlag[1];

                    

                    AfterBootloader_CmdType result = Bootloader_DataParse(receiveData,12);

                    //Uart_WriteByte_g(result);

                    switch(result)

                    {

                        case EntryBootloader:

                            break;

                        case Reset:

                            BOOTLOADER_SOFTWARE_RESET();

                            break;

                        case Data: //数据

                            countTimer = 4001; //出现数据即不跳转到用户程序,避免烧录用户程序时出现异常

                            //UserFlash_EraseIvtAndUserAppBlock();

                            UserFlash_DataParseAddrData(receiveData,12);

                            Uart_WriteBytes_g(g_Bootloader_DataReponse,12);

                            GPIO_LED_D3_Toggle_g();

                            break;

                        case DataEnd: //数据结束

                            GPIO_LED_D4_Enable_g();

                            GPIO_LED_D3_Enable_g();

                            Uart_WriteBytes_g(g_Bootloader_DataProgramEndReponse,12);

                            BOOTLOADER_SOFTWARE_RESET(); //数据刷新完毕,复位

                            break;

                        case CheckBootloader: //回馈正处于Bootloader中

                            Uart_WriteBytes_g(g_Bootloader_CheckBootloaderReponse,12);

                            break;

                        case Erase:

                            UserFlash_EraseIvtAndUserAppBlock();

                            Uart_WriteBytes_g(g_Bootloader_EraseFlashReponse,12);

                            break;

                        default:

                            break;

                    }

 

                }

                

                dataIndex = 0;

                break;

            default: 

                receiveData[dataIndex] = tmp; dataIndex++;

                break;

        }

    }

}


在数据处理上,由于dsPIC33EP256GP506只支持双指令字编程,所以我们接收到2个数据才会判断然后写入flash,考虑到最后肯定是配置字,而此处配置字是无法写入的,所以不考虑数据个数是否是奇数(奇数会导致最后一个数据漏写)情况了。

推荐阅读

史海拾趣

FINTEK公司的发展小趣事

随着ASP芯片市场的成功,FINTEK公司意识到单一产品线的局限性。为了保持竞争优势并开拓新市场,公司开始多元化拓展产品线。经过市场调研和技术储备,FINTEK相继推出了数字信号处理器(DSP)、微控制器(MCU)以及射频前端模块(RF FEM)等一系列新产品。这些产品的推出不仅丰富了公司的产品线,也进一步巩固了FINTEK在半导体领域的市场地位。

Connor-Winfield公司的发展小趣事

随着全球经济的一体化,电子行业也逐渐呈现出全球化的趋势。Connor-Winfield敏锐地把握住了这一机遇,开始实施全球化战略。公司积极拓展海外市场,与多家国际知名企业建立了紧密的合作伙伴关系。这些合作不仅为公司带来了更多的商业机会,也使其在全球化竞争中保持了领先地位。

AMOTECH(阿莫泰克)公司的发展小趣事

1994年,AMOTECH在韩国创立,凭借创始人的远见卓识和技术团队的扎实能力,公司迅速在电子行业中崭露头角。经过两年的努力,1996年,AMOTECH被政府通讯部评为“光明前途企业”,这是对其技术实力和市场潜力的肯定。随后,公司不断加大研发投入,终于在2000年获得ISO9000认证,这标志着AMOTECH在产品质量管理上达到了国际标准。

Diode Laser Concepts公司的发展小趣事

在电子行业的早期,激光技术刚刚起步,而Diode Laser Concepts公司的创始人——一位激光领域的专家,看到了二极管激光器(Diode Laser)在精密制造和医疗领域的巨大潜力。他带领团队攻克了一系列技术难题,成功研发出高效、稳定的二极管激光器。这一突破性的技术为公司的创立奠定了坚实的基础。

广东爱晟电子(exsense)公司的发展小趣事

随着业务的不断拓展,爱晟电子意识到品质是品牌的核心。公司引进了先进的生产设备和管理体系,严格按照ISO9001质量体系运作,确保产品质量的稳定性和可靠性。同时,公司还加强了对原材料的质量控制,与国内外优质供应商建立了长期稳定的合作关系。这些举措使得爱晟电子的产品在市场上赢得了良好的口碑,品牌影响力逐渐增强。

乾坤(Cyntec)公司的发展小趣事

随着科技的不断进步,电子行业的发展日新月异。乾坤公司意识到,要想保持领先地位,就必须不断进行技术创新。于是,公司加大了对研发团队的投入,引进了一批高水平的科研人才,并与多所高校和研究机构建立了紧密的合作关系。在一次偶然的实验中,研发团队发现了一种新型材料,可以显著提升电子元器件的性能。经过一系列严格的测试和验证,这种新材料被成功应用于产品生产中,使得乾坤的电子元器件在性能上实现了质的飞跃。这一技术创新不仅为公司带来了丰厚的利润,更让乾坤在电子行业中声名鹊起。

问答坊 | AI 解惑

Pocket PC中汉字输入法分析与实现.pdf

Pocket PC中汉字输入法分析与实现.pdf…

查看全部问答>

硬盘找不到

我有台机子,原来找装的硬盘是串口的,今天我把它直接换了个并口的,机子一直是说找不到硬盘,不知道是不是需要做些设置,还是硬盘坏了…

查看全部问答>

wince更新内核问题(eboot logo)

系统:wince 5.0 CPU 三星2450 目的:用户实现更新开机画面。         方法一:把bootlogo.bmp写到nand的某一块,然后eboot去读,我还没有想这个         方法二:在电脑上把bootlo ...…

查看全部问答>

PH8810电话模块

这个电话模块有没有人会吗,,,急急,,现在的问题就在于,程序不知道干怎么写??? 有高手用过,请教一下…

查看全部问答>

请教一下 在wince里面添加新的ttf字库的问题

请问一下 为什么在wince里添加网上下载的中文字库显示不了 英文的却能显示 还有就是我自己做的中文字库也能显示  在英文字库里添加中文字库也能显示 这是为什么啊…

查看全部问答>

linux交互界面开发minigui

工控机交互界面,相对简单,所以可优化考虑用minigui或不用第三方图形库。在linux虚拟机上能运行就行,移植到arm我们自己完成。 需求和用户界面、菜单等基本画好了,详见: http://www.qiyedz.com/LinuxGuiDev.doc 要求有开发经验,有阶段性 ...…

查看全部问答>

我朋友想参加嵌入式开发的培训,有没有好的机构推荐一下啊!在上海!

我朋友想参加嵌入式开发的培训,有没有好的机构推荐一下啊!在上海!…

查看全部问答>

AVR程序求解一个简单的函数

void LS_595_DS1(uchar dat){ char i; for(i=0;i<8;i++) {   _SH1=0;   _DS1=dat&0x01;   dat>>=1;   delay_ls(5);   _SH1=1;  }  _SL1=0;  delay_ls(5) ...…

查看全部问答>