【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开发记录

    编写一个基础的Bootloader,记录一下开发过程及遇到的问题。 1、基本思路 作为一个Bootloader,它首先需要具备跳转功能,能够跳转到我们的APP地址空间中运行APP。 其次,它还需要有能够读写FLASH的能力。除了启动APP,另外还有对APP进行升级的操作,这个功能需要用到读写FLAS

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    2024年02月06日
    浏览(48)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包