2011-03-01 01:06 PM
USB Leave DFU Mode Issue
2011-06-10 08:36 AM
Update:
I have been able to leave the DFU boot loader code and return to the user application code by manually setting the address pointer prior to sending the DFU_DNLOAD request with 0 data.
The only downside is that it seems to fail about 1 out of 4 times. The user application uses the USB IP to implement a HID device. When the exit function works properly the device will automatically enumerate with the PC as a HID device and will run the user application. When it fails the PC will not recognize the device at which point a physical reset is required to start the user application.
I think the problem is related to Note 2 on page 22 of AN3156. This note states:
When performing a jump from the bootloader to a loaded application code which uses the USB IP, the user application has to disable all pending USB interrupts and reset the core before enabling interrupts. Otherwise, a pending interrupt (issued from the boot loader code) may interfere with the user code and cause a functional failure. This procedure is not needed after exiting the system memory boot mode.
Here is the code snippet of the DLL function that performs the exit operation:
uint8_t DfuExit()
{
/* intermediate variables */
uint8_t ExitStatus = 0;
UCHAR Buffer = 0;
UCHAR *pBuffer = &Buffer;
DFUSTATUS DfuStatus;
UCHAR DfuState;
DWORD dwRet;
UCHAR AddrPtrCmd[5] = {0x21, 0x00, 0x00, 0x00, 0x08};
/* open device driver */
if(DfuOpenDriver())
{
/* check current dfu status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* check for previous dfu error */
if(DfuStatus.bState == STATE_DFU_ERROR)
{
/* clear error status */
STDFU_Clrstatus(&DfuHandle);
/* check current dfu status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
}
/* check current dfu state */
if((DfuStatus.bState == STATE_DFU_IDLE) | (DfuStatus.bState == STATE_DFU_DOWNLOAD_IDLE))
{
/* set download request to set address pointer */
STDFU_Dnload(&DfuHandle, AddrPtrCmd, 5, 0);
/* get current dfu status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* check current dfu status */
if((DfuStatus.bState == STATE_DFU_DOWNLOAD_BUSY))
{
/* get current dfu status*/
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* check status again to see if stack pointer was set */
if(DfuStatus.bState != STATE_DFU_ERROR)
{
/* send dowload request with 0 data */
STDFU_Dnload(&DfuHandle, pBuffer, 0, 0);
/* get current dfu status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* check dfu status */
if(DfuStatus.bState == STATE_DFU_MANIFEST)
{
ExitStatus = 1;
}
}
}
}
/* close device driver */
DfuCloseDriver();
}
return ExitStatus;
}