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

11

Soy un miembro de pregrado de un equipo de investigación que trabaja en un proyecto que involucra un ASIC transmisor de RF y su receptor inalámbrico que finalmente 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 a la computadora. Actualmente, mi enfoque es utilizar interrupciones activadas por bordes para colocar los datos en un búfer circular y hacer todo el proceso de decodificación bit a bit en el bucle principal. El microcontrolador debe emitir simultáneamente estos datos mediante USB (puerto de comunicación virtual) a la computadora.

Aquí hay un problema que estoy teniendo y que estoy anticipando:

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

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

Entonces, la pregunta es simple, ¿qué podría uno hacer para resolver estos problemas o no es este el enfoque correcto? Estoy dispuesto a considerar enfoques menos centrados en el software también. Por ejemplo, el uso de 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.

Keegan Jay
fuente
Tengo que decir que es raro que vea que muchas sugerencias que me gustan contestadas tan rápido, responden bien a su pregunta. Me interesaría saber más sobre los cambios de datos. ¿Son explosivos, de repente a toda velocidad y luego períodos de poca información o es plausible que pases un período extenso con datos continuos?
Kortuk
Mientras el ASIC tenga energía, envía un flujo continuo de datos. No estalló en absoluto. Es una aplicación de detección médica en tiempo real con lectura de computadora. ¿Alguna vez has visto un electrocardiograma?
Keegan Jay
Tantas respuestas geniales aquí. Vi una clara división entre soluciones que implican cambios en las interrupciones y soluciones que involucran hardware dedicado / lógica digital. Cosas como FPGA y Verilog con las que estoy familiarizado, pero aún no tengo experiencia, por lo que esto significa que deben guardarse a largo plazo. En el corto plazo, @rocketmagnets está bien con menos métodos de interrupción. Me gusta la elegancia de dedicar tareas serviles a la lógica digital y guardar el ARM para una verdadera computación. En el futuro, la potencia del ARM se utilizará para el análisis y el filtrado de los datos seriales inalámbricos.
Keegan Jay
¿La señal es síncrona o asíncrona?
markrages
Asincrónico. 4 bits de inicio, 10 bits de datos, 2 bits de parada. Debido a la naturaleza del ASIC que está transmitiendo, los tiempos HI y LO varían mucho de un chip a otro. Ya he escrito un algoritmo para deducir la velocidad en baudios.
Keegan Jay

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 están 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 desperdicia 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 ciclo que suceden con mucha más frecuencia que otras. Quizás los bits entrantes, por ejemplo, en cuyo caso, agreguen más de esas pruebas, de modo que una mayor parte del procesador se dedique 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, tenga ese evento en interrupción y tenga todo lo demás en el bucle.

Rocketmagnet
fuente
Me gusta tu respuesta más que la respuesta de otra persona de Rocketmagnet. En lugar de más hadrware, hardware más rápido, más de algo más, Rocketmagnet sugiere: hacer menos, mejor y más simple.
Bien, he visto muchos casos en los que las interrupciones hacen que la solución sea mucho mejor. Hacen grandes cosas, permiten código bien estructurado, baja latencia y muchas otras ventajas, pero tengo que estar de acuerdo con usted aquí. Parece que el proceso es tan intenso que 1 controlador puede necesitar dedicar toda su atención al manejo de la transmisión en serie. El front-end digital me parece ideal, pero muchas veces tienes algunos micros y no hay FPGA cuando se trata de un proyecto escolar, probablemente dedicaría un micro a manejarlo primero para mí y luego trataría de instalar un FPGA para reemplazarlo. costo.
Kortuk
Esta es probablemente la solución con la que iré en el corto plazo. Esperaba evitar esto porque implica volver a escribir un poco de los controladores seriales existentes, pero es una solución elegante que está dentro de mis capacidades en un corto período de tiempo.
Keegan Jay
1
@ JayKeegan: Sí, probablemente sea la ruta más rápida hacia una solución. PSoC y FPGA podrían ser el enfoque para el próximo proyecto.
Rocketmagnet
6

Posiblemente podría usar un FPGA en lugar de un Microcontrolador para decodificar y almacenar en búfer el flujo de datos inalámbrico. Luego, use el procesador ARM para vaciar los búferes de FPGA (por ejemplo, usando una interfaz SPI) y envíe el contenido al puerto de comunicación USB. Es un trabajo, pero un FPGA debería ser capaz de mantenerse fácilmente siempre que pueda repararlo con la frecuencia suficiente para garantizar que sus memorias intermedias de hardware no se desborden (o si puede manejar los datos caídos en un nivel superior del protocolo) )

vicatcu
fuente
Esta podría ser una excelente solución a largo plazo. Esperaba haber recibido muchas soluciones de hardware / lógica digital además de soluciones de software porque ahora tengo una excusa para aprender sobre estas cosas. Todavía no tengo experiencia con FPGAs desafortunadamente.
Keegan Jay
6

Fácil: use un microcontrolador PSoC5 .

PSoC

Tiene toda la facilidad de uso de un microcontrolador, además 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 poderoso núcleo ARM de 32 bits puede hacer girar sus instrucciones Thumb.

Rocketmagnet
fuente
La página de resumen no enumera las frecuencias de reloj, lo que generó mi sospecha. La hoja de datos dice 40MHz (también noté 6mA a 6MHz). Eso es la mitad de lo que OP tiene ahora. "El MCU también tiene que manejar muchas otras tareas", por lo que puede depender de cuáles sean si es una buena idea o no.
stevenvh
Suben hasta 67MHz. Por lo tanto, es casi tan rápido como el procesador actual del OP, excepto que la mayor parte del trabajo se realizará en hardware, dejando a la CPU con mucho más tiempo libre.
Rocketmagnet
1
No miré todas las hojas de datos. El primero que elegí decía 40MHz.
stevenvh
@stevenvh: tienen diferentes grados de velocidad. El tercer número en el PN es el grado de velocidad. (4 = 48MHz, 6 = 67MHz).
Rocketmagnet
1
Esta es también una solución fantástica a largo plazo, al igual que la idea FPGA. Nunca he oído hablar de este tipo de chip, pero trae mucha funcionalidad en el resto de mi placa en un solo chip. En el futuro, esto podría significar que todo el receptor se ajusta a algo del tamaño de una memoria USB, que es la visión de mi líder de proyecto. Estaré aprendiendo Verilog el próximo semestre.
Keegan Jay
4

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

La solución de @vicatcu es ciertamente una buena, pero si no puede o no le agregará más hardware (y esto incluye un procesador más rápido), entonces debe elegir. Si este enlace en serie es el más importante, debe sentarse en el ISR hasta que se hayan recopilado todos los bits. 180 instrucciones por bit en realidad no está nada mal, pero no intentes hacer todo. Cuando detecte el inicio de una transferencia, gire hasta que se complete la transferencia. Rellene el resultado en un FIFO y luego reanude el procesamiento normal.

No dice cuánto dura cada transmisión, pero si son cortas y con ráfagas, esta sería una solución viable. Estoy dispuesto a apostar que su implementación de puerto COM virtual también tiene algo de almacenamiento en búfer de hardware, por lo que un servicio de interrupción "lento" no debería presentar demasiados problemas. En cuanto al resto de lo que necesita hacer el MCU ... tiene que tomar algunas decisiones de diseño.

akohlsmith
fuente
Este tipo de solución complementa el enfoque de software de Rocketman con la reducción de la cantidad de controladores basados ​​en interrupciones. Puedo mantener el controlador serial principal que mencioné como basado en interrupciones. También intentaré girar hasta que se lea todo el cuadro como mencionas.
Keegan Jay
3

En primer lugar, me gustan algunas de las respuestas aquí, y algunas me han votado.

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

El lado de la corteza-M3 simplemente interrumpiría los datos SPI recibidos. Eso reduce su interrupción anterior activada por borde externo de 400 KHz a 50 KHz.

Las dos razones por las que sugiero esto se deben a que 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 permitirle preservar algunos de La estructura de su código actual.

Aparte de eso, creo que la idea de PSoC es increíble con su propia transferencia periférica personalizada a través de DMA a USB.

Jon L
fuente
Este es en realidad el plan que tenía en mente al publicar esto. Si no puedo simplificar el software reduciendo la dependencia de las interrupciones (respuesta seleccionada), entonces eso es lo que haré. Pero sí, requerirá otra ejecución de la placa, probablemente dos porque soy un asco para hacer mis diseños correctamente la primera vez.
Keegan Jay
@ JayKeegan, jaja bienvenido al club!
Jon L
2

Si su formato de datos es similar al de un UART, pero a una velocidad de transmisión impredecible pero constante, mi inclinación sería utilizar un CPLD para convertir cada palabra de datos entrantes en formato SPI o asíncrono estándar. No creo que haya ninguna necesidad de introducirse en el ámbito de los CPLD. En realidad, incluso la lógica discreta casi podría funcionar. Si pudiera generar un reloj que fuera un smidgin más de 5 veces su velocidad de datos deseada, podría usar un contador dividir por cinco y dividir por 16 con algunas puertas. Organice el contador de división por cinco para que se mantenga en restablecimiento siempre 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 llegue a 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 actualmente). Un segundo 16V8 o 22V10 podría usarse como un divisor de tasa fraccional para generar el reloj 5x, o uno podría usar un chip ligeramente más grande (CPLD) y hacer todo en uno.

Editar / Anexo

Tras una consideración adicional, si se va a utilizar un CPLD, se pueden 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 detención. Además, si uno está usando SPI, podría usar la señal / CS para asegurarse de que el dispositivo receptor verá los datos correctamente enmarcados. 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 LSB (7 bits de datos) y una trama con todos los LSB libres (3 bits de datos); el reloj SPI se aceleraría durante los bits de parada, por lo que se enviarían todos los datos.

Algunos microcontroladores tienen módulos de generación PWM bastante versátiles que incluyen cosas como la capacidad de mantenerse en restablecimiento mediante 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 los circuitos de generación de tiempo.

Otro enfoque que Rocketmagnet mencionó de alguna manera sería tener un micro pequeño cuyo único propósito es decodificar los datos en serie y convertirlos a un formato que pueda usar 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.

Super gato
fuente
Todo esto será muy valioso al diseñar la lógica digital para la decodificación. De hecho, saldré como SPI. Por ahora, solo estoy decodificando usando un MCU independiente (restricciones de tiempo). ¡Gracias!
Keegan Jay