Atmel USB envía paquete STALL después de 1 minuto

Después de un minuto de tiempo (inactivo o activo), la pila USB en mi Atmel SAM4E-EK envía un paquete de BLOQUEO USB que básicamente elimina la conexión USB con el host. ¿Cómo puedo evitar que esto suceda?

El host es un Windows 7 y el estado del paquete USB recibido en el host (PC) es 0xC0000004 desde la dirección del punto final 0x84 (UDI_CDC_DATA_EP_IN_0) y uno con el mismo estado desde 0x83 (UDI_CDC_COMM_EP_0). El dispositivo USB es un dispositivo compuesto USB con CDC y MSC habilitados.

Atmel tiene un proyecto de ejemplo que también es un dispositivo compuesto USB con MSC + CDC y esto también se agota después de un par de minutos (3-4 minutos).

Si tiene el código fuente de la pila USB, léalo para encontrar el código que lo envía y la condición que lo activa. Si no tiene el código fuente, busque en la documentación de la pila. Quizás no haya integrado correctamente la pila en su firmware. ¿Tiene algún proyecto de ejemplo de proveedor que funcione sin mostrar el problema? ¿Ocurre en un host diferente?
USB MSC utiliza protocolos de enlace STALL en algunas condiciones de error. Es posible que desee investigar esto.
Tengo el código fuente y pasé el día leyéndolo. Encontrar la fuente del paquete bloqueado es difícil cuando hay una pila completa de dispositivos USB para analizar. También tengo mucha documentación, aunque de bastante mala calidad y alguna un poco desactualizada. Hay un proyecto de ejemplo de Atmel llamado 'Dispositivo compuesto USB (MSC + CDC)' que también se agota con un paquete bloqueado, aunque no después de 1 minuto. Esto sucede en varios hosts.
@Entalpi: dado que tiene una placa de evaluación de Atmel que falla al ejecutar el código de demostración proporcionado por Atmel, me parece que tiene una justificación genuina para obtener más ayuda de Atmel/Microchip (ya sea a través de un caso de soporte oficial en su sitio web, o a través de una "comunidad" como esta ). Si tiene hardware adicional que es lo suficientemente similar para ejecutar el código de demostración USB de Atmel, el resultado de la prueba puede ayudar a confirmar o negar un problema relacionado con el hardware con el kit de evaluación original.
Lo haré, podrían señalar algo que también me he perdido.

Respuestas (2)

Tengo problemas similares con ATMEL AVR32 USB. Derivé mi clase USB del ejemplo de CDC y AVR-SoftwareFramework-2.3.1descubrí que tenían un error (muy probablemente en el HW en algún lugar del chip). En el ejemplo, solicitan flushcada NB_MS_BEFORE_FLUSH-th SoF(Inicio de cuadro) que en algunos casos (principalmente cuando no se realiza ninguna comunicación durante algún tiempo) congelará Is_device_enumerated()la llamada que se realiza en la misma función de tarea CDC (en la próxima iteración) hasta el punto el chip deja de ejecutar instrucciones, interrupciones, etc. hasta que se realiza el restablecimiento de HW.

Mi código derivado original era así (lo siento, ya no tengo el código de ejemplo CDC original):

#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;
    }

Y después de llegar al fondo de esto y solucionar el problema, el código de trabajo se ve así:

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;
    }

Donde USB es mi clase haciendo un trabajo específico. Además, esto ocasionalmente envía un bloqueo, pero no congelará la MCU hasta la muerte. Además, esto resuelve el problema de que, después de reiniciar la PC host, debe reiniciar o volver a conectar el USB.

Sin embargo, todavía sospecho que el ejemplo de USB contiene otro error que posiblemente solo establezca incorrectamente los tiempos de espera o que falte el reconocimiento en algún lugar porque durante períodos más largos de inactividad, pipe0 a veces se congela.

Ya no puedo verificar que esto funcione desde que dejé la empresa, pero creo que esto es correcto ya que también sospechamos una falla de HW en alguna parte. :)

Eventos como NAK, ACK, STALL... son emitidos por SIE (Serial Interface Engine) del controlador USB. Por lo tanto, no podrá encontrarlo en el código fuente o en el manual de referencia técnica del dispositivo.