自从传闻ARM要出售给美国公司,本人内心的不安全感促使我寻找ARM架构单片机的替代产品。网上问了些网友,有推荐GD32VF103,于是花了些时间了解这个系列的MCU,发现其实也还行,这个MCU跟GD32F103很像,RAM, ROM,外设,封装都差不多。虽说开发环境有些不太熟,不过花些心思,也能使用,至少,比51单片机好用多了。

因为官方Firmware没有IAP方面的内容,所有这篇文章专门讲讲此单片机如何进行IAP,毕竟实际工作应用中会经常使用。

一.开发环境。

我使用的IDE是Nuclei Studio IDE,这个是芯莱科技基于 MCU Eclipse IDE 开发的一款针对芯来公司处理器核产品的集成开发环境工具。GD32VF103也是这家这家公司联合兆易创新推出的。

IDE下载地址为:https://www.nucleisys.com/download.php

我使用的开发板是一款只需要30几块钱的带彩屏的开发板,非常小,MCU型号是GD32VF103CBT6。开发板型号叫longan nano

,资料下载地址为:https://dl.sipeed.com/LONGAN/Nano/

二.原理

回顾并参考STM32F1系列的IAP过程:

1.接收APP镜像数据,并将其写入对应Flash地址。

2.设置SP(堆栈指针)

3.设置PC(也就是跳转至APP特定地址)。

4.APP本身需要设置中断入口的地址偏移。

由于STM32F1XX复位后,硬件自动从特定地址获取SP和PC,所有启动文件不会再次设置SP。所有,当我们用C语言写IAP程序,反而需要模拟此过程,需要设置SP。

对于GD32VF103,复位后硬件本身并不会进行类似操作。也就是说,设置SP本身是启动文件必须的功能,无需C程序再次设置。其实不止SP,还有GP等。可以查看启动文件(一般命名为startup_xxx.s)和链接文件(.ld)了解其过程。

三.代码实现

1.IAP

由于我买的开发板有个TF卡座,所有我通过TF进行IAP。

#ifndef __IAP_H
#define __IAP_H#define FMC_PAGE_SIZE     0x400
#define APP_STARTADDR    0x08010000
#define APPPATH_STR      "0:/SYS/APP.BIN"uint8_t iap_all(void);#endif  
#include "nuclei_sdk_soc.h"
#include "iap.h"
#include "lcd.h"
#include "./fatfs/ff.h"            /* Declarations of FatFs API */
#include <stdio.h>
#include <string.h>//保存读到的文件数据
uint32_t filebuf[FMC_PAGE_SIZE/2];/*!\brief    erase fmc pages in addr \param    addr : fmc addr\retval   none
*/
void fmc_erase_onepage(uint32_t addr )
{uint32_t erase_counter;// unlock the flash program/erase controller fmc_unlock();// clear all pending flags fmc_flag_clear(FMC_FLAG_END);fmc_flag_clear(FMC_FLAG_WPERR);fmc_flag_clear(FMC_FLAG_PGERR);// erase the flash page fmc_page_erase( addr );fmc_flag_clear(FMC_FLAG_END);fmc_flag_clear(FMC_FLAG_WPERR);fmc_flag_clear(FMC_FLAG_PGERR);// lock the main FMC after the erase operation fmc_lock();
}/*!\brief      program for one page\param      addr\param         buf\retval     none
*/
void fmc_program_onepage( uint32_t addr , uint32_t *buf )
{uint16_t i;for( i=0; i<FMC_PAGE_SIZE; i+=4 ){if( *(uint32_t*)(addr+i) != 0xFFFFFFFF ){break;}}if( i != FMC_PAGE_SIZE ){fmc_erase_onepage(  addr ) ;}// unlock the flash program/erase controller fmc_unlock();//adjust addraddr-=(addr%FMC_PAGE_SIZE);// program flash for( i=0; i<FMC_PAGE_SIZE; i+=4 ){fmc_word_program( addr+i, buf[i/4] );fmc_flag_clear(FMC_FLAG_END);fmc_flag_clear(FMC_FLAG_WPERR);fmc_flag_clear(FMC_FLAG_PGERR);}// lock the main FMC after the program operationfmc_lock();
}/*!\brief        对比内容是否相同\param        appxaddr:flash地址\param        data:内存地址\param        size:要比较的大小\retval        1:完全相同;0:不一致
*/
uint8_t iap_cmp(uint32_t appxaddr,uint32_t *data,uint32_t size)
{uint32_t i;if(size==0)return 1;for(i=0;i<size;i+=4){    if( *(uint32_t*)(appxaddr+i)  != data[i/4] ){return 0;}} return 1 ;}/*!\brief      过程:读文件,判断版本,写Flash,检查是否一致,显示进度,判断完整性,显示结果。\param      none\retval     0:成功 ;Other:没有成功
*/
uint8_t iap_all(void)
{    FIL appfile;FILINFO fileinfo;uint8_t res = 0 ;char * ptr = (char *)filebuf;printf( "open appfile:" );if( f_open( &appfile,APPPATH_STR ,FA_READ ) == FR_OK ){    uint16_t  i=0;uint32_t  tlen=0;UINT  br=0;f_stat( (char*) APPPATH_STR ,&fileinfo );printf("ok,file size :%d\r\n",fileinfo.fsize);LCD_ShowString(0,8,"App Upd:",RED);LCD_ShowString(2,8+16,"Prog:   %",RED);LCD_ShowNum( 0,16*4, fileinfo.fsize  ,8,BLACK) ;printf("\r\nRead appfile data:\r\n");res=0;if(  fileinfo.fsize >= FMC_PAGE_SIZE ){for( i=0; i<(fileinfo.fsize/FMC_PAGE_SIZE); i++ ){memset(ptr,0xff,FMC_PAGE_SIZE);res = f_read( &appfile, ptr , FMC_PAGE_SIZE/2 ,&br);if(  res   ){printf("appfile read error\r\n");res = 0x02 ;break;}else{tlen+=br;if( i==0){   //把版本号放在APP_STARTADDR+4,这里比较,如果相同则不更新APPif( filebuf[1] == *(uint32_t*)(APP_STARTADDR+4) ){res |= 0x10;break;}//LCD_ShowNum( 8*9,8  , filebuf[1] ,8,RED) ;}res = f_read( &appfile, ptr+512 , FMC_PAGE_SIZE/2 ,&br);tlen+=br;fmc_program_onepage( APP_STARTADDR+i*FMC_PAGE_SIZE, filebuf );if ( iap_cmp(APP_STARTADDR+i*FMC_PAGE_SIZE , filebuf ,br ) ){printf( "iap prog:%d%%\r\n", (uint32_t)(i*100/(fileinfo.fsize/FMC_PAGE_SIZE) +0.5 ) );LCD_ShowNum( 2 +8*5,8+16  , (uint32_t)(i*100/(fileinfo.fsize/FMC_PAGE_SIZE) )+0.5 ,3,RED) ;} else {res = 0x03;printf("cmp err\r\n" );break;}}}}//最后不够FMC_PAGE_SIZE的部分if( res==0 && fileinfo.fsize%FMC_PAGE_SIZE){memset( ptr,0xff,FMC_PAGE_SIZE);res = f_read( &appfile, ptr , FMC_PAGE_SIZE/2 ,&br);if(  res   ){printf("appfile read error\r\n");res = 0x02 ;}else{if( i==0 ){//把版本号放在APP_STARTADDR+4,这里比较,如果相同则不更新APPif( filebuf[1] == *(uint32_t*)(APP_STARTADDR+4) ){res |= 0x10;}}if( !res ){tlen+=br;res = f_read( &appfile, ptr+512 , FMC_PAGE_SIZE/2 ,&br);tlen+=br;LCD_ShowNum( 2 +8*5,8+16  , (uint32_t)(i*100/(fileinfo.fsize/FMC_PAGE_SIZE) ) ,3,RED) ;fmc_program_onepage( APP_STARTADDR+i*FMC_PAGE_SIZE, filebuf );if ( iap_cmp(APP_STARTADDR+i*FMC_PAGE_SIZE , filebuf ,br ) ){printf( "iap prog:%d%%\r\n", (uint32_t)(i*100/(fileinfo.fsize/FMC_PAGE_SIZE) +0.5 ) );LCD_ShowNum( 2 +8*5,8+16  , (uint32_t)(i*100/(fileinfo.fsize/FMC_PAGE_SIZE) )+0.5 ,3,RED) ;}else{res = 0x03;printf("cmp err\r\n" );}}}}printf( "\r\nreaded data size:%d\r\n",tlen );f_close(&appfile); LCD_ShowNum( 8*10,8  ,  tlen ,8,BLACK) ;if( res==0 && tlen == fileinfo.fsize ){ //res = f_unlink(APPPATH_STR);  //del fileLCD_ShowString(0,16*3,"iap ok!",BLUE);printf("IAP ok,res:%d\r\n",res );}else if( res&0x10 ){res=0;printf("version same\r\n" );LCD_ShowString(0,16*3,"version same!",BLUE);}else{res |= 0x80;printf("iap fail\r\n" );LCD_ShowString(0,16*3,"iap fail!",BLUE);}}else{res = 0x01 ;printf("No appfile\r\n" );}return res;
}

上面会进行文件版本判断。文件版本放在镜像文件的第二个“字”,可以直接在启动文件里设置。

2.APP

写一个待验证app程序,例如定时器控制流水灯什么的,最好带中断,以便验证。

注意一点,需要在链接脚本文件里面修改起始地址。

/********************* Flash Configuration ************************************* <h> Flash Configuration* <o0> Flash Base Address <0x0-0xFFFFFFFF:8>* <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>* </h>*/
__ROM_BASE = 0x08000000;
__ROM_SIZE = 0x00020000;

修改为

/********************* Flash Configuration ************************************* <h> Flash Configuration* <o0> Flash Base Address <0x0-0xFFFFFFFF:8>* <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>* </h>*/
__ROM_BASE = 0x08010000;
__ROM_SIZE = 0x00010000;

注意要保证__ROM_BASE不能小于IAP程序代码大小,并且剩余flash空间足够放得下APP程序代码。

跳转指令:

 ((void(*)())(0x08010000))();

保险起见,跳转前关全局中断。

__disable_irq();

下图为测试图:IAP成功后跳转至APP。

GD32VF103 IAP测试

RISC-V架构单片机GD32VF103:IAP功能相关推荐

  1. RISC V (RV32+RV64) 架构 整体介绍

    文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...

  2. 【genius_platform软件平台开发】第八十八讲:arm公司的V架构和内核发展史(整理)

    1. ARM公司简介 ARM(Advanced RISC Machines)有三种含义:它是一个公司的名称.它是一类微处理器的通称.它是一种技术的名称. ARM 公司是微处理器行业的一家知名企业,它是 ...

  3. STM32实现IAP功能之一

    最近因项目需求要实现STM32的在线升级即IAP功能,先将这几天的学习体会和IAP的具体实现总结出来,分享给大家,希望对同样实现IAP的童鞋有所帮助,文中最后会上传名为STM32_Update.zip ...

  4. STM32通过USB实现Bootlader/IAP功能

    前沿: 最近在做STM32的USB Bootlader/IAP功能,也就是通过USB实现固件升级,本文介绍下实现的基本思路,希望对实现IAP的同学一个参考,改方法已经在产品中得到实际应用并验证是比较合 ...

  5. 英飞凌 AURIX TC3XX 系列单片机的 SOTA 功能介绍

    1.前言 本文讲述的是英飞凌 AURIX TC3XX 系列多核单片机的 SOTA 功能介绍:SOTA 称为软件在线升级,即不依赖下载调试器的情况下,通过CAN.UART等方式实现应用程序的更新. 和O ...

  6. STC51单片机实现IAP远程升级过程分享

    STC51单片机实现IAP远程升级过程分享 1.STC内部ISP更新机制 2.了解51单片机IAP分区 3.IAP分区的调用流程与IAP部分源码: 4.IAP步骤总结 5.源码下载 关于STC单片机I ...

  7. kafka 串讲:架构模型、角色功能梳理

    kafka 串讲:架构模型.角色功能梳理 kafka 的 what why how,先有一个粗略宏观的理解 rabbitmq.各种 mq 的技术选型.横向对比 首先,kafka 是一个消息中间件.我们 ...

  8. MVC与三层架构的联系及三层架构实现学生注册功能

    MVC与三层架构的联系及三层架构实现学生注册功能 三层架构的逻辑关系: MVC和三层架构的联系: 三层架构实现学生注册功能的逻辑: 学生注册页面: 输入学生信息: 完成学生注册: 代码实现: add. ...

  9. Flume在企业大数据仓库架构中位置及功能

    Flume在企业大数据仓库架构中位置及功能 hadoop 数据仓库 flume 数据仓库架构 1.如下图所示,外部数据中,关系型数据库导入到HDFS用sqoop,由Nginx产生的文件实时监控用Flu ...

最新文章

  1. [WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
  2. 《预训练周刊》第7期:傅立叶图像变换器解析、阿里达摩院发布最大中文预训练语言模型PLUG
  3. C#访问远程主机资源的方法
  4. C语言进行网站开发之cgi
  5. 2011年度最佳 jQuery 插件发布
  6. ENISA报告:ICS-SCADA防护建议
  7. 在python中使用什么工具管理模块_怎么使用Python pip(管理模块工具)
  8. h标签对html网页的作用,网页H标签SEO价值的说明与举例
  9. 美橙互联域名与其他地方的区别
  10. Magento2创建自定义Widget 并通过添加图片选择器插入图片
  11. docker部署webapp的例子
  12. python工资这么高为什么不学-为什么Python岗位薪资越来越高
  13. php5.6软件下载,【PHP下载】PHP for Linux 5.6.6-ZOL软件下载
  14. WebRTC:会话描述协议SDP
  15. python爬虫分析百度文库、道客巴巴、豆丁网获取图片链接
  16. java毕业设计软件技术课程学习系统设计与实现源码+lw文档+mybatis+系统+mysql数据库+调试
  17. html问卷调查实验报告,网上问卷调查实验报告..doc
  18. 关于区块链及其数据溯源的学习笔记
  19. windows 重置路由表
  20. SQLServer 自定义函数 日期计算月初/月末/年初/年末/季初/季末

热门文章

  1. MyBatis SQL语句详解
  2. 程序员如何高效提问?
  3. Mac下的netstat命令
  4. 信用卡分期利率陷阱——实际利率计算
  5. 天行健君子以自强不息----宣言
  6. RabbitMQ学习【尚硅谷】
  7. element-ui input 只能输入数字保留两位小数
  8. python重要知识点_35个高级Python知识点总结
  9. 计算机网flags,计算机网络原理实验_使用网络协议分析仪Wireshark
  10. 啊哈算法——第四章:搜索