ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【STM32CUBE+IAR+IAP升级】

2021-09-19 19:00:54  阅读:323  来源: 互联网

标签:uint32 HAL UART APP STM32CUBE printf IAP IAR


STM32CUBE+IAR+IAP升级

案例应用:利用IAR+串口调试助手对STM32F411VET6进行简单的IAP实现,(代码分为两部分:BootLoader+APP翻转LED)

1.工具:

2.工程配置

2.1.1简要说下,本案例IAP,使用uart进行轮询方式接收数据(bin文件),没有任何校验,因此在后续接受过程中可能会出现丢包(丢失bin文件数据)的问题,建议串口波特率设置小些(本案例为9600

FLASH划分:STM32F411vet6片内FLASH512K,RAM128K,本案例将分配32KByte给BootLoader,480KByte给应用程序(本案例为LED_APP,功能0.5s翻转电平一次),如下图所示
在这里插入图片描述
2.1.2 LED_APP

​ ——>STM32CUBEMX中 RCC,SYS,GPIO(PD12),UART,时钟树配置如下,LED应用程序挺简单的
在这里插入图片描述
对printf()函数的重定义具体见:【STM32】STM32CUBEMX+UART串口调试,循环接受发送数据

——>main.c

#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

void SystemClock_Config(void);
#define APPLICATION_ADDRESS  (uint32_t)0x08008000//LED_APP起始位置

int main(void)
{
  __enable_irq();//开中断
  SCB->VTOR = APPLICATION_ADDRESS;//设置程序烧写起始位置

  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART2_UART_Init();

  printf("LED_APP TEST, This is IAP Application\r\n");
  while (1)
  {
      printf("This is IAP Application running\r\n");
      HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
      HAL_Delay(500);
  }

}

——>IAR设置程序起始位置,(对应用程序调试时,不用修改起始位置,调试无误后再修改向量表起始地址和其ROM,RAM,并生成bin文件)

​ 1.在第2步中.cif文件要选选stm32f411xe_flash.icf,因为我们这里是将程序烧写进flash,如果是烧写到sarm,那就选sarm.icf

​ 2.第3步中设置向量表起始地址这里是0x08008000(可以相应修改自定义的,根据你分配区域的大小设置)

​ 3.第4步中Memory Regions中ROM: 0x08008000~0x0807FFFF(总共480KB),RAM:栈是在RAM上分配 的,大小0x2000 0000 ~ 0x2001 FFFF(对应F411ve 128K),一般起始地址为0x2000 0000 ,这里设置为0x2000 00c0,留给参数变量c0大小的区域。
在这里插入图片描述
——>IAR生成bin文件设置,设置完后保存,编译之后会在你的工程exe文件中生成BIN文件,注意bin文件的大小要在设置的范围内
在这里插入图片描述
2.1.3 BootLoader

​ ——>STM32CUBEMX配置和LED_APP配置一样,UART串口波特率设置成9600,

​ ——>同样需要对printf()函数进行重定义,具体见:【STM32】STM32CUBEMX+UART串口调试,循环接受发送数据

main.c

#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
#include <string.h>
#include "flash_if.h"

typedef  void (*pFunction)(void);

#define	UART_BUF_SIZE		256

uint32_t JumpAddress;
pFunction JumpToApplication;
uint8_t uart_buf[UART_BUF_SIZE] = {0};

void SystemClock_Config(void);

int main(void)
{
   uint8_t key = 0;
   uint32_t temp = 0;
   uint32_t timeout = 0;
   uint32_t userapplen = 0;

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();

  printf("\r\n This is Bootloader\r\n");
 
  while (1)
  {

      printf("\r\n=================== Main Menu ============================\r\n\n");
	  printf("  Download user application to the internal Flash ------ 1\r\n\n");
	  printf("  Execute the loaded application ----------------------- 2\r\n\n");


           /* Clean the input path */
	  __HAL_UART_FLUSH_DRREGISTER(&huart2);
	  /* Receive key */
	  HAL_UART_Receive(&huart2, &key, 1, HAL_MAX_DELAY);
            switch(key)
	  {
	  case '1':
		  /* Download user application in the Flash */
		  /* 1. erase user application area */
		  printf("Wait for the internal Flash erase to complete\r\n");
		  if(FLASH_If_Erase(APPLICATION_ADDRESS, 6) == 1)
		  {
			  printf("Erase the internal Flash is fail\r\n");
			  Error_Handler();
		  }
		  printf("Erase the internal Flash is complete\r\n");

		  /* 2. download a file via serial port */
		  printf("Waiting for the file to be sent ... \r\n");
		  userapplen = 0;
		  timeout = HAL_MAX_DELAY;
		  /* Clean the input path */
		  __HAL_UART_FLUSH_DRREGISTER(&huart2);
		  while(1)
		  {
			  if(HAL_UART_Receive(&huart2, uart_buf, UART_BUF_SIZE, timeout) != HAL_OK)
			  {
				  temp = UART_BUF_SIZE - (huart2.RxXferCount + 1);
				  if(FLASH_If_Write(APPLICATION_ADDRESS + userapplen, (uint32_t*)uart_buf, temp / 4) != FLASHIF_OK)
				  {
					  printf("Write the internal Flash is fail\r\n");
					  Error_Handler();
				  }
				  userapplen = userapplen + temp;
				  break;
			  }
			  timeout = 1000;//等待接收完成
			  if(FLASH_If_Write(APPLICATION_ADDRESS + userapplen, (uint32_t*)uart_buf, UART_BUF_SIZE / 4))//4字节对齐
			  {
				  printf("Write the internal Flash is fail\r\n");
				  Error_Handler();
			  }
			  userapplen = userapplen + UART_BUF_SIZE;
		  }
		  printf("Programming Completed Successfully! %ldBtye\r\n", userapplen);
		  break;

	  case '2':
		  printf("Start program execution......\r\n\n");
		  /*
		   * 关闭或反初始化前面用到的外设和中断
		   * 1、反初始化UART
		   * 2、关闭系统滴答定时器中断
		   * */
		 HAL_UART_DeInit(&huart2);
		// HAL_SuspendTick();
       //  __disable_irq();
 	    /* execute the new program */
	      JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
         /* Jump to user application */
	      JumpToApplication = (pFunction) JumpAddress;
	     /* Initialize user application's Stack Pointer */
	      __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
	      JumpToApplication();
		  break;

	  default:
		  printf("Invalid Number ! ==> The number should be either 1 or 2\r");
		  break;
	  }
  }
}

编译调试无误后就可以开始了,生成bin文件注意大小,在32K之内,不需要修改起始地址。

1、上电后打印功能菜单。

2、发送‘1’就会进入IAP模式;首先会擦除APP空间,然后等待用串口助手发送LED_APP的bin文件写入flash,直至完成。

3、发送‘2’就会直接跳转到LED_APP运行,结果如下。
在这里插入图片描述
——>BootLoader程序简单说下(个人看法,如有不同见解,欢迎留言讨论)

  • FLASH_If_Erase(APPLICATION_ADDRESS, 6)函数,第一个参数擦除的sector的起始地址,第二个参数根据自己的flash中sector数进行相应设置(判断下有没有擦除成功)

  • FLASH_If_Write(APPLICATION_ADDRESS + userapplen, (uint32_t * )uart_buf, temp / 4)写flash函数,第一个参数起始地址,第二个要写的数据的缓存地址,第三个要写的数据长度。在该函数之前uart_buf类型为uint8_t,(1个字节)用于接收BIN文件数据,所以轮询方式的HAL_UART_Receive()接收了几十次,FLASH_If_Write()也写了几十次,不过FLASH_If_Write()是以4字节对齐的方式写入,对应于(uint32_t * )uart_buf,

  • case ‘1’:中while()循环:当通过串口助手发送bin文件之后,执行HAL_UART_Receive()后(有可能满buffer有可能没有)—>执行1次FLASH_If_Write(),写完之后更新下次要写的flash起始位置—>HAL_UART_Receive()—>执行1次FLASH_If_Write()…,最后一次进入if(HAL_UART_Receive()!= HAL_OK),写完剩余数据,跳出循环,那么问题来了HAL_UART_Receive()接收数据和FLASH_If_Write()会存在快慢的问题,如果本次接收到的数据还没有写完flash,下一次又来数据又去写那么会存在丢包的问题,为避免该问题,这里将波特率设置的很小9600,可以尝试看看115200时的现象。

  • case ‘2’:在跳转到新的LED_APP之前关掉前面用到的外设和中断,然后在新的应用程序重新开启中断,避免干扰

标签:uint32,HAL,UART,APP,STM32CUBE,printf,IAP,IAR
来源: https://blog.csdn.net/qq_38145331/article/details/120383202

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有