5 votos

STM32F103: ¿Puede un temporizador puede interferir con uart?

Tengo un programa simple, que recibe datos de la interfaz UART y maneja una tira led WS2812b. Estoy usando USART3 para recibir datos (en modo IRQ) y T3C2 (timer 3, canal 2) para manejar los LEDs. Aquí está el código:

https://hastebin.com/rucumovero.cpp

Si uso la interfaz uart sin habilitar un temporizador, todo funciona perfectamente, pero cuando habilito el temporizador empiezo a perder datos. Por ejemplo, aquí el log si envío 5 paquetes similares de 32 bytes [0x41..0x60].

read 29 byte(s): 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 
read 29 byte(s): 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 60 
read 28 byte(s): 41 42 43 44 45 46 47 48 49 4A 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5D 5E 5F 60 
read 29 byte(s): 41 42 43 44 45 46 47 48 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 5A 5B 5C 5D 5E 5F 60

cada vez que se pierden 3~4 bytes.

Intenté usar otra velocidad de transmisión, otro puerto usart - el resultado es el mismo. El intervalo del temporizador se establece en la línea 142:

timer_set_period(TIM3, WSP);

donde

#define TICK_NS (1000/72)
#define WSP (1300 / TICK_NS)

Si comento esta línea, el problema desaparecerá, pero, por supuesto, no podré conducir LEDs sin ella.

Entonces, parece que no puedo manejar los leds WS2812b y recibir datos de la UART al mismo tiempo. ¿Se supone que debe comportarse así? ¿Alguna idea de cómo puedo solucionarlo?

3 votos

Primero determina si estás ante un fallo de hardware (ej: trama corrupta debido al PWM del LED) o de software (ej: algo se detiene demasiado tiempo). Sugerencia: USART_SR->ORE.

0 votos

@Jeroen3 ¡Gracias! Sí, estoy recibiendo USART_SR_ORE bandera cuando estoy perdiendo datos. ¿Hay alguna manera de encontrar la razón de rebasamiento?

1 votos

He tenido alguna experiencia con la pérdida de datos y (alta velocidad de transmisión) UART. La única buena solución parece ser usar la prioridad de interrupción más alta para la UART (y sólo para la UART) y asegurarse de que la IRQ de la UART sólo está deshabilitada durante periodos muy cortos (por ejemplo, cuando se evalúa el buffer de recepción). En mi caso no podía usar el DMA porque no sabía cuántos bytes iba a recibir.

6voto

luchador Puntos 74

Creo que el problema es el tiempo empleado por la rutina de interrupción del temporizador y que no has configurado las prioridades. O haces la rutina del timer lo suficientemente eficiente, o haces un buffer DMA para la UART, o subes la prioridad (numero de prioridad mas bajo) de la interrupcion uart (lo que puede significar fallos visuales en la pantalla, en este caso haz partes criticas del codigo del timer no-interrumpibles y mira si es suficiente para ayudar a la UART).

También puedes unificarlas todas en una rutina de interrupción del temporizador. Puedes hacer la frecuencia del temporizador lo suficientemente rápida para la UART sin buffer DMA y sondearlo y ejecutar el código normal del temporizador con una frecuencia más baja, o, hacer un buffer DMA y ejecutar el temporizador tan lento como el código normal necesite y sondear el buffer UART. Esto hace las cosas más deterministas en contraste con el sondeo en el modo de proceso.

0 votos

Gracias por su respuesta. Parece que el ajuste de prioridad funciona para mí, pero voy a hacer algunos cambios en la rutina de interrupción (este no es mi código - Yo sólo lo uso como es)

6voto

user8837440 Puntos 76

Mirando esto

#define TICK_NS (1000/72)
#define WSP (1300 / TICK_NS)

su temporizador toma alrededor de 100 pasos (si he entendido bien de las especificaciones) y luego se ejecuta cualquier rutina que le dijo que. No pude ver claramente cuánto tiempo le toma a tu programa hacer un paso, pero parece como si tu rutina del temporizador debiera ejecutarse muy a menudo (un par de 1000 veces por segundo o más).

Ahora bien, si tu rutina uart funciona como se espera sin el temporizador, pero pierde datos cuando lo introduces, sugiere fuertemente que el temporizador interrumpe tu comunicación serie.

Esto podría deberse a que:

  1. su rutina de temporizador se ejecuta con demasiada frecuencia
  2. la rutina del temporizador es demasiado larga
  3. la interrupción del temporizador tiene mayor prioridad que la interrupción del uart.

O quizá sean las tres cosas juntas.

Posibles soluciones:

  1. Un STM32 tiene algo llamado NVIC (Nested Vector Interrupt Controller), que puedes usar para cambiar las prioridades de las interrupciones.

  2. Cuando utilizas dos o más interrupciones tienes que tener en cuenta que pueden ejecutarse casi al mismo tiempo (esto ocurre más a menudo cuando ambas interrupciones se ejecutan a frecuencias similares), y una rutina puede perder información debido a esto (especialmente con uart). Así que tienes que pensar en una manera de manejar este caso explícito -> mecanismo de bloqueo o alterar las prioridades.

  3. Cuanto más se alargue tu rutina, mayor será la probabilidad de que entres en el caso descrito en el punto dos. Normalmente es una buena práctica hacer rutinas de interrupción tan cortas como sea posible, y nunca utilizar retardos o bucles dentro de una interrupción.

  4. Considere si hay alguna forma de ejecutar su rutina de temporizador con bastante menos frecuencia. De esta forma al menos minimizas la posibilidad de pérdida de datos, pero para descartarla por completo, tendrás que hacer lo descrito en el punto 1-3.

3 votos

Posible solución 5: Considere no utilizar interrupciones para controlar la tira de LEDs. Especialmente si el tiempo no es crítico debería ser suficiente para esperar hasta un cierto punto en el tiempo en el bucle principal.

0 votos

@Michael ¿No es lo mismo que aumentar la prioridad de interrupción?

0 votos

@user8837440 ¡Gracias por tu respuesta! ¿Cuál es la mejor manera de medir los intervalos de tiempo para depurar la frecuencia del temporizador y para evaluar cuánto tiempo se ejecuta mi rutina de controlador de interrupción?

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X