STM32Cube 生成 USB DFU

STM32Cubemx 生成USB DFU 固件升级程序

  1. 生成代码

如图,新建项目工程


首先,芯片型号为STM32F401CB,配置好USB时钟树,在USB_Device中选择Download Firmware Update Class(DFU)类,其主要设置如上图红色标记处,USBD_DFU_APP_DEFAULT_ADD为APP程序flash起始地址,这里我的程序才48k多一点,故使用最后的扇区64k,扇区具体参数请查阅相关datasheet。USBD_DFU_MEDIA Interface 属性是对芯片flash使用的描述,@Internal Flash /0x08000000/01016Ka,03016Kg,01*064Kg,0x08000000表示起始地址,我这里DFU的程序大小不到16K,故只使用了第一个扇区,a代表只读,g代表读写可擦除,具体参考软件介绍,这里的参数必须参照芯片型号进行填写。

程序栈可以设置大一点,这里为0x2000,Gnerate 生成程序代码。

  1. 修改关键代码
    keil软件打开工程,找到 usbd_dfu_if.c文件依次修改如下:
    uint16_t MEM_If_Init_FS(void)函数 增加如下代码
1
2
3
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);//解锁flash,清楚标志位

uint16_t MEM_If_DeInit_FS(void) 函数 增加如下代码

1
HAL_FLASH_Lock();

uint16_t MEM_If_Erase_FS(uint32_t Add)函数 增加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
uint32_t UserStartSector;
    uint32_t SectorError;
    FLASH_EraseInitTypeDef pEraseInit;

    /* Unlock the Flash to enable the flash control register access *************/
    MEM_If_Init_FS();

    /* Get the sector where start the user flash area */
    UserStartSector = GetSector(Add);

    pEraseInit.TypeErase = TYPEERASE_SECTORS;
    pEraseInit.Sector = UserStartSector;
    pEraseInit.NbSectors = 1;//我这里只使用了最后一个Sector,根据APP程序大小确定
    pEraseInit.VoltageRange = VOLTAGE_RANGE_3;

    if (HAL_FLASHEx_Erase(&pEraseInit, &SectorError) != HAL_OK)
    {<!-- -->
        /* Error occurred while page erase */
        return (1);
    }

GetSector()可自行编写,就是根据flash地址确定扇区数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
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
  {<!-- -->
    sector = FLASH_SECTOR_4;
  }
 

  return sector;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len)
{<!-- -->
  /* USER CODE BEGIN 3 */
    uint32_t i = 0;

    for(i = 0; i < Len; i+=4)
    {<!-- -->
        /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
           be done by byte */
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest+i), *(uint32_t*)(src+i)) == HAL_OK)
        {<!-- -->
            /* Check the written value */
            if(*(uint32_t *)(src + i) != *(uint32_t*)(dest+i))
            {<!-- -->
                /* Flash content doesn't match SRAM content */
                return 2;
            }
        }
        else
        {<!-- -->
            /* Error occurred while writing data in Flash memory */
            return 1;
        }
    }
   
  return (USBD_OK);
  /* USER CODE END 3 */
}

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 */
     uint32_t i = 0;
    uint8_t *psrc = src;

    for(i = 0; i < Len; i++)
    {<!-- -->
        dest[i] = *psrc++;
    }
  return (uint8_t*)(dest);
  /* USER CODE END 4 */
}

uint16_t MEM_If_GetStatus_FS(uint32_t Add, uint8_t Cmd, uint8_t *buffer)
{<!-- -->
  /* USER CODE BEGIN 5 */
     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);
  /* USER CODE END 5 */
}

Main.c中程序如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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_USB_DEVICE_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
   
   
   
    if(HAL_GPIO_ReadPin( power_swich_sta_GPIO_Port , power_swich_sta_Pin ) == GPIO_PIN_SET)//根据按键进行APP跳转
        {<!-- -->
                 /* Test if user code is programmed starting from USBD_DFU_APP_DEFAULT_ADD address */
        if(((*(__IO uint32_t*)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000 ) == 0x20000000)
                    {<!-- -->
            /* Jump to user application */
            JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);//USBD_DFU_APP_DEFAULT_ADD 为初始设置的APP地址
            JumpToApplication = (pFunction) JumpAddress;

            /* Initialize user application's Stack Pointer */
            __set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
            JumpToApplication();
                    }
        }
       
    MX_USB_DEVICE_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
           
  while (1)
  {<!-- -->
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
       
        HAL_Delay(100);
        HAL_GPIO_TogglePin(BAT_Sta_GPIO_Port,BAT_Sta_Pin);
   

  }
  /* USER CODE END 3 */
}
  1. APP程序下载地址修改
    start地址为APP flash起始地址0x8010000 ,大小64k,编译程序,生成hex文件

如上图,将APP hex 文件转换成 Dfu文件

先将dfu程序下载,连接USB,打开上图软件,Choose选择生成好的DFU文件,Upgrade下载,Verify校验,leave DEU mode。

若软件提示 红色字体 bad firmwa ,请修改usbd_def.h 如上图

DFU软件下载百度网盘提取码:提取码:phs2,也可自行搜索 UM0412 进行下载