cancel
Showing results for 
Search instead for 
Did you mean: 

Composite HID MSC - Periodic reset when SD not present

seanb
Associate II
Posted on December 18, 2014 at 05:29

I'm developing a composite HID and MSC device. The MSC is backed by a uSD card and FatFS.

Everything is working great when the uSD card is present but if there is no uSD present DCD_HandleUsbReset_ISR is getting called twice in quick succession about every 30 seconds. If there are HID reports being sent/received when this happens they are failing. I'm not looking to be able to hot plug the uSD or anything like that but I need for it to be optional to have it installed.

Again, if the uSD is inserted everything works great. I'd really appreciate some ideas about where to start fixing this please!

Using STM32_USB-Host-Device_Lib_V2.1.0 on StdPeriph

No Cube or HAL
4 REPLIES 4
tsuneo
Senior
Posted on December 18, 2014 at 19:03

> The MSC is backed by a uSD card and FatFS.

You should know that MSC works exclusively with FatFS. While MSC would own the media (uSD), FatFS shouldn’t write to the media, and vice versa. > but if there is no uSD present DCD_HandleUsbReset_ISR is getting called twice in quick succession about every 30 seconds. It means, as the host got unexpected response, it reset the MSC device. > Using STM32_USB-Host-Device_Lib_V2.1.0 on StdPeriph While no media is present, these callbacks of the storage layer should return -1. USBD_STORAGE_fops->IsReady(lun) USBD_STORAGE_fops->GetCapacity(lun, &blk_nbr, &blk_size) In the device MSC example, these routines are assigned to above callbacks, as follows.

usbd_storage_msd.c
/**
* @brief check whether the medium is ready
* @param lun : logical unit number
* @retval Status
*/
int8_t STORAGE_IsReady (uint8_t lun)
{
#ifndef USE_STM3210C_EVAL 
static int8_t last_status = 0;
if(last_status < 0)
{
SD_Init();
last_status = 0;
}
if(SD_GetStatus() != 0)
{
last_status = -1;
return (-1); 
} 
#else
if( SD_Init() != 0)
{
return (-1);
} 
#endif
return (0);
}
int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
#ifdef USE_STM3210C_EVAL 
SD_CardInfo SDCardInfo;
SD_GetCardInfo(&SDCardInfo); 
#else
if(SD_GetStatus() != 0 )
{
return (-1); 
} 
#endif 
*block_size = 512; 
*block_num = SDCardInfo.CardCapacity / 512; 
return (0);
}

- If you don’t apply USE_STM3210C_EVAL conditional macro, SD_GetStatus() should return FAIL, when no media would present. - If you apply USE_STM3210C_EVAL, SD_Init() should return FAIL on no media. STORAGE_GetCapacity() has to be rewritten, so that this routine returns FAIL on no media. Further code analysis will diverge, as you don’t provide exact target MCU information. Trace it by yourself. Tsuneo
seanb
Associate II
Posted on December 19, 2014 at 01:56

HiTsuneo,

Thanks for your help, you should also know that you have already been a huge help to my project with all of your other posts! First up, stupid of me not to mention, my target is an STM32F405RG on a custom board design. I have spent quite some hours on this already and I've already made sure IsReady and GetCapacity return -1. Unfortunately that doesn't stop the host sending the reset. To be certain I replaced the entire function bodies with just a ''return -1;'' and this is the sequence of events when no uSD card is present:

* USB DeviceReset
* USB DeviceReset
SCSI_INQUIRY
SCSI_INQUIRY
SCSI_READ_FORMAT_CAPACITIES
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ_FORMAT_CAPACITIES
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ_FORMAT_CAPACITIES
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_INQUIRY
SCSI_READ_CAPACITY10
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ_CAPACITY10
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ10
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ10
-20 second delay-
* USB DeviceReset
* USB DeviceReset
SCSI_READ10
-20 second delay-
* USB DeviceReset
* USB DeviceReset

All of these: SCSI_READ_FORMAT_CAPACITIES SCSI_READ_CAPACITY10 SCSI_READ10 result in this:

SCSI_SenseCode(lun, NOT_READY, MEDIUM_NOT_PRESENT);
return -1;

But still I get reset which is why I turned to asking here for help 🙂 I have just installed a trial copy of USBlyzer and will start playing around to see if I can get any further. Thanks again!
seanb
Associate II
Posted on December 19, 2014 at 05:24

I've uploaded a capture of the USBlyzer output, hopefully this can help shed some more light:

http://spostimg.org/omdqcgtkx/USB_Reset.png

You can see how 0279 and 0278 hang for around 20s before being cancelled and the reset occurring. Here is how my endpoints are defined:

#define HID_IN_EP 0x81
#define HID_OUT_EP 0x01
#define MSC_IN_EP 0x82
#define MSC_OUT_EP 0x02

Please let me know if there is any other relevant information that might be useful. I did notice that in returning -1 fromSCSI_ProcessCmd, as happens with the MEDIUM_NOT_PRESENT SenseCode, causesMSC_BOT_CBW_Decode to callMSC_BOT_Abort which in turn stalls IN endpoint:DCD_EP_Stall(pdev, MSC_IN_EP); Is this correct?!
seanb
Associate II
Posted on December 20, 2014 at 11:43

I really hate it when I come across forum posts from people with the exact same problem as me but they never come back to say whether they solved it or not.

So.. After many wasted hours trying to get this fixed in the end I resolved the problem by avoiding it completely.

I removed the call to initialise the SD card from MSC_BOT_Init and instead I do it in USBD_USR_Init. From there I set a flag depending on whether it succeeds.

The flag is then used to selectively return a different descriptor, enable different endpoints and some other stuff.

Essentially if there is an SD card present I return a descriptor with both MSC and HID enabled, if the SD card is not present I return a descriptor with only HID bits in. Seems to work very well so far.