Use STM32CubeMX software to generate USB_DEVICE_DFU upgrade program

1. Test platform:
MCU: STM32F429NIH6
Tool: STM32CubeMX software
Compilation software: MDK

2. Configuration steps
(1). Open the STM32CubeMX software, create a new project file, and create a serial port sending and receiving routine. It is necessary to send the data received by the serial port. The routine for generating the serial port will not be introduced in detail here. .
(2). Configure USB_OTG_FS. Since the USB pins on the circuit board are connected to PA11 and PA12, configure USB_OTG_FS here, configure Device Only in the Mode item, and enable interrupts at the same time.
insert image description here
(3). Configure USB_DEVICE, Class For FS IP item to select Download Firmware Update Class (DFU), USBD_DFU_XFER_SIZE represents the maximum number of bytes per transfer, USBD_DFU_APP_DEFAULT_ADD represents the starting address of the upgrade program.

insert image description here
USBD_DFU_APP_DEFAULT_ADD setting
The value set here should be the start address of your upgrade download storage. For the word APP in the field, don’t think that you need to fill in the start address of the APP program. In fact, its function is to trigger the DFU transmission upgrade and tell you that it should be erased Which area address, because most of the DFU functions are applied in the Bootloader project, compared to the Bootloader, when running DFU upgrade, it should be simple and direct (directly erase or write the data of the APP area address, instead of running DFU in the APP To upgrade, you cannot directly erase the code of the APP itself, but transfer it and download it to the download area or other areas that do not interfere with the APP program code).

The meaning of USBD_DFU_MEDIA Interface
description: 0x08000000 is the starting address. "a" stands for Read-only, and "g" stands for Read/Write/Erase. That is to say, the area specified by "a" should be the Bootloader space that cannot be erased or modified, and the area specified by "g" is the user code space. The size is determined by the previous number. The number in front of the multiplication sign " " is the number of Sectors, and the latter is the size of the Sector. This means that starting from 0x08000000, the first 3 Sectors (each Sector is 16k bytes) are Read- only, the next Sector (each Sector is 16k bytes) is Read/Write/Erase, etc.
For example:
"@Internal Flash /0x08000000/120
128Ba,1416*128Bg"
means:
starting from 0x08000000, the first 120 Sectors (each Sector is 128 bytes) are Read-only,
and the following 1416 Sectors (each Sector is 128 bytes) for Read/Write/Erase.

@Internal Flash /0x08000000/03 016Ka, 01 016Kg, 01 064Kg, 07 128Kg, 04 016Kg, 01 064Kg, 07 128Kg
Meaning: Starting from 0x08000000,
03
016Ka represents 3 Read-only areas of 16k bytes.
01 016Kg represents a 16k byte Read/Write/Erase.
01
064Kg represents a 64k byte Read/Write/Erase.
07 128Kg represents 7 Read/Write/Erase of 128k bytes.
04
016Kg represents 4 Read/Write/Erase of 16k bytes.
01 064Kg represents a 64k byte Read/Write/Erase.
07
128Kg represents 7 Read/Write/Erase of 128k bytes.

(4). After the CubeMX configuration is complete, improve the following interfaces, located in usbd_dfu_if.c
uint16_t MEM_If_Init_FS(void)
uint16_t MEM_If_Erase_FS(uint32_t Add)
uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t L en)
uint8_t *MEM_If_Read_FS(uint8_t *src , uint8_t *dest, uint32_t Len)
uint16_t MEM_If_GetStatus_FS (uint32_t Add, uint8_t Cmd, uint8_t *buffer)

The function of MEM_If_Init_FS
is to initialize the FLASH, unlock the FLASH, and clear all the flag bits for subsequent writing actions.

uint16_t MEM_If_Init_FS(void)
{
    
    
	HAL_FLASH_Unlock();
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                           FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
  /* USER CODE BEGIN 0 */
  return (USBD_OK);
  /* USER CODE END 0 */
}

insert image description here
MEM_If_DeInit_FS
This function is opposite to the function of MEM_If_Init_FS, which re-locks the FLASH and prohibits the operation of the FLASH

uint16_t MEM_If_DeInit_FS(void)
{
    
    
	HAL_FLASH_Lock();
  /* USER CODE BEGIN 1 */
  return (USBD_OK);
  /* USER CODE END 1 */
}

insert image description here
GetSector
local function, the function is not included in the initial code, the main function is to return the Sector address of the user's starting area, the STM32F429 internal FLASH has 2 blocks according to the chip manual, each block is 12 sectors, and the first 4 in each block is 16K, the 5th is 64K, and the remaining 7 are 128K.

#define	ADDR_FLASH_SECTOR_0			0x08000000
#define	ADDR_FLASH_SECTOR_1			0x08004000
#define	ADDR_FLASH_SECTOR_2			0x08008000
#define	ADDR_FLASH_SECTOR_3			0x0800C000
#define	ADDR_FLASH_SECTOR_4			0x08010000
#define	ADDR_FLASH_SECTOR_5			0x08020000
#define	ADDR_FLASH_SECTOR_6			0x08040000
#define	ADDR_FLASH_SECTOR_7			0x08060000
#define	ADDR_FLASH_SECTOR_8			0x08080000
#define	ADDR_FLASH_SECTOR_9			0x080A0000
#define	ADDR_FLASH_SECTOR_10		0x080C0000
#define	ADDR_FLASH_SECTOR_11		0x080E0000
#define	ADDR_FLASH_SECTOR_12		0x08100000
#define	ADDR_FLASH_SECTOR_13		0x08104000
#define	ADDR_FLASH_SECTOR_14		0x08108000
#define	ADDR_FLASH_SECTOR_15		0x0810C000
#define	ADDR_FLASH_SECTOR_16		0x08110000
#define	ADDR_FLASH_SECTOR_17		0x08120000
#define	ADDR_FLASH_SECTOR_18		0x08140000
#define	ADDR_FLASH_SECTOR_19		0x08160000
#define	ADDR_FLASH_SECTOR_20		0x08180000
#define	ADDR_FLASH_SECTOR_21		0x081A0000
#define	ADDR_FLASH_SECTOR_22		0x081C0000
#define	ADDR_FLASH_SECTOR_23		0x081E0000

static uint32_t GetSector(uint32_t Address)
{
    
    
	uint32_t sector = 0;
	if((Address < ADDR_FLASH_SECTOR_1)&&(Address >= ADDR_FLASH_SECTOR_0))
	{
    
    
		sector = FLASH_SECTOR_0;
	}
	else if((Address < ADDR_FLASH_SECTOR_2)&&(Address >= ADDR_FLASH_SECTOR_1))
	{
    
    
		sector = FLASH_SECTOR_1;
	}
	else if((Address < ADDR_FLASH_SECTOR_3)&&(Address >= ADDR_FLASH_SECTOR_2))
	{
    
    
		sector = FLASH_SECTOR_2;
	}
	else if((Address < ADDR_FLASH_SECTOR_4)&&(Address >= ADDR_FLASH_SECTOR_3))
	{
    
    
		sector = FLASH_SECTOR_3;
	}
	else if((Address < ADDR_FLASH_SECTOR_5)&&(Address >= ADDR_FLASH_SECTOR_4))
	{
    
    
		sector = FLASH_SECTOR_4;
	}
	else if((Address < ADDR_FLASH_SECTOR_6)&&(Address >= ADDR_FLASH_SECTOR_5))
	{
    
    
		sector = FLASH_SECTOR_5;
	}
	else if((Address < ADDR_FLASH_SECTOR_7)&&(Address >= ADDR_FLASH_SECTOR_6))
	{
    
    
		sector = FLASH_SECTOR_6;
	}
	else if((Address < ADDR_FLASH_SECTOR_8)&&(Address >= ADDR_FLASH_SECTOR_7))
	{
    
    
		sector = FLASH_SECTOR_7;
	}
	else if((Address < ADDR_FLASH_SECTOR_9)&&(Address >= ADDR_FLASH_SECTOR_8))
	{
    
    
		sector = FLASH_SECTOR_8;
	}
	else if((Address < ADDR_FLASH_SECTOR_10)&&(Address >= ADDR_FLASH_SECTOR_9))
	{
    
    
		sector = FLASH_SECTOR_9;
	}
	else if((Address < ADDR_FLASH_SECTOR_11)&&(Address >= ADDR_FLASH_SECTOR_10))
	{
    
    
		sector = FLASH_SECTOR_10;
	}
	else if((Address < ADDR_FLASH_SECTOR_12)&&(Address >= ADDR_FLASH_SECTOR_11))
	{
    
    
		sector = FLASH_SECTOR_11;
	}
	else if((Address < ADDR_FLASH_SECTOR_13)&&(Address >= ADDR_FLASH_SECTOR_12))
	{
    
    
		sector = FLASH_SECTOR_12;
	}
	else if((Address < ADDR_FLASH_SECTOR_14)&&(Address >= ADDR_FLASH_SECTOR_13))
	{
    
    
		sector = FLASH_SECTOR_13;
	}
	else if((Address < ADDR_FLASH_SECTOR_15)&&(Address >= ADDR_FLASH_SECTOR_14))
	{
    
    
		sector = FLASH_SECTOR_14;
	}
	else if((Address < ADDR_FLASH_SECTOR_16)&&(Address >= ADDR_FLASH_SECTOR_15))
	{
    
    
		sector = FLASH_SECTOR_15;
	}
	else if((Address < ADDR_FLASH_SECTOR_17)&&(Address >= ADDR_FLASH_SECTOR_16))
	{
    
    
		sector = FLASH_SECTOR_16;
	}
	else if((Address < ADDR_FLASH_SECTOR_18)&&(Address >= ADDR_FLASH_SECTOR_17))
	{
    
    
		sector = FLASH_SECTOR_17;
	}
	else if((Address < ADDR_FLASH_SECTOR_19)&&(Address >= ADDR_FLASH_SECTOR_18))
	{
    
    
		sector = FLASH_SECTOR_18;
	}
	else if((Address < ADDR_FLASH_SECTOR_20)&&(Address >= ADDR_FLASH_SECTOR_19))
	{
    
    
		sector = FLASH_SECTOR_19;
	}
	else if((Address < ADDR_FLASH_SECTOR_21)&&(Address >= ADDR_FLASH_SECTOR_20))
	{
    
    
		sector = FLASH_SECTOR_20;
	}
	else if((Address < ADDR_FLASH_SECTOR_22)&&(Address >= ADDR_FLASH_SECTOR_21))
	{
    
    
		sector = FLASH_SECTOR_21;
	}
	else if((Address < ADDR_FLASH_SECTOR_23)&&(Address >= ADDR_FLASH_SECTOR_22))
	{
    
    
		sector = FLASH_SECTOR_22;
	}
	else 
	{
    
    
		sector = FLASH_SECTOR_23;
	}
	return sector;
}

insert image description here
insert image description here
insert image description here
MEM_If_Erase_FS
This function implements the function of erasing the data in the APP area, the initialization package format of the HAL library, and defines the erasing method as erasing according to the sector

uint16_t MEM_If_Erase_FS(uint32_t Add)
{
    
    
	uint32_t UserStartSector;
	uint32_t SectorError;
	FLASH_EraseInitTypeDef pEraseInit;
	MEM_If_Init_FS();
	UserStartSector = GetSector(Add);
	pEraseInit.TypeErase = TYPEERASE_SECTORS;
	pEraseInit.Sector = UserStartSector;
	pEraseInit.NbSectors = 3;
	pEraseInit.VoltageRange = VOLTAGE_RANGE_3;
	if(HAL_FLASHEx_Erase(&pEraseInit,&SectorError)!=HAL_OK)
	{
    
    
		return (USBD_FAIL);
	}	
  return (USBD_OK);
  /* USER CODE END 2 */
}

insert image description here
MEM_If_Write_FS
Flash write interface function, writes the FLASH data received by the USB into the FLASH, which is also a key function interface, and is programmed in word

uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
    
    
  /* USER CODE BEGIN 3 */
  UNUSED(src);
  UNUSED(dest);
  UNUSED(Len);
	
	uint32_t i = 0;	
	
	for(i = 0; i < Len; i = i + 4)
	{
    
    
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,(uint32_t)(dest + i),*(uint32_t *)(src + i)) == HAL_OK)
		{
    
    
			if(*(uint32_t *)(src + i) != *(uint32_t *)(dest + i))
			{
    
    
				return 2;
			}
		}
		else
		{
    
    
			return 1;
		}
	}	

  return (USBD_OK);
  /* USER CODE END 3 */
}

insert image description here
MEM_If_Read_FS
reads the data at the specified address into the target array and returns the array address

uint8_t *MEM_If_Read_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{
    
    
  /* Return a valid address to avoid HardFault */
  /* USER CODE BEGIN 4 */
  UNUSED(src);
  UNUSED(dest);
  UNUSED(Len);
	
	uint32_t i = 0;
	uint8_t *psrc = src;
	for( i = 0; i < Len ; i++ )
	{
    
    
		dest[i] = *psrc++;
	}
	return (uint8_t *)(dest);


//  return (uint8_t*)(USBD_OK);
  /* USER CODE END 4 */
}

insert image description here
MEM_If_GetStatus_FS
return status

uint16_t MEM_If_GetStatus_FS (uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{
    
    
	uint16_t FLASH_PROGRAM_TIME = 50;
	uint16_t FLASH_ERASE_TIME = 50;
	switch (Cmd)
	{
    
    
		case DFU_MEDIA_PROGRAM:
			buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
			buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
			buffer[3] = 0;
		break;
		case DFU_MEDIA_ERASE:
		default:
			buffer[1] = (uint8_t)FLASH_ERASE_TIME;
			buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
			buffer[3] = 0;
	break;
	}                             
  return  (USBD_OK);
}

(4). Increase the bootloader program of the jump APP

void JumpToBootloader(void)
{
    
    
	uint32_t i=0;
	void (*SysMemBootJump)(void);        /* 声明一个函数指针 */
//	__IO uint32_t BootAddr = 0x1FF09800; /* STM32F4的系统BootLoader地址 */
	__IO uint32_t BootAddr = USBD_DFU_APP_DEFAULT_ADD;
	/* 关闭全局中断 */
	__set_PRIMASK(1);//关总中断

	/* 关闭滴答定时器,复位到默认值 */
	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;
	}    

	/* 使能全局中断 */
	__set_PRIMASK(0);//开总中断

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

	/* 设置主堆栈指针 */
	__set_MSP(*(uint32_t *)BootAddr);

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

	/* 跳转到系统BootLoader */
	SysMemBootJump(); 

	/* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
	while (1)
	{
    
    

	}
}

insert image description here

Guess you like

Origin blog.csdn.net/qizhi321123/article/details/127263064