【STM32】制作一个bootloader

这篇具有很好参考价值的文章主要介绍了【STM32】制作一个bootloader。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

工作环境:STM32CubeMX+Keil

相关环境准备这里就不介绍了。

bootloader是什么

  • bootloader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件的更新,也就是单片机选择性的自己给自己下载程序。可以更新,可以不更新,更新的话,boot loader更新完程序后,跳转到新程序运行;不更新的话,boot loader直接跳转到原来的程序去运行。
  • boot loader更新完程序后并不擦除自己,下次启动后依然先运行boot loader程序,又可以选择性的更新或者不更新程序,所以boot loader就是用来管理单片机程序的更新。
  • 在实际的单片机工程项目中,如果加入了boot loader功能,就可以给单片机日后升级程序留出一个接口,方便日后单片机程序更新。当然,这就需要创建亮哥工程项目,一个位boot loader工程,一个为app工程。
  • bootloader工程生成的文件通常下载到ROM或者Flash中的首地址,这样可以保证上电后先运行boot loader程序。而app工程生成的文件则下载到ROM或者Flash中boot loader后面的地址中。也就是说,存在ROM或者Flash中的内容是分为两部分的。
  • 要实现同一个ROM或者Flash中保存两段程序,并且保证不能相互覆盖,则需要在下载程序时指定地址。如在keil中,可以进行如下调整(需要知道Flash的扇区地址)。

【STM32】制作一个bootloader

升级流程

在介绍升级流程之前。我们必须先搞清楚MCU型号对应的Flash分区情况,可以直接查看手册(当然,其实我们也可以在hal库代码中找到相关信息),如下图:

【STM32】制作一个bootloader

因为上文说到,我们有两个程序需要下载到Flash,bootloader文件一般下载在最开始的地址,application一般在后面的地址。

【STM32】制作一个bootloader

上图即为我们预定义的flash分配情况。我们一般是按照整个扇区进行利用的,这样便于擦除和写入。

  • bootloader从起始地址开始,这个没有疑问。我分配了扇区0给它(这个大小是具体情况而定)。

  • ota_flag这个是用于存放是否升级的标志位。存放在扇区1,ota_flag只占用4字节,当写入0x87654321的时候,表示需要升级,否则,无需升级。

  • application占用了两个连续的扇区,扇区2和扇区3。

  • ota_data也占用了两个连续的扇区,扇区4和扇区5。

【STM32】制作一个bootloader

代码示例

#ifndef BOOTLOADER_H
#define BOOTLOADER_H

#ifdef __cpluscplus
extern "c"
{
#endif

#define FLASH_SECTOR_STEP_SIZE  (128*1024)
#define FLASH_SECTOR_0_ADDRESS  (0x08000000)

#define MCU_OTA_FLAG_ADDRESS (FLASH_SECTOR_0_ADDRESS+ FLASH_SECTOR_STEP_SIZE * FLASH_SECTOR_1)
#define APPLICATION_ADDRESS  (FLASH_SECTOR_0_ADDRESS+ FLASH_SECTOR_STEP_SIZE * FLASH_SECTOR_2)

#define MCU_OTA_DATA_ADDRESS (FLASH_SECTOR_0_ADDRESS+ FLASH_SECTOR_STEP_SIZE * FLASH_SECTOR_4)
#define MCU_OTA_FLAG_VALUE   (0x87654321)

int erase_mcu_ota_flag();
int write_mcu_ota_flag();
int erase_application_sectors();
int write_application_sectors();
int mcu_reset();


#ifdef __cpluscplus
}
#endif
#endif
#include "bootloader.h"
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_flash.h"
#include <stdint.h>


int erase_mcu_ota_flag()
{
	  int ret=0;
    uint32_t SectorError = 0;
	
		FLASH_EraseInitTypeDef sector;
		sector.TypeErase = FLASH_TYPEERASE_SECTORS;
		sector.VoltageRange = FLASH_VOLTAGE_RANGE_3;
		sector.Sector = FLASH_SECTOR_1;
		sector.NbSectors = 1;
	
		HAL_FLASH_Unlock();
		ret = HAL_FLASHEx_Erase(&sector, &SectorError);
		HAL_FLASH_Lock();
	  return ret;
}

int write_mcu_ota_flag()
{
	  int ret=0;
		HAL_FLASH_Unlock();
		ret = HAL_FLASH_Program(FLASH_PSIZE_WORD, MCU_OTA_FLAG_ADDRESS, MCU_OTA_FLAG_VALUE);
		HAL_FLASH_Lock();
	  return ret;
}

int erase_application_sectors()
{
	  int ret=0;
    uint32_t SectorError = 0;
	
		FLASH_EraseInitTypeDef sector;
		sector.TypeErase = FLASH_TYPEERASE_SECTORS;
		sector.VoltageRange = FLASH_VOLTAGE_RANGE_3;
		sector.Sector = FLASH_SECTOR_2;
		sector.NbSectors = 2;
	
		HAL_FLASH_Unlock();
		ret = HAL_FLASHEx_Erase(&sector, &SectorError);
		HAL_FLASH_Lock();
	  return ret;
}

int write_application_sectors()
{
	  int ret=0;
		HAL_FLASH_Unlock();
	  for(int i=0;i<MCU_OTA_DATA_ADDRESS;i+=4)
	  {
			ret = HAL_FLASH_Program(FLASH_PSIZE_WORD, APPLICATION_ADDRESS+i, *(__IO uint32_t*)(MCU_OTA_DATA_ADDRESS+i));
	  }
		HAL_FLASH_Lock();
	  return ret;
}

int mcu_reset()
{
	 __set_FAULTMASK(1);
   __NVIC_SystemReset();
}
/* 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 "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bootloader.h"
#include <stdio.h>
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef void (*pFunction)();
/* 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 */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */


/* 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_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint32_t JumpAddress;
    pFunction Jump_To_Application;
	if(*(__IO uint32_t*)MCU_OTA_FLAG_ADDRESS != MCU_OTA_FLAG_VALUE)
	{
		  JumpAddress = *(__IO uint32_t*)(APPLICATION_ADDRESS+4);
      Jump_To_Application = (pFunction)JumpAddress;

      __set_MSP(*(__IO uint32_t*)APPLICATION_ADDRESS);
      Jump_To_Application();
	}
	else
	{ 
		  printf("mcu_ota");  
		
		  erase_application_sectors();
		
		  write_application_sectors();
		
		  erase_mcu_ota_flag();
		
		  mcu_reset();
	}
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

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

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** 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.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 75;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  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 */

总结

关于地址跳转部分,可以参考STM32 Bootloader程序中Jump2App函数分析文章来源地址https://www.toymoban.com/news/detail-477463.html

到了这里,关于【STM32】制作一个bootloader的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 ——bootloader IAP

    本文使用单片机型号:STM32F104xx IAP(In Application Programming) 是用户自己的程序在运行过程中对 User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。为了实现 IAP 功能,系统将分为 bootloader 和 app 两部分。bo

    2023年04月09日
    浏览(33)
  • STM32 UDS Bootloader开发-下位机篇-bootloader软件(1)

    上一篇文章介绍了STM32 UDS Bootlodaer开发中的需求。本文根据需求开发bootloader软件。 Bootloader参考github大神SummerFalls的UDS_S32K144_XXX.具体实施到STM32中还需要不少修改的地方,原工程对UDS协议的支持也不完善。本文完善了一部分。 NXP官网也更新了

    2024年02月07日
    浏览(106)
  • STM32 UDS Bootloader开发-下位机篇-bootloader软件(2)

    之前一篇文章中介绍了跟跳转,CAN驱动,定时器的配置代码。本文继续介绍Bootloader中的UDS协议栈。 Bootloader参考github大神SummerFalls的UDS_S32K

    2024年02月08日
    浏览(63)
  • STM32 UDS Bootloader开发-下位机篇-bootloader软件(3)

    上一篇文章中主要介绍了UDS服务相关的内容。本文接着介绍flash操作的相关修改,及bootloader调试过程中的问题及修改点。 /

    2024年02月12日
    浏览(41)
  • STM32的bootloader程序(通过串口更新STM32应用程序)

            Bootloader,也被称为引导加载程序,是操作系统启动过程中的一个重要组成部分。它是存储在非易失性存储器中的一段小程序,负责在操作系统内核运行之前加载并启动一些必要的系统组件。         当计算机开机后,BIOS(基本输入/输出系统)会首先运行,检

    2024年02月04日
    浏览(51)
  • 5.[STM32]动动小手,自己制作做一个自动浇花系统吧

    🚀 作者简介:大家好啊,我叫DW,每天分享一些嵌入式知识,期待和大家一起进步! 🉑🉑 系列专栏: STM32 👀👀👀 小实验简介:利用土壤湿度传感器测量土壤湿度,介于阈值之间或者大于阈值水泵关闭,小于设定阈值水泵开启且蜂鸣器报警提醒主人浇水,土壤湿度、水泵

    2023年04月11日
    浏览(30)
  • STM32/GD32 BootLoader升级 IAP升级

    如果我们的App 程序起始地址在0x08006000 ,并且App 的中断向量表在起始地址,那么BootLoader 程序下载App 后,为了App 程序能正确运行,开始App 程序的运行后第一步,就要把中断向量表重定位到0x08006000 那里。 我们的BootLoader下载App程序后,App程序就需要做同样的事情。主要有三个

    2024年02月11日
    浏览(60)
  • stm32 Bootloader设计(YModem协议)

    原文链接:https://blog.csdn.net/qinrenzhi/article/details/82771527 相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些。下文中的bootload就来实现这样的功能。 前段时间有项目关于Bootload设计。所以就仔细的去了研究了一翻。以前都是用的stm32官方的,没有去深入了解。这

    2024年02月03日
    浏览(39)
  • STM32 APP跳转到Bootloader

    stm32 app跳转到bootloade 【STM32】串口IAP功能的实现,BootLoader与App相互跳转 STM32 从APP跳入BootLoader问题

    2024年02月08日
    浏览(41)
  • STM32 UDS Bootloader开发-需求篇

    最近断断续续的在做基于STM32F103的UDS Bootloader,没有项目驱动,只是自己感兴趣。目前基本已经可以实现功能了,在此对做的东西进行一下总结,希望可以帮助到有需要的人。 本次使用的单片机为STM32F103RCT6,flash大小256k,一个扇区2k,SRAM:48KB flash起始地址为 0x8000000 ,大小为0x

    2024年02月06日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包