RISC-V架构单片机GD32VF103:IAP功能
自从传闻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。
RISC-V架构单片机GD32VF103:IAP功能相关推荐
- RISC V (RV32+RV64) 架构 整体介绍
文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...
- 【genius_platform软件平台开发】第八十八讲:arm公司的V架构和内核发展史(整理)
1. ARM公司简介 ARM(Advanced RISC Machines)有三种含义:它是一个公司的名称.它是一类微处理器的通称.它是一种技术的名称. ARM 公司是微处理器行业的一家知名企业,它是 ...
- STM32实现IAP功能之一
最近因项目需求要实现STM32的在线升级即IAP功能,先将这几天的学习体会和IAP的具体实现总结出来,分享给大家,希望对同样实现IAP的童鞋有所帮助,文中最后会上传名为STM32_Update.zip ...
- STM32通过USB实现Bootlader/IAP功能
前沿: 最近在做STM32的USB Bootlader/IAP功能,也就是通过USB实现固件升级,本文介绍下实现的基本思路,希望对实现IAP的同学一个参考,改方法已经在产品中得到实际应用并验证是比较合 ...
- 英飞凌 AURIX TC3XX 系列单片机的 SOTA 功能介绍
1.前言 本文讲述的是英飞凌 AURIX TC3XX 系列多核单片机的 SOTA 功能介绍:SOTA 称为软件在线升级,即不依赖下载调试器的情况下,通过CAN.UART等方式实现应用程序的更新. 和O ...
- STC51单片机实现IAP远程升级过程分享
STC51单片机实现IAP远程升级过程分享 1.STC内部ISP更新机制 2.了解51单片机IAP分区 3.IAP分区的调用流程与IAP部分源码: 4.IAP步骤总结 5.源码下载 关于STC单片机I ...
- kafka 串讲:架构模型、角色功能梳理
kafka 串讲:架构模型.角色功能梳理 kafka 的 what why how,先有一个粗略宏观的理解 rabbitmq.各种 mq 的技术选型.横向对比 首先,kafka 是一个消息中间件.我们 ...
- MVC与三层架构的联系及三层架构实现学生注册功能
MVC与三层架构的联系及三层架构实现学生注册功能 三层架构的逻辑关系: MVC和三层架构的联系: 三层架构实现学生注册功能的逻辑: 学生注册页面: 输入学生信息: 完成学生注册: 代码实现: add. ...
- Flume在企业大数据仓库架构中位置及功能
Flume在企业大数据仓库架构中位置及功能 hadoop 数据仓库 flume 数据仓库架构 1.如下图所示,外部数据中,关系型数据库导入到HDFS用sqoop,由Nginx产生的文件实时监控用Flu ...
最新文章
- [WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
- 《预训练周刊》第7期:傅立叶图像变换器解析、阿里达摩院发布最大中文预训练语言模型PLUG
- C#访问远程主机资源的方法
- C语言进行网站开发之cgi
- 2011年度最佳 jQuery 插件发布
- ENISA报告:ICS-SCADA防护建议
- 在python中使用什么工具管理模块_怎么使用Python pip(管理模块工具)
- h标签对html网页的作用,网页H标签SEO价值的说明与举例
- 美橙互联域名与其他地方的区别
- Magento2创建自定义Widget 并通过添加图片选择器插入图片
- docker部署webapp的例子
- python工资这么高为什么不学-为什么Python岗位薪资越来越高
- php5.6软件下载,【PHP下载】PHP for Linux 5.6.6-ZOL软件下载
- WebRTC:会话描述协议SDP
- python爬虫分析百度文库、道客巴巴、豆丁网获取图片链接
- java毕业设计软件技术课程学习系统设计与实现源码+lw文档+mybatis+系统+mysql数据库+调试
- html问卷调查实验报告,网上问卷调查实验报告..doc
- 关于区块链及其数据溯源的学习笔记
- windows 重置路由表
- SQLServer 自定义函数 日期计算月初/月末/年初/年末/季初/季末