1
\$\begingroup\$

After one minute of time (inactive or active) the USB stack on my Atmel SAM4E-EK sends a USB STALL packet which basically kills the USB connection with the host. How can I prevent this from happening?

The host is a Windows 7 and the status of the USB packet received on the host (PC) is 0xC0000004 from endpoint address 0x84 (UDI_CDC_DATA_EP_IN_0) and one with the same status from 0x83 (UDI_CDC_COMM_EP_0). The USB device is a USB composite device with CDC and MSC enabled.

Atmel has a example project which is also a USB Composite Device with MSC + CDC and this too times out after a couple of minutes (3-4 minutes).

\$\endgroup\$
  • 2
    \$\begingroup\$ If you have the source code of the USB stack, read it to find the code which sends this and the condition that triggers it. If you don't have the source code, dig into the stack documentation. Perhaps you have not integrated the stack into your firmware correctly. Do you have any vendor example project which works without exhibiting the problem? Does it occur on a different host? \$\endgroup\$ – Chris Stratton Jul 3 '17 at 14:54
  • \$\begingroup\$ USB MSC uses STALL handshakes under some error conditions. You may want to look into this. \$\endgroup\$ – Turbo J Jul 3 '17 at 20:06
  • \$\begingroup\$ I have the source code and I spent the day reading it through. Finding the source of the stall packet is hard when there is entire USB device stack to comb through. I also have a lot of documentation, although quite poor quality and some a bit outdated. There is an example project from Atmel namned 'USB Composite Device (MSC + CDC)' this too times out with a stall packet although not after 1 minute. This happens on multiple hosts. \$\endgroup\$ – Entalpi Jul 4 '17 at 7:22
  • 1
    \$\begingroup\$ @Entalpi - Since you have an Atmel evaluation board which fails when running Atmel-supplied demo code, it seems to me that you have a genuine justification to get more help from Atmel/Microchip (either via an official support case on their website, or via a "community" like this one). If you have additional hardware which is similar enough to run the Atmel USB demo code, that test result may help to confirm/deny a hardware-related problem with the original evaluation kit. \$\endgroup\$ – SamGibson Jul 5 '17 at 12:13
  • 1
    \$\begingroup\$ Will do, they might point out something I have missed also. \$\endgroup\$ – Entalpi Jul 5 '17 at 12:15
1
\$\begingroup\$

I got similar problems with ATMEL AVR32 USB. I derived my USB class from the CDC example and AVR-SoftwareFramework-2.3.1 and I found out that they got a bug (most likely on the HW somewhere on the chip). In the example they call flush for every NB_MS_BEFORE_FLUSH-th SoF (Start of Frame) which in some cases (mostly when no communication is done for some time) will freeze Is_device_enumerated() call which is done in the same CDC task function (in next iteration) to the point the chip stop executing instructions,interrupts etc until HW reset is done.

My original derived code was like this (sorry I do not have the original CDC example code anymore):

#define NB_MS_BEFORE_FLUSH          100
void usb_device::flush()        { bool zlp=false; if(!Is_usb_write_enabled(TX_EP)) zlp=true; Usb_ack_in_ready_send(TX_EP); b_tx_new = true; if(zlp==true) { while(!Is_usb_write_enabled(TX_EP)); Usb_ack_in_ready_send(TX_EP); } }
void device_cdc_task(void)
    {
    if (!Is_device_enumerated()) { _reset_fifos=true; return; }
    if (_reset_fifos)
        {
        _reset_fifos=false;
        usb.fifo_send.reset();
        usb.fifo_recv.reset();
        Usb_reset_endpoint_fifo_access(RX_EP);
        Usb_reset_endpoint_fifo_access(TX_EP);
        }
    if (sof_cnt>=NB_MS_BEFORE_FLUSH)    // Flush buffer in Timeout
        {
        sof_cnt=0;
        usb.flush();
        }
    if (usb.b_send) usb.send(); else usb.recv();
    usb.b_send=!usb.b_send;
    }

And after getting to the bottom of this and fixing the issue the working code looks like this:

void device_cdc_task(void)
    {
    if (!Is_device_enumerated()) { _reset_fifos=true; return; }
    if (_reset_fifos)
        {
        _reset_fifos=false;
        usb.fifo_send.reset();
        usb.fifo_recv.reset();
        Usb_reset_endpoint_fifo_access(RX_EP);
        Usb_reset_endpoint_fifo_access(TX_EP);
        sof_cnt=NB_MS_BEFORE_FLUSH;
        }
    if (sof_cnt>=NB_MS_BEFORE_FLUSH)    // Flush buffer in Timeout
        {
        Usb_ack_in_ready_send(TX_EP);
        b_tx_new=true;
        sof_cnt=0;
        }
    if (usb.b_send) usb.send(); else usb.recv();
    usb.b_send=!usb.b_send;
    }

Where USB is my class doing specific job. Also this occasionally send stall but will not freeze the MCU to death. Also this solves the issue that after restart of host PC you need to reset or reconnect the USB.

However I am still suspicious that the USB example contains another bug possibly just wrongly set timeouts or missing acknowledge somewhere because during longer periods of inactivity pipe0 sometimes freezes.

\$\endgroup\$
  • \$\begingroup\$ I cannot verify that this works anymore since I have left the company but I would believe this to be correct since we also suspected a HW fault somewhere. :) \$\endgroup\$ – Entalpi Sep 5 '18 at 15:57
1
\$\begingroup\$

Events such as NAK, ACK, STALL... are issued by SIE (Serial Interface Engine) of the USB controller. So you will not be able to find it in the source code or Technical reference manual of the device.

\$\endgroup\$
  • \$\begingroup\$ Is there any way to figure out the origin of the stall from the SIE? \$\endgroup\$ – Entalpi Jul 7 '17 at 11:46
  • \$\begingroup\$ Yes, capture the USB traffic and share it here. I can help you to analyse the trace. BTW, are you using a good quality cable ? Can you try with a shorter cable? \$\endgroup\$ – Prji Jul 7 '17 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.