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).
Tengo problemas similares con ATMEL AVR32 USB. Derivé mi clase USB del ejemplo de CDC y AVR-SoftwareFramework-2.3.1
descubrí que tenían un error (muy probablemente en el HW en algún lugar del chip). En el ejemplo, solicitan flush
cada 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.
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.
chris stratton
turbo j
Entalpí
Sam Gibson
Entalpí