了解bootloader的实现,请加QQ: 1273623966 (验证填bootloader);欢迎咨询或定制bootloader;我的博客主页www.cnblogs.com/geekygeek

今年国庆完成了4个bootloader,前面介绍了2个,都是PIC32MZ的USB bootloader, 接着介绍2个PIC24 的USB bootloader, 首先是PIC24 USB CDC bootloader。PIC24 USB CDC bootloader 是我开发给我的PIC24FJ256GB106硬件板子的。

开发环境

1. IDE: MPLABX v4.01

2. Compiler: XC16, v1.11

3. Library&Example: c:/microchip_solutions_v2013-06-15/USB/Device-CDC-Basic Demo

这个PIC24 CDC bootloader 是在MLA_v2013-06-15的USB CDC basic demo的基础上修改而成。bootloader 占用空间从0x400开始, 长度= 0x1C00。 CDC bootloader模拟UART通信,一行一行接收串口发送过来的hex原文,然后对每行的hex原文进行解析,将里面的bin数据烧写到对应的地址上。整个的逻辑实现都在我写的Boot_DoProcess()函数中,函数代码如下。

uint8_t BOOT_DoProcess(uint8_t *buffer, uint16_t byteCount)
{
uint8_t i; uint8_t bcount, recType;
DWORD_VAL pData;
uint8_t retVal = 0;
if (byteCount == 64)
{
return 1;
}
bcount = GetXbyte(buffer[LEN_NIBBLE1_INDEX],buffer[LEN_NIBBLE2_INDEX]); if (!Checksum(buffer, bcount))
{
retVal = 2;
return retVal;
} srcAddress.v[1] = GetXbyte(buffer[ADDRH_NIBBLE1_INDEX],buffer[ADDRH_NIBBLE2_INDEX]);
srcAddress.v[0] = GetXbyte(buffer[ADDRL_NIBBLE1_INDEX],buffer[ADDRL_NIBBLE2_INDEX]);
srcAddress.Val >>= 1;
recType = GetXbyte(buffer[TYPE_NIBBLE1_INDEX],buffer[TYPE_NIBBLE2_INDEX]);
switch(recType)
{
case LINEAR_ADDRESS:
srcAddress.v[3] = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1],buffer[TYPE_NIBBLE2_INDEX+2]);
srcAddress.v[2] = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+3],buffer[TYPE_NIBBLE2_INDEX+4]);
retVal = 3;
break;
case DATA:
if ((srcAddress.Val >= BOOT_START_ADDRESS) && (srcAddress.Val < APPL_RESET_ADDRESS)) // boot protection, avoid to overlap
{
retVal = 4;
return retVal;
}
eraseAddress.Val = srcAddress.Val;
if ((srcAddress.Val % ERASE_BLOCK) == 0)
{
NVM_EraseBlock(eraseAddress.Val);
}
for (i=0; i < 2*bcount;)
{
pData.byte.LB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+0],buffer[TYPE_NIBBLE2_INDEX+1+i+1]);
pData.byte.HB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+2],buffer[TYPE_NIBBLE2_INDEX+1+i+3]);
pData.byte.UB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+4],buffer[TYPE_NIBBLE2_INDEX+1+i+5]);
pData.byte.MB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+6],buffer[TYPE_NIBBLE2_INDEX+1+i+7]);
unsigned int error = NVM_WriteWord(srcAddress.Val, pData.Val);
if ((error & 0x2000) > 0)
{
retVal = 5;
return retVal;
}
error = 0;
srcAddress.Val += 2;
i += 8;
}
//retVal = 1;
break;
case END:
retVal = 6;
break;
}
return retVal;
}

在main.c中ProcessIO()函数中调用Boot_DoProcess(). ProcessIO改动很大,代码如下。

void ProcessIO(void)
{
BYTE numBytesRead;
WORD status;
//Blink the LEDs according to the USB device status
BlinkUSBStatus();
// User Application USB tasks
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; if(buttonPressed)
{
if(stringPrinted == FALSE)
{
if(mUSBUSARTIsTxTrfReady())
{
putrsUSBUSART("Button Pressed -- \r\n");
stringPrinted = TRUE;
}
}
}
else
{
stringPrinted = FALSE;
} if(USBUSARTIsTxTrfReady())
{
numBytesRead = getsUSBUSART(USB_Out_Buffer,64);
if(numBytesRead != 0)
{
BYTE i;
BYTE j;
for(i=0;i<numBytesRead;i++)
{
switch(USB_Out_Buffer[i])
{
case 0x0A:
case 0x0D:
USB_In_Buffer[i] = USB_Out_Buffer[i];
if (!BOOT_Handshake)
{
BOOT_Handshake = 1;
}
else
{
if ((BOOT_RecordSOF == 1) && (BOOT_RecordEOF == 0))
{
BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
BOOT_RecordEOF = 1;
for (j=0; j<BOOT_RecordCounter; j++)
{
BOOT_OperationBuffer[j] = BOOT_RecordBuffer[j];
}
BOOT_OperationCounter = BOOT_RecordCounter;
BOOT_RecordLineFlag = 1;
BOOT_RecordSOF = 0;
BOOT_RecordEOF = 0;
BOOT_RecordCounter = 0;
}
}
break;
case ':':
USB_In_Buffer[i] = USB_Out_Buffer[i];
if (BOOT_Handshake)
{
if (!BOOT_RecordSOF)
{
BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
BOOT_RecordSOF = 1;
}
}
break;
default:
USB_In_Buffer[i] = USB_Out_Buffer[i];
if ((BOOT_Handshake == 1) && (BOOT_RecordSOF == 1))
{
BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
if (BOOT_RecordCounter == BOOT_RECORD_MAX)
{
BOOT_RecordEOF = 1;
for (j=0; j<BOOT_RecordCounter; j++)
{
BOOT_OperationBuffer[j] = BOOT_RecordBuffer[j];
}
BOOT_RecordLineFlag = 1;
BOOT_OperationCounter = BOOT_RecordCounter;
BOOT_RecordSOF = 0;
BOOT_RecordEOF = 0;
BOOT_RecordCounter = 0;
}
}
break;
}
}
putUSBUSART(USB_In_Buffer,numBytesRead);
if (BOOT_RecordLineFlag)
{
if (BOOT_OperationCounter == BOOT_RECORD_MAX)
{
putUSBUSART("XXXXXXXXXXXXXXXX\r\n", 18);
}
else
{
status = BOOT_DoProcess(BOOT_OperationBuffer, BOOT_OperationCounter);
if (status == 6)
{
//TODO Deinitialization
(*((void(*)(void))APPL_RESET_ADDRESS))();
}
else
{
//putUSBUSART("\r", 1);
}
}
BOOT_RecordLineFlag = 0;
}
}
if (!BOOT_Handshake)
{
BOOT_Timeout--;
if (BOOT_Timeout == 0)
{
// TODO Jump to Application
// TODO Deinitialization
(*((void(*)(void))APPL_RESET_ADDRESS))();
}
else if (BOOT_Timeout%20000 == 0)
{
putUSBUSART(".", 1);
}
}
else
{
if (!BOOT_ProgramRequired)
{
BOOT_ProgramRequired = 1;
putUSBUSART("\r\n",2);
}
}
}
CDCTxService();
} //end ProcessIO

整个CDC bootloader就完成了。合着bootloader的Linker script编译完成后,通过PICKit3烧写到硬件板子中。CDC是模拟UART通信,所以通过USB线连接到电脑,电脑可以侦测到COM口。

接着就是测试bootloader的功能了。写了个测试用的应用程序,应用程序地址是从0x2000开始到结束(地址分配参考AN1094)。应用程序合着客制的Linker script编译。测试时,我是通过超级终端发送应用程序的Hex原文。重启目标板,打开超级终端,选择CDC 模拟的COM口,配置成9600-8-none-1. 设置Line delay=40ms. 超级终端窗口出现”..."字符后,窗口中按下回车,菜单栏选择“发送文本文件”, 加载应用程序Hex, ,点击发送。然后就等着烧写完成。(上面贴的都是最终可以使用的完成函数代码,但是在实现过程中,修改几次,特别是测试过程中,发现不少问题,修改代码一一解决之后才最后完成)

以下是烧写步骤:

1. 打开超级终端

2. 重启烧录好CDC bootloader的目标板

3. 超级终端配置,选择CDC emulating后的出现的COM口,设置成9600-8-none-1, 设置Line Delay.

4. 一旦超级终端窗口出现”..."字符,立即发送回车。

5. 点击发送/发送文本文件..., 选择要发送的hex文件。

6. 等待升级完成,CDC bootloader 每接收完一行都会原文返回。

PIC24 通过USB在线升级 -- USB CDC bootloader的更多相关文章

  1. PIC32MZ 通过USB在线升级 -- USB CDC bootloader

    了解bootloader 的实现,请加QQ: 1273623966 (验证填 bootloader):欢迎咨询或定制bootloader:我的博客主页www.cnblogs.com/geekygeek ...

  2. PIC32MZ 通过USB在线升级 -- USB HID bootloader

    了解 bootloader 的实现, 请加QQ: 1273623966(验证填bootloader); 欢迎咨询或定制bootloader; 我的博客主页 www.cnblogs.com/geekyg ...

  3. PIC24 通过USB在线升级 -- USB HID bootloader

    了解bootloader的实现,请加QQ: 1273623966 (验证填bootloader):欢迎咨询或定制bootloader; 我的博客主页www.cnblogs.com/geekygeek ...

  4. PIC32MZ 通过U盘在线升级 -- USB Host bootloader

    了解bootloader的实现,请加QQ: 1273623966(验证填bootloader); 欢迎咨询或定制bootloader; 我的博客主页 www.cnblogs.com/geekygeek ...

  5. Encrypting bootloader (程序BIN文件加密及在线升级)

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

  6. Encrypted bootloader (程序BIN文件加密及在线升级)

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

  7. nrf52——DFU升级USB/UART升级方式详解(基于SDK开发例程)

    摘要:在前面的nrf52--DFU升级OTA升级方式详解(基于SDK开发例程)一文中我测试了基于蓝牙的OTA,本文将开始基于UART和USB(USB_CDC_)进行升级测试. 整体升级流程: 整个过程 ...

  8. dsp 28377在线升级 实例总结

    使用dsp品台28377d来实现在线升级的功能. 方案 : 升级程序  +  应用程序 升级程序 : 主要的目的是将上位机发送过来的应用程序数据(ccs编译生成的.bin文件)烧写到指定位置,之后在跳 ...

  9. STM32 IAP 在线升级详解(转)

    源:http://blog.csdn.net/yx_l128125/article/details/12992773 (扩展-IAP主要用于产品出厂后应用程序的更新作用,考虑到出厂时要先烧写IAP   ...

随机推荐

  1. Android进阶笔记13:ListView篇之ListView刷新显示(全局 和 局部)

    一.ListView内容变化后,动态刷新的步骤(全局刷新): (1)更新适配器Adapter数据源:(不要使用匿名内部类) (2)调用适配器Adapter的刷新方法notifyDataSetChang ...

  2. 【转】应用程序的入口是ActivityThread

    ActivityThread运行框架 在分析中,我们可以看到真正对应应用进程的不是Application而是ActivityThread.我们从实际的应用堆栈可以看到: NavitiveStart.m ...

  3. PHP面试题分享与答案

    由于之前的每一个问题都是一个比较大的知识点,作者希望可以尽量一一详细解答,如果有不足的地方欢迎大家补充和修改,同时借鉴牛人写的Mysql中算法的实现以及内存原理,Btree结构等. 1:MySQL数据 ...

  4. ASP.NET Web API 自定义MediaType实现jsonp跨域调用

    代码来自<ASP.NET Web API 2 框架揭秘>一书. 直接上代码: /// <summary> /// 自定义jsonp MediaType /// </sum ...

  5. 随便扯扯React生命周期 --《爱看不看系列》

    生命周期嘛,顾名思义,就是说组件这辈子从生下来到死掉经历的事情.先来看看一张图片,温故温故,如图: 你会发现有些周期的名字都能找出点规律,我找到的规律是凡是 Will 字母的,表示该钩子函数会在该生命 ...

  6. 怎么得到scrollTop

    我们学习一个事件 :  页面滚动效果 window.onscroll = function() { 页面滚动语句  } 谷歌浏览器 和没有声明 DTD  <DOCTYPE     > : ...

  7. Vue nodejs商城项目-商品列表页面组件

    data(){        return {            goodsList:[], // 商品列表            priceFilter:[ // 价格区间数组          ...

  8. 配置隐私协议 - iOS

    根据苹果隐私协议新规的推出,要求所有应用包含隐私保护协议,故为此在 App 中添加了如下隐私协议模块. 首次安装 App 的情况下默认调用隐私协议模块展示相关信息一次,当用户点击同意按钮后,从此不再执 ...

  9. [SCOI2009]windy数(数位DP)

    题目描述 windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? 输入输出格式 输 ...

  10. Docker 入坑教程笔记

    Docker 入坑教程笔记 视频网址B站:点这里 查询命令 man docker 简单启动和退出 docker run --name [容器名] -i -t ubuntu /bin/bash 交互启动 ...