Using DFU and MSC
Hello there,
I’m working on a device that in its normal operation uses the MSC.
But I want my clients to also be able to update the device via USB using DFU.
#define USBD_PID_FS 57105
#define USBD_PRODUCT_STRING_FS "STM32 DownLoad Firmware Update"
#define USBD_CONFIGURATION_STRING_FS "DFU Config"
#define USBD_INTERFACE_STRING_FS "DFU Interface"
#define USBD_PID_FS 22314
#define USBD_PRODUCT_STRING_FS "STM32 Mass Storage"
#define USBD_CONFIGURATION_STRING_FS "MSC Config"
#define USBD_INTERFACE_STRING_FS "MSC Interface"
I found these differences and made a work around, CubeProgrammer is detecting a DFU device when a button is pressed:
void MX_USB_DEVICE_Init(void)
{
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
//check to enter DFU mode
if(HAL_GPIO_ReadPin(USR_BUT_ENTER_GPIO_Port, USR_BUT_ENTER_Pin) == GPIO_PIN_RESET){
if (USBD_Init(&hUsbDeviceFS, &DFU_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_DFU) != USBD_OK)
{
Error_Handler();
}
if (USBD_DFU_RegisterMedia(&hUsbDeviceFS, &USBD_DFU_fops_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
return;
}
/* USER CODE END USB_DEVICE_Init_PreTreatment */
/* Init Device Library, add supported class and start the library. */
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC) != USBD_OK)
{
Error_Handler();
}
if (USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_Storage_Interface_fops_FS) != USBD_OK)
{
Error_Handler();
}
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
/* USER CODE END USB_DEVICE_Init_PostTreatment */
}
And I smashed together a implementation like this:
/*
* usbd_desc_dfu.c
*
* Created on: Sep 15, 2026
* Author: william.vanraemdonck
*/
#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "STMicroelectronics"
#define DFU_VID 0x0483
#define DFU_PID 0xDF11
#define DFU_PRODUCT_STR "STM32 DownLoad Firmware Update"
#define DFU_CONFIG_STR "DFU Config"
#define DFU_INTERFACE_STR "DFU Interface"
#define DFU_MANUF_STR USBD_MANUFACTURER_STRING
#define DFU_LANGID USBD_LANGID_STRING
static uint8_t *DFU_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static uint8_t *DFU_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
USBD_DescriptorsTypeDef DFU_Desc = {
DFU_DeviceDescriptor,
DFU_LangIDStrDescriptor,
DFU_ManufacturerStrDescriptor,
DFU_ProductStrDescriptor,
DFU_SerialStrDescriptor,
DFU_ConfigStrDescriptor,
DFU_InterfaceStrDescriptor
};
__ALIGN_BEGIN static uint8_t DFU_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
0x12, USB_DESC_TYPE_DEVICE,
0x00, 0x02, /* bcdUSB 2.00 */
0x00, 0x00, 0x00, /* class/subclass/protocol: per-interface */
USB_MAX_EP0_SIZE,
LOBYTE(DFU_VID), HIBYTE(DFU_VID),
LOBYTE(DFU_PID), HIBYTE(DFU_PID),
0x00, 0x02, /* bcdDevice 2.00 */
USBD_IDX_MFC_STR, USBD_IDX_PRODUCT_STR, USBD_IDX_SERIAL_STR,
USBD_MAX_NUM_CONFIGURATION
};
__ALIGN_BEGIN static uint8_t DFU_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING,
LOBYTE(DFU_LANGID), HIBYTE(DFU_LANGID)
};
__ALIGN_BEGIN static uint8_t DFU_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
static uint8_t *DFU_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); *length = sizeof(DFU_DeviceDesc); return DFU_DeviceDesc; }
static uint8_t *DFU_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); *length = sizeof(DFU_LangIDDesc); return DFU_LangIDDesc; }
static uint8_t *DFU_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); USBD_GetString((uint8_t *)DFU_MANUF_STR, DFU_StrDesc, length); return DFU_StrDesc; }
static uint8_t *DFU_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); USBD_GetString((uint8_t *)DFU_PRODUCT_STR, DFU_StrDesc, length); return DFU_StrDesc; }
static uint8_t *DFU_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); USBD_GetString((uint8_t *)DFU_CONFIG_STR, DFU_StrDesc, length); return DFU_StrDesc; }
static uint8_t *DFU_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{ UNUSED(speed); USBD_GetString((uint8_t *)DFU_INTERFACE_STR, DFU_StrDesc, length); return DFU_StrDesc; }
static uint8_t *DFU_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
/* reuse the CubeMX one so the serial stays consistent */
return FS_Desc.GetSerialStrDescriptor(speed, length);
}
Now when I try programming the device over DFU it says in the terminal from cube programmer:
Error: Data read failed
And the loading bar just goes back and forward but staying at 0%.
Is there anything else I have look over or should still do?
Kind regards,
William
