Skip to main content
Mischa
Associate
February 5, 2022
Question

STM32G071: TIM1+PWM+DMA 2nd pulse looks strange

Hi,

I'm trying to talk to WS2812 RGB Leds. I'm using TIM1 CH3 PWM Output with DMA. Everything looks almost fine. I'm always sending the same data using:

HAL_TIM_PWM_Start_DMA (&htim1, TIM_CHANNEL_3, (uint32_t *) pwmData, (24 * NUM_OF_LEDS) + 50);

Here pwmData sets a duty cycle of 33 % (20 of period 60, 48 MHz) for the first 13 cycles. In between I wait for 500 ms.

But time to time (~1 out of 3) the second pulse behaves strange. Only the second pulse seems to randomly jump approx. from duty cycle 20 ... 80 %. All remaining pulses are correct.

Thanks for any hint!

This topic has been closed for replies.

5 replies

waclawek.jan
Super User
February 5, 2022

I don't use Cube and don't know how exactly Cube does this thing, but under certain circumstances (CCR preload enabled), the first two pulses may actually be result of the last two values in buffer from the previous run.

Try using deliberately different duty cycles in the first few cycles, like 30% in first, 40% in second etc., and observe.

JW

Michal Dudka
Lead
February 6, 2022

With timer you have to manage some complications with proper DMA request source, preloads etc. Consider using SPI instead timer. SPI can simply generate pulse train that you need on MOSI line (let SCK free). Imagine sending byte with bitrate 8Mb/s bit sequence:

0b11100000 generates pulse width 3*1/8=375ns and space 625ns

0b11111000 generates pulse width 5*1/8=625ns and space 375ns

Moreover by variating SPI bitrate and message bit length (up to 16bits) you can sending multiple WS2812 bits in one byte/word. It can be realised much more easier then handling timers.

waclawek.jan
Super User
February 6, 2022

Nice trick with the SPI, @Michal Dudka​ !

JW

Mischa
MischaAuthor
Associate
February 6, 2022

@Michal Dudka​  I like that idea using SPI, too. Thanks!

Visitor II
February 10, 2025

I'm a little late, but maybe I can help someone with the same issue.

I solved that problem by adding two zeros before the data. You need to declare:

uint16_t pwmData[24*NUM_OF_LEDS + 52]

Then, before adding the data, you need to do this:

pwmData[0] = 0;
pwmData[1] = 0;

For some reason, the second data sent from DMA to PWM gets glitched. Sending two null values before the data solves that problem.

 

 

void WS2812_Send(TIM_HandleTypeDef *htim, uint8_t TIM_CHANNEL) {
 uint32_t color;
 uint16_t indx = 2;

 pwmData[0] = 0;
 pwmData[1] = 0;

 for (int i = 0; i < NUM_LEDS; i++) {
 color = ((LED_Data[i][1] << 16) | (LED_Data[i][2] << 8) | (LED_Data[i][3]));

 for (int bit = 23; bit >= 0; bit--) {
 pwmData[indx++] = (color & (1 << bit)) ? 34 : 17;
 }
 }

 for (int i = 0; i < 50; i++) {
 pwmData[indx++] = 0;
 }

 HAL_TIM_PWM_Start_DMA(htim, TIM_CHANNEL, (uint32_t *)pwmData, indx);

 while (!datasentflag) {}
 datasentflag = 0;
}