Skip to main content
Visitor II
February 5, 2022
Question

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

  • February 5, 2022
  • 5 replies
  • 1635 views

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

    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

    Graduate II
    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.

    Super User
    February 6, 2022

    Nice trick with the SPI, @Michal Dudka​ !

    JW

    MischaAuthor
    Visitor II
    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;
    }