Problemas de transmisión de datos relacionados con FIFO entre el microcontrolador y la PC

2

Tengo una situación en la que un microcontrolador debe realizar una gran cantidad de conversiones de ADC y formatear los resultados en comandos (o paquetes de datos) y enviarlos a una PC utilizando el UART. Para medir continuamente mientras envío datos, creé un búfer circular (cola / FIFO-buffer) para almacenar los paquetes pendientes, y el microcontrolador vaciará (lo ideal) esta cola tan rápido como lo permita la PC.

El microcontrolador envía automáticamente el siguiente comando (si lo hubiera) después de que se haya recibido un carácter ACK (en este caso, un ''! ''). El controlador de interrupciones de UART es así:

if (ch == '!') // ch is the received character
{
    cmd_rx_ack = '!';
    cmd_tx_pop_cmd();
}

La función cmd_tx_pop_cmd () está sacando un paquete del búfer circular y colocando los bytes en una matriz cmd_tx [] y la longitud del paquete en cmd_tx_length.

En el bucle principal:

if (cmd_rx_ack == ‘!’)
{
    cmd_rx_ack = 0; // Reset ack status

    // Transmit the command
    if (cmd_tx_length > 0)
    {
        cmd_tx_transmit();
    }
}

La función cmd_tx_transmit () simplemente transmite los bytes en cmd_tx [] uno por uno (esto se hace en el bucle principal, ya que lleva mucho tiempo hacerlo en el controlador UART).

Esto funciona bien, si el consumidor de la cola (en este caso, el controlador UART) tiene una prioridad más alta que el productor (un temporizador que periódicamente hace que el ADC convierta y envíe un paquete de datos con el resultado en la cola). Anteriormente tuve problemas de concurrencia (consulte Problemas de concurrencia con el búfer circular en incrustado programa ) pero ahora tengo otro problema:

Quiero que el microcontrolador envíe el siguiente paquete en la cola, no solo cuando se haya recibido un ACK, sino también en las situaciones enumeradas a continuación:

  1. El primer paquete que se transmitirá
  2. Si las mediciones se realizan a una velocidad más lenta que el tiempo que se tarda en enviar un paquete.

En la primera situación, el paquete nunca se transmite, ya que no se recibe ningún ACK después de que el paquete se coloca en la cola.

En la segunda situación, los paquetes nunca se sacan de la cola por el mismo motivo que en la primera situación. (Supongamos que el primer paquete es ACKed y el controlador UART desea transmitir el siguiente, pero la cola está vacía en este momento). En este caso, la cola es cada vez más grande y no se transmiten paquetes.

Puedo resolver el primero transmitiendo el primer paquete manualmente (sin el uso de la cola) y poner el resto en la cola. Sin embargo, no es una solución bonita, pero funciona ... todavía tengo que resolver el segundo problema.

Por lo tanto, creo que el controlador UART no es el lugar correcto para hacer la cola de espera ya que no puede tomar en cuenta las dos situaciones que acabo de mencionar. Pero no puedo ponerlo en el bucle principal, ya que tiene la prioridad más baja y luego los problemas de concurrencia se convierten en un problema.

¿Cuál sería una buena manera de implementar esto?

Gracias de antemano :-)

BTW 1: un ACK se transmite al microcontrolador si la PC acepta el paquete transmitido. He hecho una codificación especial de los paquetes para poder determinar su longitud. Esto funciona bien y cmd_tx_pop_cmd () solo mostrará el primer paquete disponible en la cola. He probado todo esto muchas, muchas veces y funciona perfectamente, así que no se centre en esta parte ya que no es el problema.

BTW 2: El microcontrolador es un TM4C123GH6 de la serie Tiva C que se encuentra en el Launchpad de la serie C de Tiva. Estoy usando gcc-arm-none-eabi.

    
pregunta pvh1987

2 respuestas

0

Después de pensar un poco, se me ocurrió una solución. La idea es que solo el manejador de UART (el consumidor) abrirá la cola, ya que tiene una prioridad más alta que el bucle principal y también una prioridad más alta que el manejador de temporizador que realiza las mediciones. Sin embargo, en las dos situaciones que enumeré en mi pregunta anterior, el controlador UART no abrirá la cola porque la cola está vacía en el momento en que el controlador UART recibió un ACK.

La solución que se me ocurrió es informar al productor (el temporizador de medición) que la cola estaba vacía en el último ACK y que el siguiente paquete debe transferirse manualmente (sin el uso de la cola). Esto solucionó la segunda situación. La primera situación se resuelve transmitiendo siempre el primer paquete manualmente.

Cambié el controlador UART a

if (ch == '!')
{
    if (cmd_tx_queue.size == 0)
    {
        cmd_transmit_manually = 1;
        cmd_rx_ack = 0;
    }
    else
    {
        cmd_transmit_manually = 0;
        cmd_tx_pop_cmd();
        cmd_rx_ack = '!';
    }
}

El bucle principal permanece como antes:

if (cmd_rx_ack == ‘!’)
{
   cmd_rx_ack = 0; // Reset ack status

   // Transmit the command
   if (cmd_tx_length > 0)
   {
       cmd_tx_transmit();
   }
}

En el temporizador ISR acabo de verificar si cmd_transmit_manually está configurado. Si es así, borro cmd_transmit_manually y coloco el paquete directamente en la matriz cmd_tx [] y configuro cmd_rx_ack = '!'. Luego, el bucle principal transferirá este paquete cuando regrese el ISR del temporizador.

Si cmd_transmit_manually es 0, el paquete se inserta en la cola en su lugar.

Después de un rato, el controlador UART recibirá el ACK. Si la cola no está vacía, el siguiente comando aparecerá en la matriz cmd_tx [] para que el bucle principal se transfiera. Si está vacío, cmd_transmit_manually se establece en 1. No se puede insertar ningún paquete en la cola mientras se realiza esta comprobación, ya que el controlador UART tiene una prioridad más alta que el controlador del temporizador.

He probado este código muchas veces ahora, con diferentes períodos de tiempo para la medición. Todavía tengo que verlo fallar. También he verificado que no faltan paquetes en la transmisión.

Lo siguiente podría ser crear una función cmd_tx_push_cmd () que se transmita automáticamente de forma manual si cmd_transmit_manually está configurado y, de no ser así, coloca el paquete en la cola. De esa manera, el ISR del temporizador se puede simplificar y el código se puede limpiar un poco.

Si cree que esta no es la mejor solución o si he pasado por alto algo importante, hágamelo saber. Por ahora, parece funcionar como debería, y creo que es una solución bastante simple :-)

    
respondido por el pvh1987
2

En general, un protocolo de transmisión controlado por interrupciones siempre debe iniciarse desde algún lugar fuera de la interrupción.

¿Pero realmente necesitas interrupciones? Esto suena como una aplicación sencilla: el bucle principal comprueba algunas situaciones posibles:

  • temporizador expirado: inicie la conversión A / D
  • Conversión A / D completada: poner el resultado en cola
  • ! recibido: conjunto de transmisión permitido
  • transmisión permitida y no transmisión: si la cola no está vacía: resultado emergente; se permite el tránsito claro; conjunto de transmisión
  • uart buffer empty: transmite el siguiente carácter, o borra la transmisión si no hay ninguno disponible

La parte de transmisión podría borrarse si se expresa en una ETS.

    
respondido por el Wouter van Ooijen

Lea otras preguntas en las etiquetas

Comentarios Recientes

para entregar lógica digital de un procesador a otro! Por ejemplo, los modelos MC8 de muestra manejaban 32 FIFO mientras que uno similar a una PC manejaba 512 FIFO. La notificación de errores no se produjo debido a los circuitos RC básicos lentos, MC5 solo intentó modular solo 8 millones de bits a la vez, mientras que el modelo basado en PC solo produjo alrededor de 500,000 bits. Pero los prototipos de PC también mostraron una gran cantidad de desenfoque de color, que posteriormente se reparó en modelos de chips... Lees verder