STM32F407用USB和串口烧写程序

本文介绍了如何使用STM32CubeProgrammer通过USB和串口更新STM32F407的程序。进入系统bootloader有两种方式:设置BOOT0引脚或程序跳转。串口烧写需要设置BOOT0并使用RS232接口,USB烧写同样需进入bootloader。程序跳转涉及关闭外设时钟、禁止PLL、禁止中断和清除中断挂起标志。文章还提供了跳转到bootloader和应用程序的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系统bootloader

STM32的系统存储区自带bootloader,此程序是ST在芯片出厂时烧录进去的,主要用于将用户应用程序下载到芯片内部Flash。支持USB、SPI、I2C、CAN、UART等接口方式下载。
我使用的是407,所以用bootloader下载程序的话只能是USB,USART1,USART3和CAN
在这里插入图片描述
在这里插入图片描述

如何进入系统bootloader

有两种方式可以进入系统的boot loader
一种是通过设置BOOT0引脚,将该引脚置高可以上电后直接进入系统boot loader。
令一种方法是通过程序跳转到系统bootloader。
跳转前需要注意以下问题
1、禁止所有外设时钟
2、禁止使用PLL
3、禁止所有中断
4、清除所有中断挂起标志。

以上部分内容在芯片参考手册的2.4章节,自举配置这一部分也有简单说明。

用串口和USB更新程序

用串口烧写程序 (需要使用RS232接口)

1、首先将BOOT0置高,进入系统bootloader
2、打开软件 STM32CubeProgrammer,如下图所示,选择UART,设置串口、波特率、以及偶检验(因为上电后串口默认是偶校验),点击 connect按钮,下面的信息框里会显示是否连接 成功。
在这里插入图片描述
3、选择烧写文件,点击Start Programm…,就开始烧写程序了。

在这里插入图片描述

USB烧写程序

1、同样需要将BOOT0置高进入系统bootloader
2、打开软件 STM32CubeProgrammer,选择USB,点击2处的刷新可以看到USB接口(必须先进入系统bootloader才可以),点击connect连接。后面的烧写方式与UART方式相同。
在这里插入图片描述

通过程序跳转到系统bootloader

如果我们的硬件电路不方便引出BOOT脚,那么就可以使用程序跳转的方式。
1、我们可以在自己的APP程序中,加入一个跳转程序,例如按下某一个按钮就跳转到系统bootloader,然后就可以用USB方式烧写程序,但是这种方式有一个弊端,就是如果升级程序的时候突然断开连接了,那么单片机中就没有程序了,必须再重新用SW的方式烧写一遍才行。
2、我们可以写两个程序,一个引导程序,一个APP程序,这两个程序在flash中的位置是不一样的,这样在更新APP程序的时候,即便发送异常,也不会破坏引导程序。
主要程序如下所示

/**
  * @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();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_1)==GPIO_PIN_RESET)
		{
			JumpToBootloader();
		}
		else
		{
			JumpToApp();
		}
    /* 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};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses 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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

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

/* USER CODE BEGIN 4 */
#define DISABLE_INT()	__set_PRIMASK(1)
#define ENABLE_INT()	__set_PRIMASK(0)

static void JumpToBootloader(void)
{
	/*除了使用boot引脚控制运行系统bootloader,也可以使用程序跳转,跳转前需要注意以下问题
	1、禁止所有外设时钟
	2、禁止使用PLL
	3、禁止所有中断
	4、清除所有中断挂起标志
	以上操作执行完毕后,直接使用跳转指令,跳转到System Memory地址即可。这个地址可以在数据手册中找到
	
	如果觉得关闭外设时钟等操作太复杂,也可以通过另外一种方式来实现上述操作,即:软件复位
	芯片复位后,外设时钟、中断等默认都是关闭的,只要在初始化前完成跳转即可。我们知道,stm32
	在运行main.c函数之前会先执行system_stm32f4xx.c中的SystemInit函数,在HAL库中,该函数只是配置了中断向量,
	因此可以直接在main.c函数的开始添加跳转代码。具体流程如下
	1、需要升级时,首先在flash某个地址将一个标志置1  (没有测试这种方法)
	2、产生软件复位
	3、判断标志位为1,需要升级,标志位清零,执行跳转程序。
	4、判断标志位为0,直接运行程序 DFU*/
	uint32_t i=0;
	void (*SysMemBootJump)(void); /* 声明一个函数指针*/
	__IO uint32_t BootAddr =  0x1FFF0000;//0x1FFF0000; /* STM32F4 的系统 BootLoader 地址 */
	
	/* 关闭全局中断 */
	DISABLE_INT();//CPU_IntDis();  
	
	/* 关闭滴答定时器,复位到默认值 */
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
	
	/* 设置所有时钟到默认状态,使用 HSI 时钟 */
	HAL_RCC_DeInit();
	
	/* 关闭所有中断,清除所有中断挂起标志 */
	for (i = 0; i < 8; i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}
	
	/* 使能全局中断 */
	ENABLE_INT();//CPU_Init();
	
	/* 设置重映射到系统 Flash */
	__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
	
	/* 跳转到系统 BootLoader,首地址是 MSP,地址+4 是复位中断服务程序地址 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));
	
	/* 设置主堆栈指针 */
	__set_MSP(*(uint32_t *)BootAddr);
	
	/*在 RTOS 工程,这条语句很重要,设置为特权级模式,使用 MSP 指针 */
	__set_CONTROL(0);
	
	/* 跳转到系统 BootLoader */
	SysMemBootJump();
	
//	/* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
//	while (1)
//	{
//		
//	}
}

static void JumpToApp(void)
{
	uint32_t i=0;
	void (*SysMemBootJump)(void);        /* 声明一个函数指针 */
	__IO uint32_t BootAddr = 0x8004000; /* 系统的APP地址 */	
	

	/* 关闭全局中断 */
	DISABLE_INT(); 

	/* 关闭滴答定时器,复位到默认值 */
	SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;

	/* 设置所有时钟到默认状态,使用HSI时钟 */
	HAL_RCC_DeInit();

	/* 关闭所有中断,清除所有中断挂起标志*/
	for (i = 0; i < 8; i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}	

	/* 使能全局中断 */
	ENABLE_INT();

	/* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断复位程序地址 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));

	/* 设置主堆栈指针 */
	__set_MSP(*(uint32_t *)BootAddr);
	
	/*在 RTOS 工程,这条语句很重要,设置为特权级模式,使用 MSP 指针 */
	__set_CONTROL(0);

	/* 跳转到系统 BootLoader */
	SysMemBootJump(); 
}
/* USER CODE END 4 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

在JumpToApp函数中,系统的APP地址定义的是0x8004000,为什么选这个地址呢,因为在把引导程序烧进去之后,用J-Flash软件读取了一下Read back–>Selected sectors; 读取完毕之后发现引导程序大概占用了0xE70左右的大小。于是APP程序的地址就从第二个扇区开始了。
同时APP程序还要设置一下,如下图所示:0x7C00是大小,就是芯片的Flash大小减去第一个扇区的大小。
在这里插入图片描述
然后同时也要在APP程序里面修改中断向量表的位置,在文件system_stm32f4xx.c文件中。
在这里插入图片描述

这样就完成了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值