UART recibe escritura y lectura de búfer

Estoy haciendo una comunicación simple entre un mcu ARM y un módulo GSM.

El problema al que me enfrento es cómo lidiar con la escritura y la lectura simultáneas hacia y desde el búfer FIFO.

Debido a la escala del programa, tengo una gran matriz de búfer de 1000 bytes de longitud.

En este momento, se activa una interrupción cada vez que se recibe un byte en el registro de datos de UART y la rutina de la interrupción está llenando mi FIFO de 1 KB.

Mi rutina de lectura calcula los datos disponibles en FIFO y copia algunos de los datos en un segundo búfer para su posterior procesamiento.

La rutina de interrupción se detiene para poner más datos cuando no queda más espacio en el búfer FIFO, para evitar sobrescribir en el puntero de lectura en los casos en que mi programa principal no tuvo tiempo para procesar los datos.

Ahora estoy tratando de encontrar la mejor solución para evitar sobrescribir en el puntero de lectura, mientras que la rutina de interrupción nunca se detiene para poner datos. ¿Hay alguna solución para esto o la sobreescritura es inevitable?

Un procesador más rápido o un software más rápido.
¿El GSM tiene capacidad de protocolo de enlace?
El uso de señales de control de flujo para evitar que el módulo GSM envíe datos podría ser una alternativa.
¿Cuál es la diferencia entre evitar la rutina de interrupción y sobrescribir en el puntero de lectura?
Configure la interrupción cuando el FIFO esté medio lleno.
¿Por qué necesita un segundo Buffer? El UART llena un búfer circular, luego en la aplicación procesas el búfer. Solo necesitaría incrementar el puntero de lectura y procesar la mayor cantidad de datos recibidos, no copiarlos. No tiene sentido.
Sí, no está muy claro lo que estás preguntando aquí. No puede sacarlo lo suficientemente rápido, está deteniendo el GSM demasiado tiempo, está perdiendo la sincronización, ¿qué?
"... evitar que se sobrescriba en el puntero de lectura mientras que la rutina de interrupción nunca se detiene para poner datos. ¿Hay alguna solución para esto?" - Piénsalo. Si el búfer está lleno, ¿dónde puede la rutina de interrupción almacenar los datos sin sobrescribirlos? Debe drenar el búfer al menos tan rápido como se está llenando, o se desbordará.
@MarkoBuršič Se necesita el segundo búfer para lograr puertos serie virtuales. He implementado el protocolo GSM 0710 en el que tengo que guardar los datos entrantes de cada DLC que uso por separado.
Su primer paso es desglosar el trabajo que necesita realizar y decidir cuánto tiempo necesita la CPU para todas las tareas. Luego, averigüe si alguna parte del proceso puede estancarse para adaptarse a recursos insuficientes.
@MarkoBuršič. Usted puede tener la mejor respuesta. Un ISR DEBE hacer su trabajo y salir rápido. OP puede tener que comprometerse moviendo 1/2 contenido FIFO a la vez. Tal vez la MPU es demasiado lenta. OP no especificó las velocidades de reloj de MPU o UART
Si se esperan desbordamientos del búfer en la práctica y deben tolerarse, entonces, sin un apretón de manos, se puede suponer que un búfer lleno tiene la misma probabilidad de significar la pérdida de datos. Simplemente vaciaría el búfer si alguna vez se llena para que los datos que se sabe que están truncados no se analicen innecesariamente y uno pueda acelerar con datos válidos antes. Leer hasta un final de 'bloque' válido podría ser un compromiso antes de vaciar.
Hay una regla fundamental de colas/búferes: si su sistema no es lo suficientemente rápido para manejar los datos entrantes, entonces ninguna cantidad de colas y trucos lo salvará.

Respuestas (2)

En el evento de recepción de UART:

    FIFO[Wr_pointer]= UART_Char;
    WR_Pointer++;
    WR_Pointer & = 3FF;// FIFO[1024] roll over 1022..1023...0...1...2
    if WR_Pointer==RD_Pointer then
        Overrun= true;
    else
    {
        SizeFIFO = (WR_Pointer - RD_Pointer);
        SizeFIFO & = 3FF;
    }

Ejemplo de búfer circular. No hay necesidad de copiar datos de FIFO a otra ubicación ya que los datos simplemente se sobrescriben.

En la aplicacion:

SizeFIFO_temp = SizeFIFO; //you don't want a bug when ISR will insert new data while processing the buffer
for i=0 to SizeFIFO_temp  do
{
   Data[i]=FIFO[RD_Pointer]; //it's all up to you how you process the FIFO's data
   RD_Pointer++;
   RD_Pointer &= 3FF; 
}
SizeFIFO = (WR_Pointer - RD_Pointer);
SizeFIFO & = 3FF;
Creo que te perdiste la parte donde dice "copia algunos de los datos en un segundo búfer para su posterior procesamiento". No indica cuánto tiempo necesita permanecer allí.
@Trevor_G Puede procesarlo siempre que el búfer no se sobrescriba con nuevos datos, se desborde. Esto es válido para ambos casos, si copia una parte del búfer o procesa los datos dentro del mismo búfer.
Sí, la pregunta tiene algunos agujeros grandes.
Los datos deben copiarse del fifo a otro búfer porque los datos entrantes del GSM son marcos entrantes del protocolo GSM 0710 que se utiliza para los puertos serie virtuales. Cada DLC debe tener su propio búfer porque alguna respuesta AT puede recibirse con más de un cuadro con muchos milisegundos (o incluso unos pocos segundos) entre ellos, mientras que los cuadros siempre se reciben para otros DLC. ( etsi.org/deliver/etsi_ts/101300_101399/101369/07.01.00_60/… ). Entonces, copio un nuevo marco en un segundo búfer para indicar que se ha recibido un nuevo marco.
@MrBit Puede ampliar su pregunta ya que no está claro qué problemas encuentra. Como mostrar una parte de la rutina ISR y la rutina de lectura.

El problema al que me enfrento es cómo lidiar con la escritura y la lectura simultáneas hacia y desde el búfer FIFO.

Secuencial No paralelo.

Ahora estoy tratando de encontrar la mejor solución para evitar sobrescribir en el puntero de lectura mientras que la rutina de interrupción nunca se detiene para poner datos.

El código nunca debe existir siempre en el ISR (generalmente, depende de la aplicación). Necesita tiempo para copiar datos, procesar datos, restablecer banderas y varios estados, etc. antes de que se pueda procesar una nueva solicitud. Si siempre estás recibiendo datos ¿cuándo harás el resto?.

1.Cuando ocurre una interrupción: deshabilite la interrupción (muchos se olvidan de hacer esto)

2. Dado que tiene un búfer de 1K (desperdicio de memoria, implemente un búfer circular de menor longitud), copie los datos en un búfer y observe un contador cuando se reciba la cantidad mínima de bytes necesarios para un procesamiento. No olvide habilitar el ISR nuevamente y restablecer el contador antes de salir del ISR.

3. Cuando se reciba el número mínimo de bytes necesarios para un procesamiento, procese los datos.

Alternativamente, puede hacer que el uC sea el maestro que sondea el GSM en busca de datos cuando sea necesario para que tenga el control, en lugar de que GSM le envíe datos siempre.

Para Cortex-M, un estilo de codificación válido es tener todo el código funcional en los ISR y usar la característica de 'reposo al salir' para estar inactivo cuando no hay ninguna excepción que manejar. Su cuarto párrafo parece contrario a esto.
Para un sistema basado en eventos, tiene sentido poner el sistema en suspensión una vez que se atiende el evento.
Decir 'el código nunca debe existir en el ISR' es incorrecto. A veces, TODO el código del sistema está en ISR.
hmm... modifiqué la respuesta