现场升级方案:LPC1788采用U盘方式进行程序IAP升级功能的实现
闲来无事,总结一下前段时间做过的U盘升级项目。一个新手的成长之路在于善于总结,生活也是一样扯远了,我准备了两个软件环境,一个带操作系统(UCOS)的,另一个裸机版的。随后我会附上两个程序代码。U盘升级可以分为两部分代码:U盘读取bin文件和IAP功能两部分。大概说一下实现过程,具体IAP网上都玩坏了。

硬件环境:NXP 1788

软件环境:KEIL

实现过程:上面说了我准备了两个程序,就用裸机版的代码说一下实现流程。带操作系统的原理都是一样的。只是多创建几个任务而已。USB_HOST实现IAP升级,总的思路就是:复制bin文件到U盘->目标板断电,插上U盘->目标板上电,进入升级->运行升级程序。其实可以更具体,比如说设置升级标志或者按键。

拿到一个程序先从main开始,直接贴代码,说一大堆废话有什么用。

int main()
{
  int32_t  rc;
 uint32_t  numBlks,blkSize;
 uint8_t inquiryResult[INQUIRY_LENGTH];

SystemInit();

UART_Init(57600);         
   Host_Init();              
    rc =Host_EnumDev();      
    if (rc ==OK) {
  
       rc = MS_Init( &blkSize, &numBlks, inquiryResult );
       if (rc == OK) {
           rc = FAT_Init();  
           if (rc == OK) {
               Bin_Read();   
           } else {
               return (0);
           }
       } else {
           return (0);
       }
    } else{       
       return (0);
    }
   while(1);
}

下面分模块说一下, 前面的硬件初始化函数很简单,USB设备枚举和FAT文件系统NXP官网上都有,只需改硬件接口,Host_Init函数如下:

void  Host_Init(void)
{
 uint32_t HostBaseAddr;

LPC_SC->PCONP   |=0x80000000;
   LPC_USB->OTGClkCtrl   =0x00000019; 
    while((LPC_USB->OTGClkSt & 0x00000019) != 0x19);
 
 LPC_USB->StCtrl =0x1;

LPC_IOCON->P0_29 &= ~(0x07UL << 0);
   LPC_IOCON->P0_30 &= ~(0x07UL << 0);
   LPC_IOCON->P1_28 &= ~(0x07UL << 0);
   LPC_IOCON->P1_29 &= ~(0x07UL << 0);

LPC_IOCON->P0_29 |= 0x01UL <<0;                                   
   LPC_IOCON->P0_30 |= 0x01UL <<0;                                   
   LPC_IOCON->P1_28 |= 0x01UL <<0;                                   
   LPC_IOCON->P1_29 |= 0x01UL <<0;                                   //  P1.29 --USB_SDA1     
   PRINT_Log("Initializing HostStack\n");

HostBaseAddr = HOST_BASE_ADDR;

Hcca      = (volatile HCCA      *)(HostBaseAddr+0x000);
   TDHead    = (volatile HCTD      *)(HostBaseAddr+0x100);
   TDTail    = (volatile HCTD      *)(HostBaseAddr+0x110);
   EDCtrl    = (volatile HCED      *)(HostBaseAddr+0x120);
   EDBulkIn   =(volatile HCED      *)(HostBaseAddr+0x130);
   EDBulkOut  = (volatile HCED      *)(HostBaseAddr+0x140);
   TDBuffer   =(volatile  uint8_t *)(HostBaseAddr+0x150);
   FATBuffer  = (volatile  uint8_t*)(HostBaseAddr+0x1D0);
    UserBuffer =(volatile  uint8_t*)(HostBaseAddr+0x1000);

Host_EDInit(EDCtrl);
   Host_EDInit(EDBulkIn);
   Host_EDInit(EDBulkOut);
   Host_TDInit(TDHead);
   Host_TDInit(TDTail);
   Host_HCCAInit(Hcca);

Host_DelayMS(50);               
   LPC_USB->Control      = 0;   
   LPC_USB->ControlHeadED =0;   
   LPC_USB->BulkHeadED   = 0;   
   
   
   LPC_USB->CommandStatus = OR_CMD_STATUS_HCR;
   LPC_USB->FmInterval   = DEFAULT_FMINTERVAL;

LPC_USB->Control  = (LPC_USB->Control &(~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
   LPC_USB->RhStatus =OR_RH_STATUS_LPSC;       
   
   LPC_USB->HCCA = (uint32_t)Hcca;
   LPC_USB->InterruptStatus |=LPC_USB->InterruptStatus;

LPC_USB->InterruptEnable  = OR_INTR_ENABLE_MIE|
                        OR_INTR_ENABLE_WDH |
                        OR_INTR_ENABLE_RHSC |
                        OR_INTR_ENABLE_UE;

NVIC_EnableIRQ(USB_IRQn);              
 NVIC_SetPriority (USB_IRQn,0);

PRINT_Log("Host Initialized\n");
}

这段主要是USB引脚配置和USB主机初始化。Bin_Read()函数如下:

void  Bin_Read(void)
{
     int32_t  fdr;
     uint32_t  bytes_read,writelen;
     uint32_t dstaddr;
     SelSector(APP_START_SECTOR,APP_END_SECTOR);        //选择扇区
     EraseSector(APP_START_SECTOR,APP_END_SECTOR);                         
     BlankCHK(APP_START_SECTOR,APP_END_SECTOR);                            
     SelSector(APP_START_SECTOR,APP_END_SECTOR);    
     PRINT_Log("\r\nstart file operations...\r\n");

fdr = FILE_Open(FILENAME_R, RDONLY);
    if (fdr >0) {
       PRINT_Log("Reading from %s...\n", FILENAME_R);
  for(writelen=0;writelen<(APP_END_ADDR-APP_START_ADDR)/1024;writelen++)
   {
    bytes_read =FILE_Read(fdr, UserBuffer,MAX_BUFFER_SIZE);           
    dstaddr=  (uint32_t)(APP_START_ADDR +(writelen)*1024);//dst address.  
   SelSector(APP_START_SECTOR,APP_END_SECTOR);    
   RamToFlash(dstaddr,(uint32_t)UserBuffer, 1024);
   Compare(dstaddr, (uint32_t)UserBuffer, 1024);
   }  
  // printf("%x",writelen);
  PRINT_Log("\r\n write filesuccessful\r\n");
   SCB->VTOR  =APP_START_ADDR;                                             
   ExceuteApplication();                                                      
   FILE_Close(fdr);                                                            
    } else{
       PRINT_Log("\r\n write file failed\r\n");
    }
}

上面的代码可以分为两部分:1.从U盘读取bin文件2.IAP功能。先说IAP部分,IAP实现方法有UART,GPRS,USB等方式。要进行IAP设计,先划分FLASH扇区。LPC1788的FLASH划分如下:


 
将flash划分为两个区,bootloader和APP区,bootloader存放升级引导程序,即我们的USB_HOST_IAP代码,根据具体的Code大小确定bootloader的扇区,APP就是用户程序即需要升级的程序代码。APP需要配置后面再说。这是我的扇区划分:
#define    IAP_START_ADDR 0x00000000                                 // IAP开始地址
#define    IAP_LOCATION    0x1FFF1FF1

#defineAPP_START_ADDR      0x00A000             // 用户程序起始地址
#defineAPP_END_ADDR       0x78000               //LPC1788 512KFlash         
//#defineAPP_SIZE      0x10000

#defineAPP_START_SECTOR     10
#defineAPP_END_SECTOR        29                  // LPC1788  512K Flash扇区

下面分别概括一下实现IAP命令的函数,IAP功能命令有准备编程扇区,复制RAM到FLASH,擦除扇区,扇区查空,读器件ID,读BOOT代码版本,比较等指令。程序要进行IAP升级,必须要先选择扇区擦除扇区之后才能写进Flash。先需要定义系统时钟,参数和一些变量。
#define    IAP_FCCLK      48000 
uint32_t   paramin[8];                                             
uint32_t   paramout[8];                                              
unsigned long command[5];
unsigned long result[5];
typedef void (*IAP) (unsigned int [ ] , unsigned int []);      
写数据之前,必须要选择需要写入的扇区,选择扇区部分代码:
uint32_t   SelSector(uint8_t   sec1,uint8_t   sec2)
{
    paramin[0] =IAP_SELECTOR;                                         
    paramin[1] =sec1;                                                 
    paramin[2] =sec2;
   (*(void(*)())IAP_LOCATION)(paramin,paramout);                     
   return(paramout[0]);                                               
}
选中扇区之后,要检查该扇区是否已经有数据,所以要擦除扇区,附代码:
uint32_t   EraseSector(uint32_t sec1, uint32_t sec2)
{
    paramin[0] =IAP_ERASESECTOR;                                      
    paramin[1] =sec1;                                                 
    paramin[2] =sec2;
    paramin[3] =IAP_FCCLK;
   (*(void(*)())IAP_LOCATION)(paramin,paramout);                     
   return(paramout[0]);                                               
}
下来就是向flash写入数据,flash起始地址必须以256字节为分界,调用函数
uint32_t   RamToFlash(uint32_t dst, uint32_t src, uint32_t no)
{
    paramin[0] =IAP_RAMTOFLASH;                                       
    paramin[1] =dst;                                                  
    paramin[2] =src;
    paramin[3] =no;
    paramin[4] =IAP_FCCLK;
   (*(void(*)())IAP_LOCATION)(paramin,paramout);                     
   return(paramout[0]);                                               
写完之后要进行比较,将RAM读出来的数据和写入到flash的数据进行比较,注意flash起始地址必须字对齐,字节个数必须能被4整除,当源或目标地址包含从地址0开始的前64个字节中的任意一个地址时, 比较的结果可能不准确。因为前64个字节可被重新映射到RAM:
uint32_t   Compare(uint32_t   dst, uint32_t   src, uint32_t   no)
{
    paramin[0] =IAP_COMPARE;                                          
    paramin[1] =dst;                                                  
    paramin[2] =src;
    paramin[3] =no;
   (*(void(*)())IAP_LOCATION)(paramin,paramout);                     
   return(paramout[0]);                                               
还有ExceuteApplication()部分的代码,程序写入flash之后,要重新映射向量表,从bootloader跳转到APP执行,这就要获取程序的入口地址和SP堆栈的值。如下:

__asm void ExceuteApplication(void)
{
  ldr r0, =0x00A000
  ldr r0, [r0]
  mov sp, r0
  ldr r0, =0x00A004
  ldr r0, [r0]
       BX  r0
}

最后关闭文件系统,main里面最主要读取bin文件调用IAP功能的Bin_Read()函数说完了。最后说一下APP程序产生bin文件的配置。
KEIL中Target Options配置:
1.将程序入口定位到App即用户程序的入口地址;2.User选项:Run#1填写产生bin文件路径:C:\Keil\ARM\ARMCC\bin\fromelf.exe--bin --outputoutput\FLASH\test.binoutput\FLASH\LPC177x_8x.axf;3.C/c++选项:Optimization选择高优先级:Level3;4.Asm选项:Define填NO_CRP;不产生空文件夹5.Linker选项:勾选UseMemory layout from TargetDialog.整个工程就算建立起来了。附两个版本的代码,仅限参考:

裸机版:http://download.csdn.net/download/u012246376/8453395 

带操作系统UCOS版本:http://download.csdn.net/download/u012246376/8453349

更多技术文章浏览请关注:

百家号:
https://author.baidu.com/home?context=%7B%22app_id%22%3A%221646108714303504%22%7D&wfr=bjh

头条号:
https://www.toutiao.com/c/user/8115738721/#mid=1646025109246987



现场升级方案:LPC1788采用U盘方式进行程序IAP升级功能的实现相关推荐

  1. Cisco1100 lic激活+采用U盘方式升级版本

    一.设备插电源,开机,插console线,插U盘. show ver 得知版本不是稳定版本,所以先将版本降级.(采用U盘的方式) dir usb0: copy usb0:/名称 conf t boot ...

  2. python语言采用编译执行方式_Python程序的执行过程 解释型语言和编译型语言

    我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在.如果是解释型语言,那么生成的*.pyc文件是什么呢?c应 ...

  3. 剖析MCU的IAP升级软件设计思路

    关注.星标公众号,不错过精彩内容 转自公号:最后一个bug 二次整理:strongerHuang 做软件开发的人,都知道程序升级.升级的方式有很多,今天就来讲讲升级的软件的设计思路. 一.ISP/IC ...

  4. 基于串口通信的DSP应用程序在线升级方法

    摘  要:为解决特殊场合DSP程序升级困难的问题,以TMS320F28035为例,介绍了一种基于串口通信的适合于TMS320C2000系列DSP实现程序更新的在线升级方法.描述了该在线升级方法的基本思 ...

  5. 采用存储复制方式同步数据,实现数据库安全升级

    2017年年初,海天起点为某省中行机房搬迁工作保驾护航.在机房搬迁过程中发现有多套数据库需要升级到11g,但由于有些数据库比较老旧,升级过程不能一次性完成,需要先升级到一个中间版本,再升级到最终目标版 ...

  6. 基于数字孪生的数字化车间升级方案

    本文根据数字化车间升级的理论与实践,具体阐述基于数字孪生运行模式的数字化车间 的升级方案与具体实现. 1    技术理论成果概述 1.1    数字孪生车间运行模式 世界各个制造大国提出的制造业国家战 ...

  7. 杂谈---嵌入式(单片机、arm)在线升级方案

    描述 最近不少人问我如何给单片机升级,如何给arm板升级.也有些人说网上很多工具可以参考或者移植.我当时回答时,如果做功能,自己想怎么玩即可,如果要做成量化的产品最好自己做一套协议. 因为应用场合不同 ...

  8. 传统数据中心升级方案

    一.引言 云计算是近年来发展最快的互联网技术,被称为第四次IT革命.IT应用服务将建立在云计算架构之上.作为云计算核心的基础设施,数据中心在网络中所扮演的角色将更加重要.云计算数据中心正在逐渐取代传统 ...

  9. 我的docker随笔28:基于容器的升级方案实验

    本文涉及: 在容器化场合中,如何更快升级.涉及2方面: docker镜像的设计. 升级方案. docker镜像设计 充分利用docker镜像分层机制,减小升级的体积,减少流量消耗. 基础镜像设计 基础 ...

最新文章

  1. Bhaskar Chowdhury: Kernel build failed ...SPHINX extension error
  2. SQL Server 数据库的维护(一)__存储过程(procedure)
  3. redis系列:通过队列案例学习list命令 1
  4. .Net Core控制台amp;EFCore连接Mysql
  5. c++ 初始化列表和构造函数初始化区别
  6. 自定义刻度_想为 Apple Watch 打造自定义表盘,试试这款 App
  7. SaltStack配置管理之Gains与State测试
  8. Canonical发布企业级Kubernetes 1.14重点让使用者简单管理
  9. 【LeetCode】【字符串】题号:*640. 求解方程
  10. c语言感叹号和逗号标红,感叹号不够用?试试感叹逗号
  11. 智能分层、满足更高工作负载,亚马逊云科技加速云端存储服务创新
  12. Qt 多线程bug:moc_widget.cpp:-1: error: undefined reference to `Mythread::~Mythread()‘:-1:
  13. 体脂秤模块的原理和基本功能说明
  14. 2020最实用115个Java面试题及面向对象的能力汇总合集
  15. 汽车零部件-线控底盘
  16. AD出现 “Net Tie failed verification”如何解决?
  17. 关于lightning2.0更新
  18. 沙鲁克汗机器人_沙鲁克汗2011年最新电影Ra One 印度又一科幻大作
  19. 建模计算机模拟框图,数学建模报童问题
  20. 地平线战投后 这家智能驾驶“新星”又获国电投“大平台”强劲助力

热门文章

  1. Address Sanitizer定位内存问题
  2. 大数据开发工程师之SQL面试题(一)
  3. SkeyePlayer RTSP/RTMP流播放器库API接口说明
  4. ROS操作系统 opencv-python读取摄像头+rviz可视化
  5. 光纤激光切机计算机无法启动,激光切割机不出光原因及解决办法
  6. ArcGIS应用(十九)Arcgis 统计分析计算多波段图像最大值、最小值、平均值等
  7. AD域根据用户名称获取DirectoryEntry对象
  8. 库仑微压分析仪测定水含量两种方法的差异
  9. Java向上转型和向下转型
  10. MATLAB遗传算法例子一