Electronic – STM32F103: Can a timer can interfere with uart

stm32stm32f10xuart

I have a simple program, which receives data from UART interface and drives a WS2812b led strip. So, I'm using USART3 to receive data (in IRQ mode) and T3C2 (timer 3, channel 2) to drive LEDs. Here is the code:

https://hastebin.com/rucumovero.cpp

If I use the uart interface without enabling a timer, everything works just perfect, but when I enable the timer I start losing data. For example, here the log if I send 5 similar 32 byte packets [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

every time 3~4 bytes are lost.

I tried to use different baud rate, different usart port – the result is the same. The timer interval is set in line 142:

timer_set_period(TIM3, WSP);

where

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

If I comment out this line, the problem will disappear, but, of course, I won't be able to drive LEDs without it.

So, it looks like I can't drive WS2812b leds and receive data from UART at the same time. Is it supposed to behave like this? Any idea how can I fix it?

Best Answer

Looking at this

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

your timer takes about 100 steps (if i got it right from the specs) and then runs whatever routine you told it to. I couldn't clearly see how much time it takes for your program to make one step, but it seems as if your timer routine should run very often (couple 1000 times per second or more).

Now if your uart routine works as expected without the timer, but loses data when you introduce it, it strongly suggests that the timer disrupts your serial communication.

This could be because:

  1. your timer routine runs to often
  2. the timer routine is too long
  3. the timer interrupt has a higher priority than the uart interrupt.

Or maybe its all three put together.

Possible solutions:

  1. An STM32 has something called the NVIC (Nested Vector Interrupt Controller), which you could use to change the the interrupt-priorities.

  2. When you use two or more interrupts you have to consider that they may run at nearly the same time(this happens more often when both interrupts run at similar frequencies), and one routine may loose information because of this (especially with uart). So you have to think of a way to handle this explicit case -> locking mechanism or altering the priorities.

  3. The longer your routine takes, the higher is the chance that you enter the case described in point two. It's usually good practise to make interrupt routines as short as possible, and never ever use delays or loops inside an interrupt.

  4. Consider if there is a way to run your timer routine considerably less often. This way you at least minimize the chance of data loss, but to completly rule it out, you will have to do the things described in point 1-3.