cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 USB VCP (cdc) and DFU

deliancourt
Associate II
Posted on March 26, 2015 at 11:26

Hello,

I communicate with an STM32F4 eval board and a host computer by using VCP, I would like permit a DFU by using software.

I search the quickly solution to implement both. I hesit between redefine USB interface when STM32 receive a specific request by VCP (desactivate VCP and activate DFU) but i don't know if is possible, the second solution will be to implement two interface with CDC but I'm not really good with USB.

All advice are welcome. Thanks by advance

#usb-cdc-vcp-dfu-and
6 REPLIES 6
Mikk Leini
Senior
Posted on March 27, 2015 at 21:04

Hello,

Let me get this right - for what you want to use DFU? For downloading new firmware?

If so, then story goes like that - DFU is a bootloader protocol and bootloader is usually a separate application in it's own memory area. In STM32 case it's in the beginning of Flash because thats where the reset vector is located. In bootloader there's usually some button or RAM condition check - if that's not set then it will jump to the real application (which in the following Flash area).

Anyway... you don't need to put DFU and VCP into one application. Keep DFU in bootloader and VCP in your application.  Then use a custom linker script to leave some no-init bytes into RAM for both application. Remember you also need to define non-overlapping Flash areas in linker. If you get special command over VCP write a magic number to that no-init RAM area and do hard reset. In bootloader check if that RAM area contains magic number and if so then stay in boot. That boot then initializes USB DFU and your PC will detect it. After finishing, clear the magic number and jump to application (or do reset). 

You can get DFU example from STM32F4Cube\Projects\STM324x9I_EVAL\Applications\USB_Device\DFU_Standalone. You need to configure it for your device and do the RAM no-init stuff on your own.

deliancourt
Associate II
Posted on March 30, 2015 at 10:31

Thanks for your answer. Yes it is for donwload new firmware with USB HS.

In fact I use actually DFU example from ST library with DfuSe Demo. My development planning is : have a functional system with VCP (already functional) and DFU by using Dfuse and then make my own software implementation. I agree with the bootloader story but when I look the main.c of DFU example, DFU seems configured like others USB interface with init, addclass, start... Start RAM is configured for start at0x20000000 in Keil flash option. Sorry for my relative ignorance this my first time with USB and µC bootloader.

int main(void)
{
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
/* Configure the system clock to 168 MHz */
SystemClock_Config();
/* Configure Key Button */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
/* Test if user code is programmed starting from address 0x0800C000 */
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);
JumpToApplication = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
JumpToApplication();
}
/* Otherwise enters DFU mode to allow user programing his application */
/* Init Device Library */
USBD_Init(&USBD_Device, &DFU_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&USBD_Device, USBD_DFU_CLASS);
/* Add DFU Media interface */
USBD_DFU_RegisterMedia(&USBD_Device, &USBD_DFU_Flash_fops);
/* Start Device Process */
USBD_Start(&USBD_Device);
/* Run Application (Interrupt mode) */
while (1)
{
}

For Sector I just know that I have 12 with 3 non Erasable (from 0x08000000 to0x0800C000). Why that not begin at 0x00 ? For vector table ? 0690X00000605FjQAI.png
Mikk Leini
Senior
Posted on March 31, 2015 at 08:29

Hi,

I still don't get the big picture but i can answer few smaller questions.

You see first three sectors as read-only because of the FLASH_DESC_STR string in the usbd_dfu_flash.c file. That is a special markup language which desribes the Flash sectors and beginning address. There's probably a manual for this but as far as i decoded it - the small character ''a'' means it's read-only. ''g'' means it's erase/write/read.

The reason of marking these first sectors as read-only is because the bootloader itself is located there. It can't overwrite itself. If it would try that.. then it would end up in some bad error or bricked device. This is one reason why you can't have bootloader and application together. Actually there is some way for bootloader update itself (i haven't tried it) and that is by downloading the new program to spare area and the swapping to the original place. But that still requires some kind of functioning code which is not your application. In best case it can be a temporary copy of some application function in SRAM which takes care of the relocation.

PS.

If you really-really want to have one USB device with two functions then you need to have two interface descriptors under one configuration descriptor. I once wanted to have VCP and MCS interfaces on one device, but then i realized it's not so easy, especially when functions are different (as CDC and DFU in your case). Although all deviceclasses have similar initialization code, the USB library doesn't merge the descriptors by itself (as far as i know, but i might be wrong also). 

Take a look at usbd_dfu.c file constant USBD_DFU_CfgDesc for example. You see it describes the configuration and 1 to 6 interfaces. As far as i understand you need to have CDC descriptor also there. But this means modifying library files. And i'm not certain at all if there won't be any other obstacles. E.g. the endpoints of two interfaces might collide. For dual interface you need to google and search the forum

deliancourt
Associate II
Posted on April 02, 2015 at 10:47

Hi,

I will try the solution with no volatile variables in protect memory. I will post the result if I have a success. 
deliancourt
Associate II
Posted on April 03, 2015 at 12:02

So, the fact is : after lot of time when I try to implement VCP in DFU project the reading work but not writing.

I have functional project only with VCP and I configure Usb like this (same desc, class... from ST example) :

/* Init Device Library */
USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&hUSBDDevice, USBD_CDC_CLASS);
/* Add CDC Interface Class */
USBD_CDC_RegisterInterface(&hUSBDDevice, &USBD_CDC_fops);
/* Start Device Process */
USBD_Start(&hUSBDDevice);

The two functions for write and read thought USB are (from http://visualgdb.com/tutorials/arm/stm32/usb/):

int
VCP_read(
void
*pBuffer, 
int
size)
{
//si read done =0
if
(!s_RxBuffer.ReadDone)
return
0;
int
remaining = s_RxBuffer.Size - s_RxBuffer.Position;
int
todo = MIN(remaining, size);
if
(todo <= 0)
return
0;
memcpy(pBuffer, s_RxBuffer.Buffer + s_RxBuffer.Position, todo);
s_RxBuffer.Position += todo;
if
(s_RxBuffer.Position >= s_RxBuffer.Size)
{
s_RxBuffer.ReadDone = 0;
USBD_CDC_ReceivePacket(&hUSBDDevice);
}
//s_RxBuffer.ReadDone = 0;
return
todo;
//return 1;
}
int
VCP_write(
const
void
*pBuffer, 
int
size)
{
if
(size > CDC_DATA_HS_OUT_PACKET_SIZE)
{
int
offset;
for
(offset = 0; offset < size; offset++)
{
int
todo = MIN(CDC_DATA_HS_OUT_PACKET_SIZE, 
size - offset);
int
done = VCP_write(((
char
*)pBuffer) + offset, todo);
if
(done != todo)
return
offset + done;
}
return
size;
}
USBD_CDC_HandleTypeDef *pCDC = 
(USBD_CDC_HandleTypeDef *)hUSBDDevice.pClassData;
while
(pCDC->TxState) { } 
//Wait for previous transfer
USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t *)pBuffer, size);
if
(USBD_CDC_TransmitPacket(&hUSBDDevice) != USBD_OK)
return
0;
while
(pCDC->TxState) { } 
//Wait until transfer is done
return
size;
}

When I try to write hcdc->TxState is never cleared because the condition

if
(len <= 0)
{
fifoemptymsk = 0x1 << epnum;
USBx_DEVICE->DIEPEMPMSK &= ~fifoemptymsk;
}

at the end ofPCD_WriteEmptyTxFifo is never true with : len = ep->xfer_len - ep->xfer_count; I have read there [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Bugs%20in%20USB%20OTG%20library&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=6991]ST Forum Bugs in USB OTG librarythat a problem can occurs when stack memory is not initialized to 0. That give me crazy, if someone have a solution he/she will be my hero !
roman239955
Associate III
Posted on June 09, 2016 at 21:57

Did you ever get DFU and CDC to work together?

I just want to know if it's possible.