Cómo decodificar eficientemente la señal serial no estándar

11

Soy un miembro universitario de un equipo de investigación que trabaja en un proyecto que involucra un ASIC transmisor de RF y su receptor inalámbrico que en última instancia debería enviar datos a una PC.

El receptor emite una señal serial rápida , continua, asíncrona, no estándar (es decir, no SPI, I2C, UART, etc.), por lo que mi trabajo es escribir un software de microcontrolador para conectar el receptor al computadora. Actualmente, mi enfoque es utilizar interrupciones activadas desde el borde para colocar los datos en un búfer circular y realizar todo el proceso de decodificación bit a bit en el bucle principal. El microcontrolador debe enviar simultáneamente estos datos mediante USB (puerto virtual de comunicaciones) a la computadora.

Este es un problema que tengo y otro que estoy anticipando:

  1. No puedo procesar los datos almacenados en el búfer lo suficientemente rápido incluso con mi muy potente procesador ARM Cortex M3 de 72 MHz. La tasa de bits es de 400 Kbps (2.5 us / bit). Para referencia que deja solo 180 ciclos por bit (incluida la decodificación Y el ISR, que tiene ~ 30 ciclos de sobrecarga, ¡ay!). La MCU también tiene que manejar muchas otras tareas que sondea en el bucle principal.

  2. El controlador del puerto com virtual USB también se basa en interrupciones. Esto me hace casi seguro de que el controlador finalmente tendrá el procesador interrumpido durante tanto tiempo que pierde la ventana de 2,5 microsegundos (180 ciclos) en la que se puede transmitir un bit. No estoy seguro de cómo se resuelven normalmente los conflictos de interrupción / carreras como esta.

Entonces, la pregunta es simple: ¿qué se puede hacer para resolver estos problemas o este no es el enfoque correcto? También estoy dispuesto a considerar enfoques menos centrados en el software. Por ejemplo, usar un chip USB dedicado con algún tipo de máquina de estado de hardware para la decodificación, pero este es un territorio desconocido.

    
pregunta Jay Keegan

6 respuestas

5

Otra respuesta: deja de usar interrupciones.

La gente salta para usar las interrupciones con demasiada facilidad. Personalmente, rara vez los uso porque en realidad pierden mucho tiempo, como usted está descubriendo.

A menudo es posible escribir un bucle principal que sondea todo tan rápido que su latencia está dentro de las especificaciones, y se pierde muy poco tiempo.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

Puede haber algunas cosas en el bucle que suceden con mucha más frecuencia que otras. Tal vez los bits entrantes, por ejemplo, en cuyo caso, agreguen más de esas pruebas, de modo que se dedique más del procesador a esa tarea.

loop
{
    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (serial_byte_ready)
    {
        // decode serial data
    }

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (enough_serial_bytes_available)
    {
        // more decoding
    }        

    if (serial_bit_ready)
    {
        // shift serial bit into a byte
    }

    if (usb_queue_not_empty)
    {
        // handle USB data
    }        
}

Puede haber algunos eventos para los cuales la latencia de este enfoque es demasiado alta. Por ejemplo, es posible que necesite un evento cronometrado con mucha precisión. En cuyo caso, tener ese evento en la interrupción, y tener todo lo demás en el bucle.

    
respondido por el Rocketmagnet
6

Posiblemente podría usar un FPGA en lugar de un microcontrolador para decodificar y almacenar el flujo de datos inalámbrico. Luego use el procesador ARM para vaciar los búferes FPGA (por ejemplo, mediante una interfaz SPI) y enviar el contenido a través del puerto de comunicaciones USB. Es un trabajo, pero un FPGA debería poder mantenerse al día siempre y cuando sea capaz de darle servicio con la frecuencia suficiente para garantizar que sus búferes de hardware no se excedan (o si puede lidiar con datos descartados a un nivel más alto del protocolo). ).

    
respondido por el vicatcu
6

Fácil: use un Microcontrolador PSoC5 .

Tiene toda la facilidad de uso de un microcontrolador, además de que contiene un CPLD, por lo que puede escribir sus propios periféricos de hardware en Verilog. Simplemente escriba su decodificador de datos en serie en verilog y use DMA para transmitirlo al puerto USB.

Mientras tanto, el potente núcleo ARM de 32 bits puede estar manipulando sus instrucciones para el pulgar.

    
respondido por el Rocketmagnet
4

Creo que tienes una elección de ingeniería clásica: rápida, barata, funciona: elige dos.

La solución de

@ vicatcu es sin duda una buena, pero si no puedes o no quieres agregarle más hardware (y esto incluye un procesador más rápido), entonces tienes que elegir. Si este enlace en serie es el más importante de lo que debería sentarse en el ISR hasta que se hayan recopilado todos los bits. 180 instrucciones por bit no son realmente malas en absoluto, pero no intentes hacer todo. Cuando detecte el inicio de una transferencia, gírelo hasta que se complete la transferencia. Guarde el resultado en un FIFO y luego reanude el procesamiento normal.

No dices cuánto tiempo dura cada transmisión, pero si son cortas e inestables, esta sería una solución viable. Estoy dispuesto a apostar a que la implementación de su puerto COM virtual tiene también un búfer de hardware, por lo que un servicio de interrupción "retrasado" no debería presentar demasiados problemas. En cuanto al resto de lo que debe hacer la MCU ... tiene que tomar algunas decisiones de diseño.

    
respondido por el akohlsmith
3

En primer lugar, me gustan algunas de las respuestas que aparecen aquí, y algunas han obtenido mi voto.

Pero solo para agregar otra solución posible: dadas las limitaciones de su proyecto, ¿sería malo agregar un segundo microcontrolador (eso implicaría otra carrera de la placa)? Tal vez un simple microcontrolador de 8 bits que se conecta a tu Cortex-M3 a través de un periférico rápido como SPI. El controlador de 8 bits de su elección sondeará los bits y los bytes de la forma como en la respuesta seleccionada, pero cuando tiene un byte, podría volcarlo en el registro de datos SPI para transferir.

El lado cortex-M3 simplemente interrumpiría en los datos SPI recibidos. Eso reduce a 50 KHz la anterior interrupción externa activada por el borde de 400 KHz.

Las dos razones por las que sugiero esto es porque algunos de los otros métodos (PSoC o FPGA agregado) son un poco caros (aunque esto probablemente no importa para un proyecto académico de bajo volumen) y porque puede permitirte preservar algo de la estructura de su código actual.

Aparte de eso, creo que la idea de PSoC es asombrosa con su propia transferencia de periféricos personalizados a través de DMA a USB.

    
respondido por el Jon L
2

Si su formato de datos es similar al de un UART, pero a una velocidad en baudios impredecible pero constante, mi inclinación sería usar un CPLD para convertir cada palabra de los datos entrantes en formato SPI o async estándar. No creo que haya ninguna necesidad de empujar todo el camino hacia el ámbito de los CPLD. En realidad, incluso una lógica discreta podría ser casi viable. Si pudiera generar un reloj que fuera un poco más de 5 veces su velocidad de datos deseada, podría usar un contador de dividir por cinco y de dividir por 16 con algunas puertas. Organice el contador de división por cinco para que se mantenga en restablecimiento cada vez que la entrada esté inactiva y el contador de división por 16 esté en cero. De lo contrario, genere un pulso de reloj SPI y golpee el contador de división por 16 cada vez que el contador de división por cinco golpea 2.

Dado el reloj 5x, uno podría generar el reloj SPI usando un 16V8 (el dispositivo lógico programable más pequeño y más barato disponible en la actualidad). Un segundo 16V8 o 22V10 se podría usar como un divisor de tasa fraccional para generar el reloj 5x, o se podría usar un chip un poco más grande (CPLD) y hacer todo en uno.

Editar/Addendum

Tras una consideración adicional, si uno va a utilizar un CPLD, puede agregar fácilmente algunas mejoras adicionales al circuito. Por ejemplo, uno puede agregar lógica con bastante facilidad para que el circuito se detenga hasta que reciba al menos 1,5 bits de bit de parada, seguido de 3,5 bits de bit de inicio; si recibe un bit de inicio demasiado corto, debería volver a buscar el bit de parada. Además, si uno está utilizando SPI, podría usar la señal / CS para asegurarse de que el dispositivo receptor verá los datos correctamente encuadrados. Si el dispositivo que recibe los datos SPI puede manejar tramas de 10 bits, uno podría enviar dichas tramas directamente. De lo contrario, cada trama de diez bits podría enviarse como una trama de 8 bits con el conjunto de LSB (7 bits de datos), y una trama con todos los claros de los LSB (3 bits de datos); El reloj SPI se aceleraría durante los bits de parada, por lo que se enviarían todos los datos. Si el segundo bit de parada no se recibió correctamente, el chip del decodificador podría liberar CS antes de registrar el último byte completo, o bien establecer uno de los bits más bajos (transmitidos posteriormente) que normalmente se habrían dejado libres.

Algunos microcontroladores tienen módulos de generación PWM bastante versátiles que incluyen elementos como la capacidad de ser restablecidos por una señal externa y sincronizar su sincronización con la liberación de dicha señal. Si su microcontrolador puede hacer eso, dependiendo de sus características exactas, eso podría simplificar considerablemente el CPLD o el circuito de generación de temporización.

Otro enfoque que Rocketmagnet tocó un tanto, sería tener un pequeño micro cuyo único propósito es descodificar los datos en serie y convertirlos en un formato utilizable por el micro principal. Su velocidad de datos de 400KHz es bastante rápida para la decodificación de software, pero algo como un PIC podría manejarlo si no tuviera que hacer nada más al mismo tiempo. Dependiendo de los dispositivos con los que esté familiarizado, esto podría ser más fácil o más difícil que usar un CPLD.

    
respondido por el supercat

Lea otras preguntas en las etiquetas

Comentarios Recientes

Entradas vData comercial con formato automático se usa de forma predeterminada en los relojes Seiko 6Q, y los canales no estándar se pueden grabar y (detectará) decodificar con el modo automático, lo que proporciona una mejor información analógica y movilidad . El uso de entradas en serie con formato automático puede reducir la velocidad de repetición de los dispositivos conectados, agregar más datos y transferir más datos por ciclo de lectura, además de tener menos peso de transporte. Esto se traduce en... Lees verder