Tengo un microcontrolador TM4C123GXL Launchpad, que tiene 8 puertos seriales UART. Estoy usando Keil uVision5 con Tiva Ware para programar.
Quería conectar 3 dispositivos UART con el microcontrolador sin pérdida de bytes. La tasa de baudios se ha establecido en 115200 bits/s sin paridad, como se muestra en la figura a continuación. Todos los dispositivos enviaron tramas de datos periódicamente cada 5 ms.
El tiempo de TX y RX se calcula usando No_0f_bytes*10/BaudRate
He interconectado con éxito los dispositivos con el UART de µC. El problema en la comunicación es que estoy perdiendo los bytes. Si hago una comunicación con un solo dispositivo (Dispositivo 2) sigo perdiendo los bytes de todo el marco (20 bytes).
¿Se debe a la limitación FIFO de 16 bytes de Tm4c123 o algo más?
También he implementado la función µDMA de TM4C123. Pero aún así, se pierden bytes. ¿Qué puedo hacer para mejorar el sistema de transmisión y recepción sin pérdidas de tramas de datos?
Editar:
Aquí está la arquitectura de software:
Estoy usando Interrupción periódica del temporizador de 5 ms para recibir y transmitir la trama. Todos los marcos tienen los primeros 2 bytes de encabezado y un contador de bytes como último byte.
void Timer1IntHandler(void) // Periodic Service Routine every 5ms
{
DisableIntrupts();
bool Correct=ReadJoystick(); //10 bytes Device 1
if(Correct)
{
GenerateServoCardsFrame();
SendServo1Frame(); //20 bytes Device 2
SendServo2Frame(); //17 bytes Device 3
ReadServo1Frame(); //15 bytes Device 2
ReadServo2Frame(); //20 bytes Device 3
GenerateJoystickFrame();
SendJoystickFrame(); //10 bytes Device 1
EnableIntrupts();
}
}
main()
{
SetupClock() ; //Setup 16 MHz Clock
SetupJoystick(); //Initalize uart1 port for Device1
SetupServoCard1(); //Initalize uart2 port for Device2
SetupServoCard2(); //Initalize uart3 port for Device3
InitalizePeriodicTimerHandler(5); //Periodic Service Routine every 5ms (Timer1IntHandler)
while(1)
{
}
}
bool ReadJoystick(void)
{
int BytePos=0;
int CountInvalid=0;
int LoopoutTime=0;
while(1)
{
if (ROM_UARTCharsAvail(UART1))
{
ByteRX = ROM_UARTCharGetNonBlocking(UART1);
if (BytePos==0)
{
if (ByteRX== 0xA1) //Header1 found
{
KArray[0] = Bytebuf ;
BytePos ++;
}
else
{
CountInvalid++;
if (CountInvalid>5)
return 0;
}
}
else if (BytePos ==1)
{
if (ByteRX == 0x66) //Header2 found
{
KArray[1] = ByteRX;
BytePos ++;
}
else
BytePos=0;
}
else
{
KArray[BytePos++] = ByteRX;
if (BytePos==10)
return 1; //Frame Recived
}
}
else
{
SysCtlDelay(0.25*SysCtlClockGet()/3 / 1000); // 0.25ms delay
LoopoutTime++;
if (LoopoutTime > 10)
return 0;
}
}
}
Según mi cálculo, 1 byte requiere 10/115200=0.08680ms y para leer un FIFO de 16 bytes requiere 1.38ms. La tabla de la figura muestra un tiempo Tx total de 4,08 ms y un tiempo Rx de 3,91 ms, lo que suma 8 ms. Esto es mayor que mi rutina de servicio de interrupción periódica.
¿Tengo que aumentar el tiempo de interrupción periódica?
El diseño de su software no es bueno y es probablemente la razón por la que se pierden los bytes entrantes.
Primero, no estoy seguro de si esto es un error o un error tipográfico. Deshabilita las interrupciones al principio Timer1IntHandler()
, pero luego solo las vuelve a habilitar si Correct
es cierto. ¿No desea volver a habilitar las interrupciones antes de regresar, independientemente del condicional? Parece extraño que las interrupciones puedan quedar deshabilitadas cuando la función regresa.
Parece que su código lee caracteres de UART1 solo dentro de la ReadJoystick()
función. Y sospecho que UART1 no se lee mientras GenerateServoCardsFrame()
se SendJoystickFrame()
llaman todas esas funciones. ¿Cuánto tiempo tardan en ejecutarse esas funciones? ¿Esas funciones podrían tomar el tiempo suficiente para que el UART1 FIFO se llene y se desborde? Esto podría ser cuando se descartan los bytes entrantes.
Si estuviera diseñando este software, lo implementaría de manera completamente diferente a como lo ha hecho usted. Habilitaría la solicitud de interrupción de UART y crearía una rutina rápida de manejo de interrupciones de UART. Lo único que haría UART ISR es copiar bytes hacia/desde los registros UART TX/RX. Crearía dos búferes circulares (también conocidos como anillos) para contener los bytes. El UART ISR copiaría un byte recibido del registro UART RX al búfer circular RX. Y el UART ISR copiaría un byte para transmitir desde el búfer circular TX al registro UART TX. El UART ISR no intentaría interpretar el significado de ninguno de los bytes. Todo lo que hace es mover bytes entre los búferes de RAM y el periférico UART. Esto mantiene corto el UART ISR, lo que permite que el programa general responda mejor a otras interrupciones.
Luego, crearía una main()
función con un bucle infinito y, dentro del bucle infinito, llamaría a una función llamada SerialReceive()
para leer mensajes del búfer RX. SerialReceive()
se implementaría como una máquina de estado. Si hay bytes disponibles en el búfer RX, procesará un número finito de bytes a través de la máquina de estado. La máquina de estado tendría estados para el encabezado del cuadro, el cuerpo y el tráiler similar a lo que ha hecho. SerialReceive()
regresa inmediatamente cuando se completa un mensaje o no hay más bytes disponibles. Cuando un mensaje está incompleto porque no hay más bytes disponibles de inmediato, SerialReceive()
no los esperará, sino que recordará el estado y el mensaje actuales para que pueda continuar con el mismo mensaje cuando se lo llame nuevamente desde main()
.
Si necesita hacer algo periódicamente, configure un temporizador como lo ha hecho, pero en lugar de hacer todo el trabajo dentro del ISR del temporizador, simplemente configure una bandera. El bucle infinito principal debe verificar repetidamente la bandera y hacer lo que sea apropiado cuando el temporizador ISR ha establecido la bandera. Hacer el trabajo desde el contexto de main()
significa que el sistema puede responder a otras interrupciones mientras está haciendo el trabajo.
Mantener los ISR breves permite que el sistema en general responda mejor a otras solicitudes de interrupción. Si pasa demasiado tiempo en un ISR, como creo que está haciendo en su temporizador ISR, entonces el sistema no responderá.
Actualización: en su comentario, dice que esas funciones se repiten hasta que se completan las transmisiones y toman más de 7 milisegundos. Es tiempo suficiente para que lleguen 80 bytes al UART y su código no lee esos bytes durante este tiempo, por lo que, por supuesto, se perderán bytes.
Sus funciones de transmisión deben copiar bytes en el búfer TX y regresar sin esperar a que se transmita el mensaje completo. El UART ISR debe transmitir un byte cada invocación mientras que el búfer TX contiene bytes.
El búfer RX y TX debe ser más grande que cualquier mensaje. Por lo general, los búferes tienen un tamaño de potencia de dos porque eso hace que sea más fácil rodear los punteros del búfer hasta el principio. Así que hazlos de 256 bytes (o 128 o 64, pero ¿por qué no más grandes?).
Debe tener un conjunto independiente de búferes RX/TX para cada UART.
Cambiar el período de su temporizador periódico ISR no afectará el problema con su código original. Dentro de su ISR periódico, su código está gastando 7 milisegundos NO leyendo el UART. Su código perderá bytes independientemente del período del temporizador.
mitu raj
Masud Salik
mitu raj
Masud Salik
mitu raj
krambo
mitu raj
broma
broma
broma
Masud Salik
broma
Masud Salik
broma
broma
broma
Lundin
volatile
errores por todas partes. La forma demain
uso es de la era de los dinosaurios, lo que sugiere que se utiliza un mal compilador. Etcétera.Masud Salik
broma
Masud Salik
broma
broma