STM32F103基于HAL工程挂载FatFS驱动SD卡实现IAP功能

news2024/11/17 19:31:13

STM32F103基于HAL工程挂载FatFS驱动SD卡实现IAP功能


  • 🎬基于SD卡IAP升级演示:
    在这里插入图片描述

  • 📍相关篇《STM32F103基于HAL工程挂载FatFS驱动SD卡》

  • 📌《使用STM32F103的串口实现IAP程序升级功能》

  • 👉🏻ST相关文档:使用SD卡时的应用内编程,STM32Cube的软件扩展(AN4854)AN4854文件,例程:https://www.st.com/zh/embedded-software/x-cube-iap-sd.html

📑工程说明

🖍本工程为个人移植项目,并不是采用上面的ST官方例程基础上修改而来。折腾这个有几天时间才成功。IAP升级文件所使用的工程也是原工程,本工程是基于上面相关篇工程(STM32F103基于HAL工程挂载FatFS驱动SD卡)基础上新增的IAP功能。

  • 🌿STM32CubeMX有关配置SD工程可以参考上面的相关内容。

  • 🌿编译IAP升级文件时,需要设置IAP偏移地址:
    在这里插入图片描述

这个地址不是固定的,是根据实际工程项目而定,具体大小根据工程编译生成的.MAP文件中的描述进行设定。(必须大于Size: 0x00004d1c,而且是4的整数倍)

在这里插入图片描述

  • 🔨有关BIN文件生成
    在这里插入图片描述
    • 📋ASF转BIN文件转换命令:
C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe  --bin -o  ./STM32F1-SD-FatFS/iap.bin  ./STM32F1-SD-FatFS/STM32F1-SD-FatFS.axf
  • 🔰参考:
    在这里插入图片描述
  • 🏳‍🌈将生成的IAP.BIN文件拷贝到SD卡根目录下。名字一定要和程序中对应读取的名字要一致。
    在这里插入图片描述
    在这里插入图片描述

📓IAP核心驱动文件(bootloader

  • bootloader.h
/*
 * bootloader.h
 *
 */

#ifndef BOOTLOADER_H_
#define BOOTLOADER_H_

typedef  void (*pFunction)(void);


void bootloader(void);



#endif /* BOOTLOADER_H_ */

  • bootloader.c
/*
 * bootloader.c
 *
 */


#include "bootloader.h"
#include "string.h"
#include "stm32f1xx_hal.h"
#include "ff.h"
#include "main.h"
#include <stdio.h>

#define FIRSTPAGE 10		//0x5000
#define LASTPAGE 248
#define ApplicationAddress    0x8005000
typedef enum
{
    NO_SDCARD,
    PROGRAMMED,
    JUST_BOOTED,
} sequence_t;

pFunction Jump_To_Application;

static void boot(void);
static void erasePage(uint32_t pagenr);
static void programPage(uint32_t pagenr, uint8_t* data, uint32_t size);


//__ASM void startApplication(uint32_t stackPointer, uint32_t startupAddress);

static FATFS fatFs;
static FIL file;
static uint8_t pagedat[2048]; //must be 4 byte aligned


void bootloader()
{
    volatile FRESULT res;
    res = f_mount(&fatFs, "0:", 0);
	myprintf("res= %i\r\n",res);
    if(res != FR_OK)
    {
        myprintf("f_mount error (%i)\r\n", res);
        boot();
    }
    res = f_open(&file, "iap.bin", FA_READ);//升级文件名
    if(res != FR_OK)
    {
			 myprintf("f_open error (%i)\r\n", res);//打开升级文件失败
        boot();//调整到程序入口
    }
    else
		{
			myprintf("Find the upgrade file and prepare the IAP upgrade \r\n");
    uint32_t page = FIRSTPAGE;
    uint32_t programmed = 0;
    while(page < LASTPAGE)
    {
        myprintf("Write to flash\r\n");
        memset(pagedat, 0xFF, PAGESIZE);   //clear the buffer
        UINT len;
        f_read(&file, pagedat, PAGESIZE, &len); //read from file
        uint8_t* flashpointer = (uint8_t*)(FLASH_BASE + PAGESIZE * page);
        if(memcmp(flashpointer, pagedat, len) != 0)     //check if there is a difference
        {
            //program page
            if(!programmed)
            {
                HAL_FLASH_Unlock();
                programmed = 1;
            }
            erasePage(page);
            programPage(page, (uint8_t*)pagedat, 2048);
        }
        if(len < PAGESIZE)
        {
            myprintf("Write programPage complete!\r\n");
            break; //file is ending
        }
        page++;
    }
    if(programmed)
    {
        myprintf("PROGRAMMED\r\n");

    }
    else
    {
        myprintf("JUST_BOOTED\r\n");
    }

    boot();
	}
}



static void erasePage(uint32_t pagenr)
{
    FLASH_EraseInitTypeDef def;
    def.Banks = FLASH_BANK_1;
    def.NbPages = 1;
    def.PageAddress = FLASH_BASE + PAGESIZE * pagenr;
    def.TypeErase = FLASH_TYPEERASE_PAGES;
    uint32_t err;
    HAL_FLASHEx_Erase(&def, &err);
}


static void programPage(uint32_t pagenr, uint8_t* data, uint32_t size)
{
    uint32_t targetaddr = FLASH_BASE + PAGESIZE * pagenr;
    uint32_t* data32 = (uint32_t*)data;
    size = size / 4;
    while(size)
    {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, targetaddr, *data32);
        targetaddr += 4;
        data32++;
        size--;
    }
}

/**
 * starts an application (sets the main stack pointer to stackPointer and jumps to startupAddress)
 */
__ASM  void startApplication(uint32_t stackPointer, uint32_t startupAddress)
{
    msr msp, r0 //set stack pointer to application stack pointer
    bx r1      //branch to application startup code r1

}

/*
void boot() {
	uint32_t JumpAddress;
	uint32_t* app_start = (uint32_t*)(FLASH_BASE + PAGESIZE * FIRSTPAGE);
//	__disable_irq();
//	SCB->VTOR = (uint32_t)app_start;
		 JumpAddress = *(__IO uint32_t*)(app_start + 4);
	Jump_To_Application = (pFunction) JumpAddress;
	startApplication(app_start[0], app_start[1]);
	__set_MSP(*(__IO uint32_t*) app_start);
	Jump_To_Application();//跳转到APP.
}
*/
void boot()
{
    uint32_t JumpAddress;
//	uint32_t* app_start = (uint32_t*)(FLASH_BASE + PAGESIZE * FIRSTPAGE);
//	__disable_irq();
//	SCB->VTOR = (uint32_t)app_start;
    if(((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000) == 0x20000000)//检查栈顶地址是否合法.
    {
			myprintf("Address OK \r\n");
        JumpAddress = *(__IO uint32_t*)(ApplicationAddress + 4);
        Jump_To_Application = (pFunction) JumpAddress;
//	startApplication(app_start[0], app_start[1]);
        __set_MSP(*(__IO uint32_t*) ApplicationAddress);
        Jump_To_Application();//跳转到APP.
    }
}

//__ASM void __set_MSP(uint32_t mainStackPointer)
//{
//  msr msp, r0
//  bx lr
//}



📝main主程序

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bootloader.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h> //for va_list var arg functions
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void myprintf(const char* fmt, ...);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void myprintf(const char* fmt, ...)
{
    static char buffer[256];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    int len = strlen(buffer);
    HAL_UART_Transmit(&huart1, (uint8_t*)buffer, len, 10000);

}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_FATFS_Init();
  /* USER CODE BEGIN 2 */
    myprintf("\r\n SD card demo \r\n");
			bootloader();
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while(1)
    {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
			myprintf("IAP main task\r\n");
//			myprintf("New main task\r\n");
			HAL_Delay(1000);
    }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while(1)
    {
    }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

📚工程源码

链接:https://pan.baidu.com/s/1Ut357bllVGCkTMlPyEdBZA 
提取码:iahu

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/700283.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

并发-JMM-CPU缓存一致性协议MESI

回顾 指令重排 第一V读&#xff0c;都不能指令重排&#xff1b;第二个V写&#xff0c;都不能指令重排 普通读写&#xff0c;写读都会发生指令重排&#xff0c;V写普通读写会发生指令重排&#xff0c;普通读写V读会发生指令重排 CPU缓存一致性协议MESI java—》cpu的执行过程…

Three.js教程:高光网格材质Phong

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 其他系列工具&#xff1a; NSDT简石数字孪生 高光网格材质Phong 高光网格材质MeshPhongMaterial和基础网格材质MeshBasicMaterial、漫反射网格材质MeshLambertMaterial一样都是网格模型的Mesh的材质。 高光网格材质MeshPho…

Web测试的主要内容和测试方法有哪些?

Web测试的主要内容&#xff1a; 一、输入框 二、搜索功能 三、增加、修改功能 四、删除功能 五、注册、登录模块 六、上传图片测试 七、查询结果列表 八、返回键检查 九、回车键检查 十、刷新键检查 Web测试的测试方法&#xff1a; 1.在测试时&#xff0c;与网络有关的步骤或者…

npm报错(npm ERR! Unexpected token ‘.‘)

使用 nvm 将 node 切换到高版本后&#xff0c;运行 npm 相关的命令报的这个错 解决办法&#xff1a; 1、通过nvm list 命令查看当前都安装的node版本列表&#xff0c;依次通过 nvm uninstall [version] 命令将已经安装的 node 版本依次删除。 [version] 代表 node 版本号。 2…

目标检测 pytorch复现Yolov4目标检测项目

目标检测 pytorch复现Yolov4目标检测项目 YOLOV4介绍YOLOV4结构解析1、主干特征提取网络Backbone2、特征金字塔3、YoloHead利用获得到的特征进行预测4、预测结果的解码 YOLOV4的训练1、YOLOV4的改进训练技巧2、loss组成 训练自己的YoloV4模型 YOLOV4介绍 YOLOV4结构解析 1、主…

官宣了!B站将以视频播放分钟数代替播放次数

6月26日&#xff0c;哔哩哔哩&#xff08;以下简称“B站”&#xff09;迎来了14周年庆。B站董事长兼CEO陈睿进行了以“很高兴遇见你”为主题的演讲。 在B站14岁的时候&#xff0c;陈睿就演讲向大家宣布&#xff1a;为了更好地挖掘B站的优质内容&#xff0c;B站将以播放分钟数替…

pyocd打包为exe后调用弹黑窗及pyocd的api调用的问题

打包为exe的程序中调用了cmd窗口&#xff0c;调用的时候会自动弹窗&#xff0c;这个弹窗用pyinstaller的-w的方法是不行的&#xff0c;参考RT-ThreadStudio的方法是如下图写一个.bat文件&#xff0c;关闭弹窗回显 echo off cd /D %~dp0 pyocd.exe %* 但一个原因是 它是0.1.1版…

git的指令

rebase 首先在master上切出一个新分支&#xff0c;叫dev 在dev上进行开发xxx 此时master上被他人提交了东西 想把这个master提交的东西移到dev上 最后统一合并到master上 步骤&#xff1a; 1.master上进行pull&#xff0c;确保本地是最新的 2.在dev上输入git rebase master …

【综合布线设计】网络杂谈(18)深入了解综合布线系统设计

涉及知识点 什么是综合布线系统设计&#xff0c;综合布线系统设计的原则&#xff0c;工作区子系统设计&#xff0c;水平子系统设计&#xff0c;垂直子系统设计&#xff0c;管理子系统设计&#xff0c;设备间子系统设计&#xff0c;建筑群子系统设计。深入了解综合布线系统设计…

二叉树OJ题:LeetCode--226.翻转二叉树

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下LeetCode中第226道二叉树OJ题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; 数据结构与算法专栏&#xff1a;数据结构与算法 个 人…

你真的学懂if语句了嘛,看完这篇文章你一定会让你有所收获,彻底玩转if语句!

&#x1f4cc;(,&#xff65;∀&#xff65;)&#xff89;゛hello ,欢迎来到鸽芷咕的个人频道。 &#x1f4dc; 本博主是C/C领域的新星作者&#xff0c;平时喜欢分享一些编程经验和学习中的遇到的难题&#xff0c;喜欢不要忘了关注咯&#xff01; ✅ 鸽芷咕&#xff1a; 个人…

Arrays类 (Java)

文章目录 1. 介绍2. 分析3. 方法3.1 toStriing()方法3.2 sort()方法 1. 介绍 A. 类介绍&#xff1a;  此类包含用来操作数组&#xff08;比如排序和搜索&#xff09;的各种方法。此类还包含一个允许将数组作为列表来查看的静态工厂. 2. 分析 A. 类包结构&#xff1a;java.uti…

linux-2.6.22.6内核nand flash框架分析

内核启动时会在串口打印nand flash的相关信息&#xff0c;通过该信息可定位到内核自带的nand flash相关驱动代码。 例如串口打印S3C24XX NAND Driver&#xff0c;搜索该字符串可找到/home/book/work/linux/linux-2.6.22.6/drivers/mtd/nand/s3c2410.c这个文件&#xff0c;这个…

The Company Requires Superficial StudyPHP 了解PHP ①

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; The Company Requires PHP MYSQL &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以…

webassembly性能优化

添加调试内容 性能查看 1.点击chrome的性能 2.点击录制按钮 3.开始启动性能分析之后&#xff0c;进行操作 4.操作完成后&#xff0c;点击停止。 5.ctrlf调出搜索&#xff0c;查看相关函数 6.从上到下查看具体耗时的操作。 其中上层包含下层时间。

购物车业务

一、分析购物车vo &#xff08;1&#xff09;添加成功页 public class CartItemVo implements Serializable {/*** 商品id*/private Long skuId;/*** 是否选中*/private Boolean check true;/*** 商品标题*/private String title;/*** 商品图片*/private String image;/***…

Redis6之哨兵模式

哨兵&#xff1a;是用于监控Redis集群中主节点状态的工具&#xff0c;是Redis高可用解决方案&#xff0c;哨兵可以监视一个或者多个redis 主节点&#xff0c;以及这些主节点的所有从节点。 某个主节点服务宕机后&#xff0c;会把这个主节点下的某个从节点升级为主节点来替代已宕…

软件测试技能,JMeter压力测试教程,监听器之灵活的文件写入(十六)

一、前言 JMeter使用Simple Data Writer插件具有非常简单的测试结果编写功能。文件格式仅限于XML和CSV&#xff0c;字段顺序已预定义。因此&#xff0c;你可能会发现Simple Data Writer不足以完成您的任务 Flexible File Writer插件允许以灵活的格式编写测试结果&#xff0c;…

HarmonyOS 4.0开发者Beta招募,快来报名尝鲜

作为一枚资深玩机党&#xff0c;相比同质化日趋严重的硬件配置&#xff0c;我对各大手机厂商的系统软件更感兴趣。把玩了几年iPhone、三星及国产安卓手机&#xff0c;沉浸体验了iOS、Android几番更新迭代&#xff0c;暮然回首——还是咱们“土生土长”的HarmonyOS更贴合我个人的…

如何使用Claude(超详细教程)

如何使用Claude(超详细教程) 1. 目前claude只支持在slack中使用 点击进入claude官网然后点击添加到Slack中 2. 跳转到Slack创建工作区 点击创建新的工作区&#xff08;以前使用过Slack可用以前的工作区&#xff09; 输入邮箱&#xff0c;建议谷歌邮箱登录&#xff08;其他邮…