• 自己用C语言写dsPIC / PIC24 serial bootloader


            了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序)。

      HyperBootloader_dsPIC

      HyperBootloader_dsPIC是我用C语言实现的UART bootloader, 采用串口通信,适用于Microchip的dsPIC30, dsPIC33,同样适用于PIC24。单片机端bootloader是用XC16编译的,电脑端的通信软件是用超级终端--HyperTerminal。

      dsPIC30 和 dsPIC33 程序存储器

      dsPIC30,dsPIC33, PIC24的程序存储器架构都一样,只是大小,和vector位置有所不同。下图所示的是dsPIC30和dsPIC33程序存储器的示意图,以及HyperBootloader的放置位置。HyperBootloader_dsPIC是放置在IVT/AIVT中断vector所占Page之外,所以IVT/AIVT不需要做任何变动。

      

      如上图所示,对于dsPIC30, HyperBootloader_dsPIC的ROM Range是0x400~0xBFF, 对于dsPIC33, HyperBootloader_dsPIC的ROM Range是0x100~0x5FF。

      ROM Range 设置

      下面以dsPIC33FJ256GP710A为例,详细说一下如何设置ROM Range。在编译HyperBootloader_dsPIC时,需要添加p33FJ256GP710A.gld文件到项目目录中来,并对其修改以下地方。

      program (xr) : ORIGIN = 0x400, LENGTH = 0x0800 /*2A9FE*/
      __CODE_BASE = 0x400;
      __CODE_LENGTH = 0x0800; /*2AA00;*/

      这样就完成了对HyerBootloader_dsPIC的ROM Range的设置。

      另外由上图可知,应用程序需要烧录到dsPIC33FJ256GP710A ROM的0xC00之后。所以在编译应用程序时,同样需要添加p33FJ256GP710A.gld文件到项目目录中来,并对其修改以下地方来完成ROM Range设置。

      program (xr) : ORIGIN = 0xC00, LENGTH = 0x02A000 /*2A9FE*/
      __CODE_BASE = 0xC00;
      __CODE_LENGTH = 0x02A000; /*2AA00;*/

      主要代码段

      HyperBootloader_dsPIC采用的是程序字烧录,具体实现代码段如下。

            for(;;)
            {
                while (U1RXREG != ':');
                while (!U1STAbits.TRMT);
                U1TXREG=':';
    
                cksum = bcount = bytecount = GetXbyte();
                //address
                SourceAddr.v[1] = GetXbyte();
                SourceAddr.v[0] = GetXbyte();
                SourceAddr.Val >>= 1;
                rectype = GetXbyte();
                switch(rectype)
                {
                case LINEAR_ADDRESS:
                    SourceAddr.v[3] = GetXbyte();
                    SourceAddr.v[2] = GetXbyte();
                    Checksum();
                    break;
                case DATA:
                    while (bytecount--)
                    {
                        Buffer[incrbyte++] = GetXbyte();
                    }
                    Checksum();
                    if (SourceAddr.Val >= CM_START)
                    {
                        //NVMCON = CM_WORD_WRITE;
                        ClearBuffData();
                        break;
                    }
                    else
                    {
                        NVMCON = PM_WORD_WRITE;
                    }
                    for (ix = 0; ix < bcount; )
                    {
                        pData.byte.LB = Buffer[ix+0];
                        pData.byte.HB = Buffer[ix+1];
                        pData.byte.UB = Buffer[ix+2];
                        pData.byte.MB = Buffer[ix+3];
    
                        TBLPAG = SourceAddr.word.HW;
                        if (SourceAddr.Val == 0)
                        {
                            pData.word.LW = BOOT_START;   // reset vector
                            pData.word.HW = 0x0004;     // goto BOOT_START
                        }
                        __builtin_tblwtl(SourceAddr.word.LW, pData.word.LW);
                        __builtin_tblwth(SourceAddr.word.LW, pData.word.HW);
                        asm("DISI #16");   //Disable interrupts for few instru
                        __builtin_write_NVM();
                        Nop();
                        while (NVMCONbits.WR);
    
                        rData.word.HW = __builtin_tblrdh(SourceAddr.word.LW);
                        rData.word.LW = __builtin_tblrdl(SourceAddr.word.LW);
    
                        if ((rData.Val != pData.Val))                   //&&(SourceAddr.Val < CM_START))
                        {
                            putsUART1((unsigned int *)"Error
    ");
                            RCONbits.SWDTEN=1;   // use WTD to reset device
                            while (1);
                        }
                        ix += 4;
                        SourceAddr.Val += 2;
                    }
                    ClearBuffData();
                    NVMCONbits.WREN = 0;
                    break;
                case END:
                    Checksum();
                    U1MODE = 0x0;
                    U1STA = 0x0110;
                    (*((void(*)(void))PROG_START))();
                    break;
                }
            }    

      如何使用

      1. 使用XC16编译HyperBootloader_dsPIC(编译前,需先修改gld文件,详见"ROM Range设置")。

      2. 使用pickit3烧录HyperBootloader_dsPIC的Hex文件到目标板中。

      3. 拔除pickit3烧录器,连接目标板与PC的串口,打开超级终端,设置如下:115200-8-None-1-None, Line Delay-20ms

      4. 重启目标板,超级终端会出现Booting... 字样。

      5. 6秒内,在超级终端窗口中按下键盘上任何按键,会出现">"(6秒内没按键,会自动跳转到用户的应用程序中去)。

      6. 打开Send Text File对话框,选择期望烧录的应用程序hex文件(编译前,需先修改gld文件,详见”ROM Range设置"),点击确认, HyperBootloader会将接收到的数据传回到电脑超级终端上,并将数据烧录到目标板程序存储器的正确位置。

      7. 烧录完毕,再次重启目标板,超级终端显示完Booting ......,就自动跳到应用程序中,目标板开始正常运行应用程序。

      之后每次更新应用程序,只需重复步骤 4 ~ 7 就可以了。

      主要特性

      HyperBootloader_dsPIC有以下主要特性

      1. C语言写的,XC16 编译。

      2. 非常容易移植, 支持dsPIC30, dsPIC33, PIC24。

      3. 支持FLASH烧写

      4. 可支持EEPROM烧写。

      5. 支持CONFIG BITS/IDLOC 烧写。

      如果你有什么疑问,或有兴趣了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 验证信息请填 bootloader 或 cnblogs)。

      想了解PIC18 bootloader 请阅读我的随笔《自己用C语言写单片机PIC18 serial bootloader》

      想了解PIC16 bootloader 请阅读我的随笔《自己用C语言写单片机PIC16 serial bootloader》

  • 相关阅读:
    Linux下Mysql自启动
    C++的Vector用法
    如何判断一个文本文件内容的编码格式 UTF-8 ? ANSI(GBK)
    windows自带记事本导致文本文件(UTF-8编码)开头三个字符乱码问题
    C/C++字符串查找函数
    C++ string 字符串查找匹配
    CentOS6.5升级autoconf版本 Autoconf version 2.64 or higher is required
    Linux命令之远程下载命令:wget
    Linux常用命令大全
    如何使用VisualStudio2013编写和调试c语言程序
  • 原文地址:https://www.cnblogs.com/geekygeek/p/hyperbootloader_dspic.html
Copyright © 2020-2023  润新知