采用UDP协议实现PIC18F97J60 ethernet bootloader

发布者:ww313618最新更新时间:2017-01-20 来源: eefocus关键字:UDP协议  PIC18F97J60  ethernet  bootloader 手机看文章 扫描二维码
随时随地手机看文章

  TCP/IP Stack

  使用pic18f97j60开发过多个项目,项目中都使用了Microchip免费提供的TCP/IP Stack实现远程控制。但是每次更新程序,都需要将pic18f97j60目标板取回来重新烧录,很不方便。既然可以实现远程控制,为什么不实现远程更新呢?这就是我的ethernet bootloader的由来。Microchip的TCP/IP Stack功能很强大,我决定只用它的UDP模块来实现。为了实现远程更新,我需要写pic18f97j60单片机端UDP协议的ethernet bootloader程序--我将其命名为PhnBoot_v1.0; 同时还需要写PC端与bootloader交互的UDP通信程序--我将其命名为PhnLoader_v1.0。我还定义了PhnBoot_v1.0和PhnLoader_v1.0之间传输数据的通信协定。

  通信协定

  单片机端PhnBoot_v1.0和PC端PhnLoader_v1.0之间的通信数据包采用以下协定

...

  定义如下:

STX - Start of packet indicator
ETX - End of packet indicator
LEN - The length of true data
DATA - General data 16 bytes, only first LEN of datas are true
CMD - Base command
ADDR - Address up to 24 bits  ( ADDRL , ADDRH , ADDRH)

  具体有以下Base command:

RD-VER:  0x00 -- Read Version Information (最终版本删除了此命令)
RD_MEM: 0x01 -- Read Program Memory (最终版本删除了此命令)
ER_MEM: 0x03 -- Erase Program Memory
WR_MEM: 0x02 -- Write Program Memory 
WR_CFG: 0x04 -- Write Configuration Registers

  PhnLoader_v1.0 功能

  定义好了通讯协定, 接着就按照协定去实现PhnLoader_v1.0。 PhnLoader_v1.0的具体功能包括选择IP地址,端口和协议类型,目前只支持UDP协议, 创建UDP服务器,加载应用程序Hex文件,Parse 应用程序的Hex文件,一行一行解读Hex文件,一旦收到更新请求,立刻按照通讯协定采用UDP协议发送Hex记录到单片机,接收单片机发送回来的Response,发送完毕后断开UDP通信,发送期间出现问题就立马结束发送。

  PhnLoader_v1.0 主要代码段

  PhnLoader_v1.0是用C#实现的,是我在利用空余时间自学C#后写的,上面提到的功能都实现了。


        private void btnDownload_Click(object sender, EventArgs e)
        {
            btnDownload.Enabled = false;
            pBarLoading.Visible = false;            if (!this.connect())
            {
                Debug.WriteLine("Udp server building unsuccessfully");
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Udp server building unsuccessfully\r\n");
                textBoxStatus.ForeColor = Color.Black;
                btnDownload.Enabled = true;                return;
            }            try
            {
                loaderReader = new StreamReader(textBoxFile.Text);

            }            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Read hex file unsuccessfully\r\n");
                textBoxStatus.ForeColor = Color.Black;
                loaderReader.Close();
                loaderServer.Close();
                btnDownload.Enabled = true;                return;
            }

            loaderFrame = new SerialFrame();
            DateTime startTime = DateTime.Now;
            IPEndPoint clientPoint = new IPEndPoint(IPAddress.Any, 0);            
            if (!loaderServer.Read(readyMsg,timeSpan))
            {
                Debug.WriteLine("Error: Timeout receive ready message from bootloader");
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Timeout receive ready message from bootloader\r\n");
                textBoxStatus.ForeColor = Color.Black;
                loaderServer.Close();
                loaderReader.Close();
                btnDownload.Enabled = true;                return;
            }            if (!erase())
            {
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Erase unsuccessfully\r\n");
                textBoxStatus.ForeColor = Color.Black;
                loaderReader.Close();
                loaderServer.Close();
                btnDownload.Enabled = true;                return;
            }

            pBarLoading.Refresh();
            pBarLoading.Visible = true;
            pBarLoading.Value = 0;
            pBarLoading.Maximum = loaderLines;
            pBarLoading.Step = 1;            string recordLine;
            Address_U = 0;            bool isNextLineUserID = false;            bool isNextLineConfigBits = false;
            textBoxStatus.AppendText("\r\nDownloading hex file ...\r\n");            try
            {                while (loaderReader.Peek() >= 0)
                {
                    pBarLoading.PerformStep();
                    recordLine = loaderReader.ReadLine();                    if (recordLine.Contains(EXTEND_TOKEN) == true)
                    {                        if (recordLine.Contains(USER_ID_TOKEN) == true)
                        {
                            isNextLineUserID = true;                            continue;
                        }                        else if (recordLine.Contains(CONFIG_BITS_TOKEN) == true)
                        {                            const int ADDR_U_START_INDEX = 9;                            const int ADDR_U_LENGTH = 4;                            string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);
                            Address_U = Convert.ToInt32(addrU, 16) << 16;
                            isNextLineConfigBits = true;                            continue;
                        }                        else
                        {                            const int ADDR_U_START_INDEX = 9;                            const int ADDR_U_LENGTH = 4;                            string addrU = recordLine.Substring(ADDR_U_START_INDEX, ADDR_U_LENGTH);
                            Address_U = Convert.ToInt32(addrU, 16) << 16;                            continue;
                        }
                    }                    else if (((recordLine.Contains(J_TYPE_CONFIG_BITS_1) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_2) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_3) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_4) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_5) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_6) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_TOKEN_1) == true) ||
                             (recordLine.Contains(J_TYPE_CONFIG_BITS_TOKEN_2) == true)) &&
                             (Address_U == 0x010000))
                    {                        if (!DownloadConfigLine(recordLine))
                        {
                            Debug.WriteLine("Error found during configuration bits programming");
                            loaderReader.Close();
                            loaderServer.Close();
                            btnDownload.Enabled = true;                            return;
                        }                        continue;
                    }                    else if (recordLine.Contains(END_OF_HEX_FILE_TOKEN) == true)
                    {                        break;
                    }                    if (isNextLineUserID)
                    {
                        isNextLineUserID = false;                        // do nothing;                    }                    else if (isNextLineConfigBits)
                    {                        if (!DownloadConfigLine(recordLine))
                        {
                            Debug.WriteLine("Error found during configuration bits programming");
                            loaderReader.Close();
                            loaderServer.Close();
                            btnDownload.Enabled = true;                            return;
                        }
                        isNextLineConfigBits = false;
                    }                    else
                    {                        if (!DownloadDataLine(recordLine))
                        {
                            Debug.WriteLine("Error found during data programming");
                            loaderReader.Close();
                            loaderServer.Close();
                            btnDownload.Enabled = true;                            return;
                        }
                    }
                }
            }            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Downloading failed\r\n");
                textBoxStatus.ForeColor = Color.Black;
                loaderServer.Close();
                loaderReader.Close();
                btnDownload.Enabled = true;                return;
            }
            textBoxStatus.AppendText("Downloading completed\r\n");            if (!run())
            {
                textBoxStatus.ForeColor = Color.Red;
                textBoxStatus.AppendText("Jump to Application unsuccessfully\r\n");
                textBoxStatus.ForeColor = Color.Black;
                loaderReader.Close();
                loaderServer.Close();
                btnDownload.Enabled = true;                return;
            }
            loaderServer.Close();
            loaderReader.Close();
            btnDownload.Enabled = true;
        }


  PhnLoader_v1.0 用户界面

  

  PhnBoot_v1.0 功能

  在PhnLoader_v1.0完成后,接着就是完成PhnBoot_v1.0。 PhnBoot_v1.0主要功能就是使用Microchip的TCP/IP Stack建立UDP Client,发送更新应用程序请求,接收PhnLoader_v1.0传送过来的Hex记录。解读Hex记录中的启始位,命名,地址,数据和结束位,将数据烧录到指定的程序存储器的位置上,然后通过ethernet返回Response消息给PC端PhnLoader_v1.0。

  PhnBoot_v1.0 位置

  PhnBoot_v1.0放置在程序存储器的头部,大小为0x2400程序字。

   

  Interrupt Vector Remap

  由于PhnBoot_v1.0位于程序存储器的头部,需要对Interrupt Vector进行remap. 代码如下。


  #define REMAPPED_APP_HIGH_INTERRUPT_VECTOR  0x2408
  #define REMAPPED_APP_LOW_INTERRUPT_VECTOR   0x2418
  #pragma code low_vector_section=0x018
  void low_vector (void)
  {
      _asm
          goto REMAPPED_APP_LOW_INTERRUPT_VECTOR
      _endasm
  }

  #pragma code high_vector_section=0x08
  void high_vector (void)
  {
      _asm
          goto REMAPPED_APP_HIGH_INTERRUPT_VECTOR
      _endasm
  }


  PhnBoot_v1.0 主要代码段

  PhnBoot_v1.0 是用C语言写的,Microchip 8-bit C Compiler--MCC18编译的。


        switch (GenUDPSt)
        {        case SM_HOME:
            ARPResolve(&Server.IPAddr);            if (ARPIsResolved(&Server.IPAddr,&Server.MACAddr))
            {
                MySock = UDPOpen(ClientPort,&Server,ServerPort);                if (MySock != INVALID_UDP_SOCKET)
                {
                    tick = 0x10000;
                    delay = BOOT_TIMEOUT;
                    GenUDPSt++;
                }
            }            else
            {
                tick--;                if (tick==0)
                {
                    tick = 0x10000;                    if (delay == 0)
                    {
                        delay = BOOT_TIMEOUT;
                        GenUDPSt = SM_CLOSE;
                    }
                    delay--;
                }
            }            break;        case SM_READY:            if (UDPIsPutReady(MySock) > BUFFER_MAX)
            {
                UDPPutString(ok);
                UDPFlush();
                GenUDPSt++;
            }            else
            {
                tick--;                if (tick==0)
                {
                    tick = 0x10000;                    if (delay == 0)
                    {
                        delay = BOOT_TIMEOUT;
                        GenUDPSt = SM_CLOSE;
                    }
                    delay--;
                }
            }            break;        case SM_RESPONSE:
            udpPackets = UDPIsGetReady(MySock);            if (udpPackets >= BUFFER_MAX)
            {
                UDPGetArray(line_buffer, BUFFER_MAX);
                UDPDiscard();                
                if (line_buffer[0] == STX && line_buffer[BUFFER_MAX - 1] == ETX)
                {                    switch (line_buffer[CMD_INDEX])
                    {                    case WR_MEM:
                        EECON1 = PGM_WRITE;
                        WriteMem();                        break;                    case WR_CFG:                        if (!last_block_written&&!CFG_NUM)
                        {
                            WriteStart();
                            last_block_written = 1;
                            ResetBlockBuffer();
                        }
                        CFG_NUM++;
                        EECON1 = CFG_WRITE;
                        WriteCfg();                        break;                    case ER_MEM:
                        EECON1 = PGM_ERASE;
                        EraseMem();                        break;                    case RUN_APP:                        if (!last_block_written)
                        {
                            WriteStart();
                            last_block_written = 1;
                            ResetBlockBuffer();
                        }
                        GenUDPSt++;                    default:                        break;
                    }                    if (UDPIsPutReady(MySock) >= BUFFER_MAX)
                    {
                        UDPPutArray(line_buffer, BUFFER_MAX);
                        UDPFlush();
                    }
                }
            }            else
            {
                tick--;                if (tick==0)
                {
                    tick = 0x10000;                    if (delay == 0)
                    {
                        delay = BOOT_TIMEOUT;
                        GenUDPSt = SM_CLOSE;
                    }
                    delay--;
                }
            }            break;        case SM_CLOSE:            while (!TXSTAbits.TRMT);
            TXREG='>';
            UDPClose(MySock);
            MySock = INVALID_UDP_SOCKET;
            _asm                goto APP_START
            _endasm            break;
        }
    }


  如何使用 

  1. 使用MCC18编译PhnBoot_v1.0,

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

  3. 拔除pickit3烧录器

  4. 将目标板与PC的接入同一局域网,并设置PC的IP地址和目标板的IP地址为同一网域,打开PhnLoader_v1.0用户界面,选择IP, 端口,和通信协议。

  5. 点击PhnLoader_v1.0用户界面上的“.."按钮加载需要烧录的应用程序Hex文件 (注意:由于PhnBoot_v1.0占用了程序存储器头部0x2400程序字,所以应用程序编译需要设置Code offset为0x2400)。

  6. 重启目标板,接着立刻在PhnLoader_v1.0界面上点击Download按钮。如果超时未点击Download按钮,目标板会自动跳转到上次烧录的应用程序中去。

  7. 烧录完毕,再次重启目标板, 2秒后目标板开始正常运行应用程序。

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

  主要特性

  本PIC ethernet bootloader有以下主要特性

  1. 使用了Microchip免费的TCP/IP Stack,采用UDP协议。

  2. C语言写的,MCC18 编译。

  3. 非常容易移植。

  4. 支持FLASH烧写, 快速,占用空间小。

  5. 可支持EEPROM烧写。

  6. 支持CONFIG BITS/IDLOC 烧写。


关键字:UDP协议  PIC18F97J60  ethernet  bootloader 引用地址:采用UDP协议实现PIC18F97J60 ethernet bootloader

上一篇:采用TCP协议实现PIC18F97J60 ethernet bootloader
下一篇:C语言dsPIC / PIC24 serial bootloader和C#语言bootloader PC端串口通信程

推荐阅读最新更新时间:2024-03-16 15:31

Arduino Atmega328P烧写bootloader及熔丝
0.前言 买到的新的Atmega328P芯片,需要对其烧录bootloader和熔丝才能正常使用,此处记录我烧录的过程。 参考资料1 1.硬件配置 AVR下载器,如图: Atmega328P最小系统,且留出ISP接口,即5V,MISO,MOSI,SCK,GND,RESET 连接AVR和Atmega328P的相应引脚 其中,AVR下载器的实际引脚如图: 2.烧录步骤 2.1.安装AVRDUDESS软件 2.2.检测MCU AVR和Atmega328P连接好之后,把AVR下载器插入电脑。然后打开AVRDUDESS软件,选择如下操作: 正常的话电机Detect后就可以识别出来MCU的型号。但是有可能会遇
[单片机]
Arduino Atmega328P烧写<font color='red'>bootloader</font>及熔丝
atmega168P烧写bootloader
烧写bootloader的方法大体分为两种: 1.使用Arduino IDE烧写bootloader 2.使用USBasp烧写 方法一:使用Arduino IDE烧写 中文教程 我们可以使用另一块Arduino,下载烧录器固件代码,然后连接需要烧写bootloader的单片机芯片进行烧写。 1.硬件连接 图中标记的是Arduino UNO上的ICSP,引脚定义为: 将第一块Arduino的MISO、MOSI、SCK连接至待烧写的单片机芯片的MISO、MOSI、SCK,同时将两者的5V、GND连接在一起,将第一块Arduino板的 pin 10 引脚连接至芯片的RESET引脚 如图所示: 2.使用Arduin
[单片机]
atmega168P烧写<font color='red'>bootloader</font>
freescale飞思卡尔 HCS12 系列单片机bootloader详解(三)
在完成内存映射的内容后,接下来我们将进入一个简单Bootloader的实际设计中来。在第一节内容中,我们已经简单介绍了bootlaoder的作用,它实际上就是在单片机重启过程中的一个步骤:如果有bootloader的启动信号,则进入bootloader模式开始新程序的接收与flash的擦写,若没有bootloader的启动信号,则直接进入用户程序执行用户程序内容。 bootloader的启动信号一般有如下两种: 1)外部引脚接地或者拉高电平;每次启动时先监测某一已经设定的引脚是否已经被操作到了bootloader启动电平位,如果是希望bootloader启动的电平,则需要跳转入bootloader程序,否则直接进入用户程序
[单片机]
基于AVR-BootLoader,通过霜蝉远程串口可实现单片机的远程升级
最近一直利用业余时间写自己的“基于AVR-BootLoader”,启发是由于一次在ourAVR论坛看到了绍子阳的bootloader,联想到公司在用AVR MCU,但每次升级程序都要花费很大的力气车马劳顿的跑到工程现场,而且很多机器还安装在国外,为了升级一次程序发费了很多的人力物力财力,加上公司的机器目前大部分都配有远程监控系统,所以本人决定写一个具有自有产权的“AVR-BootLoader”。 特别说明:本“AVR-BootLoad”软件代码属上海霜蝉版权所有,在此贡献发布,仅限于个人免费使用不得用于商业用途,本人也不保证代码的严谨性,如在升级中出现任何问题与本人无关,本人已测试过Atmega64A与Atmega12
[单片机]
基于AVR-<font color='red'>BootLoader</font>,通过霜蝉远程串口可实现单片机的远程升级
STM32的BootLoader 从SD卡更新固件
1. 前言 2. 初识BootLoader 2.1 百度百科的BootLoader 2.2 BootLoader的简单理解 2.3 BootLoader的作用 3. BootLoader预备知识 3.1 复位序列 3.1.1 栈指针 3.1.2 复位向量 3.2 重定位中断向量表 3.2.1 STM32的中断向量表 3.2.2 设置中断向量表偏移 3.3 分散加载文件相关 3.3.1 C语言的函数地址 3.3.2 BootLoader占用的ROM 3.3.3 修改ROM起始地址 3.4 hex文件和bin文件 3.4.1
[单片机]
STM32的<font color='red'>BootLoader</font> 从SD卡更新固件
STM32F103C8T6用官方bootloader实现IAP升级操作方法
在使用STM32F103C8T6单片机IAP功能时,可以自己写bootloader程序,也可以使用官方bootloader文件。下面说一下使用官方bootloader的使用方法。 首先下载官方bootloader文件 目前使用的是这个版本,打开文件夹,选择适合自己编译器的工程。 目前使用的是keil,所以打开MDK-ARM文件夹 打开IAP工程 打开后根据自己的单片机型号,对工程进行简单的修改。用的是STM32F103C8T6单片机,FLASH为64K,SRAM为20K。 设置IROM1的起始地址和大小。 设置引用的头文件,STM32F103C8T6为中等容量,所以设置文件为STM32F10X_MD,。
[单片机]
STM32F103C8T6用官方<font color='red'>bootloader</font>实现IAP升级操作方法
基于UDP协议的ARM与X86平台之间的通讯方案
  随着人工智能的应用,ARM产品已经遍布到各个领域:工业控制、无线通讯领域、消费类电子产品、成像和安全产品,包括现在流行的数码相机和打印机中绝大部分采用ARM技术,手机中的32位SIM智能卡也采用了ARM技术。除此以外,ARM微处理器及技术还应用到许多不同的领域,并会在将来取得更加广泛的应用,因此,ARM与其它平台之间通讯就显得尤为重要。   1.UDP协议本质   UDP协议是英文User Datagram Protocol的缩写,即用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽
[单片机]
一种新颖Bootloader设计方案
本文基于Microchip公司的MPLAB软件开发环境设计了一种新颖的 Bootloader ,并配套编写了PC机端上位机界面程序。其特点是控制灵活,使用便利,系统升级安全可靠。   1 Bootloader的实现   1.1 Bootloader的操作模式   Bootloader在单片机上电/复位后、用户程序之前先运行,运行后判断当前是否需要进入升级状态。如果不需要升级,就直接运行原有的程序;如果需要升级,首先擦除旧的程序,然后从串口接收用户程序,同时写入Flash中。Bootloader有2种操作模式:   ①启动加载模式,也称为“内核启动”模式。即Bootloader从目标机上的某个固态存储设备上将操作系统加载
[单片机]
一种新颖<font color='red'>Bootloader</font>设计方案
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved