¿Está bien que el USB envíe datos sin el comando OUT específico primero?

2

He estado yendo y viniendo entre el software de escritura para mi dispositivo y la aplicación de la PC tratando de hacer el protocolo correcto.

Tengo un pic18f4550 hablando sobre transferencias de interrupción. Debe enviar regularmente el estado de hasta 128 interruptores y también mantener el estado de las salidas de pines en función de los comandos de la PC (encendido / apagado, pulso, parpadeo, etc.).

Muchos de los ejemplos que encontré colocan transferencias IN dentro de un bloque que aseguran que una transferencia OUT siempre ocurra primero, así ejemplo de libUSBDotNet . Si no hay datos de salida listos, tampoco se realizará una solicitud de entrada. La plantilla del firmware se configuró inicialmente para manejar algo similar: siempre esperaría a que haya datos en el búfer de SALIDA, manejar eso, luego configurar el búfer de EN y enviar.

Cuando empecé, pensé que estaba sobrevalorado, porque mi dispositivo siempre iba a enviar el estado del conmutador si tenía la información y siempre estaba listo para los comandos, si hubiera alguno. Ajusté mi aplicación para enviar transferencias OUT y solicitudes de IN de forma independiente, y el firmware para manejar cada una de forma independiente. Pero a medida que mi código se vuelve más complejo, me pregunto si me estaba perdiendo algo.

Si me aseguré de que la estructura back-to-back OUT-IN, podría reservar uno o dos bytes OUT iniciales para incluir un comando para enviar la actualización del conmutador. También me permitiría dejar de solicitar datos fácilmente. Por supuesto, podría dejarlo como está y tener ciertos comandos reservados para establecer indicadores que habilitarían / deshabilitarían cierto comportamiento en el lado de la recopilación / transferencia de datos. Todavía no sé qué podría ser necesario al final de este proyecto, así que supongo que estoy buscando consejos para las mejores prácticas y los pros / contras de los enfoques. O tal vez estoy pensando demasiado en esto.

Gracias.

EDITAR: Además, el modo de búfer de ping-pong está desactivado en mi chip, por lo que hay buffers dedicados para el EP ENTRADO y el EP EXTERNO, si no me equivoco.

Código C # (también he portado esto en pyUSB). Compare con la muestra libUSBDotNet a la que he enlazado. Ejecutar cada 10 ms con un temporizador

private static void RunUSB(Object source, ElapsedEventArgs e)
    {
        ErrorCode ec = ErrorCode.None;

        if (true) // for now always do this.  In future only if we have commands to send.
        {
            int bytesWritten;
            ec = writer.Write (commands, 0, 3, 2000, out bytesWritten);
            if (ec != ErrorCode.None)
                throw new Exception (UsbDevice.LastErrorString);
        }

        int bytesRead;
        byte[] readBuffer = new byte[64];
        ec = reader.Read(readBuffer, 2000, out bytesRead);
        if (bytesRead != 0) 
        {
            //handle input data
        }
    }  

Código de firmware (utilizando mStack )

// initialize endpoint 1 IN buffer
unsigned char *INPacket = usb_get_in_buffer(1);
memset(INPacket, 0, EP_1_IN_LEN);

    while (1) {
        if (usb_is_configured()) 
        {
            // get data from PC
            if (usb_out_endpoint_has_data(1))
            {
                unsigned char OUTLen;
                const unsigned char *OUTPacket;
                /* Data received from host */
                OUTLen = usb_get_out_buffer(1, &OUTPacket);

                // do stuff with OUT data
                // rearm for out data
                usb_arm_out_endpoint(1);
            }

            // send data to PC            
            if (!usb_in_endpoint_halted(1))
            {
                /* Wait for EP 1 IN to become free then send. This of
                 * course only works using interrupts. */
                if(!usb_in_endpoint_busy(1))
                {
                    // fill INPacket with data
                    usb_send_in_buffer(1, byteCount);
                } else {
                    // send something
                    INPacket[0] = 0;
                    usb_send_in_buffer(1, 1);
                }
            }
        }
    }

Tenga en cuenta que el if (!usb_in_endpoint_halted(1)) estaba originalmente dentro del bloque if (usb_out_endpoint_has_data(1))

    
pregunta ptpaterson

1 respuesta

2

No puedes decidir fuera o dentro, el anfitrión lo hace. Esta pregunta, por lo tanto, no tiene sentido.

Si tiene algo que enviar al host, debe esperar un token IN. Sin embargo, el hardware SIE se encarga de esto automáticamente. Configura los buffers con los descriptores apropiados y espera a que el hardware transfiera los datos.

En esta parte, incluso puede configurar dos búferes de modo que el hardware se transfiera al primer o al segundo, y luego cambie automáticamente al segundo cuando el primero se llene / se vacíe. Esto se denomina "modo de búfer de ping pong" en la hoja de datos.

Antes de hacer un proyecto de USB, deberías leer primero la especificación de USB. Sin eso, siempre estarás hurgando en la oscuridad preguntándote por qué ciertas cosas se hicieron de ciertas maneras y si son realmente necesarias. El capítulo de USB SIE en la hoja de datos proporciona un fondo razonable, pero no sustituye a la especificación de USB.

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas