cancel
Showing results for 
Search instead for 
Did you mean: 

PWM DMA to drive WS281x LED generates inconsistent period and waveform

nico23
Senior II

I'm trying to drive the PWM of an STM32G0 but the waveform generated had an inconsistent period between bit 0 and bit 1, and I can't understand why

nico23_0-1757060068608.png

I'm using TIMER 4 on Channel 2. On the main.c I'm initializing MX_DMA_Init

void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA1_Channel2_3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
}

and TIM4 configured as 

void MX_TIM4_Init(void)
{
  /* USER CODE BEGIN TIM4_Init 0 */
  HAL_TIM_Base_DeInit(&htim4);
  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 0;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 60 - 1;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  
  /* USER CODE BEGIN TIM4_Init 2 */

  /* USER CODE END TIM4_Init 2 */
  HAL_TIM_MspPostInit(&htim4);
}

The HAL_TIM_MspPostInit has 

__HAL_RCC_GPIOD_CLK_ENABLE();
    /**TIM4 GPIO Configuration
    PD13     ------> TIM4_CH2
    PD14     ------> TIM4_CH3
    PD15     ------> TIM4_CH4
    */
    GPIO_InitStruct.Pin = OUT_uC3_Pin|OUT_uC2_Pin|OUT_uC1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

with 

#define OUT_uC3_Pin                     GPIO_PIN_13
#define OUT_uC3_GPIO_Port               GPIOD

The led_render function correctly fills the buffer with

    // Fill with alternating pattern: HI, LO, HI, LO...
    for(uint8_t i = 0; i < WR_BUF_LEN; i++) {
        wr_buf[i] = (i % 2) ? PWM_HI : PWM_LO;
    }
    
    HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2, (uint32_t *) wr_buf, WR_BUF_LEN);

and in the .h

#define PWM_HI (38)
#define PWM_LO (19)
// LED parameters
#define NUM_BPP (3) // WS2812B
#define NUM_PIXELS (18)
#define NUM_BYTES (NUM_BPP * NUM_PIXELS)

But for some reason I'm seeing a the strange, not correct, waveform

Am I doing something wrong?

2 REPLIES 2
waclawek.jan
Super User

What is the expected waveform and how is the observed one different?

[EDIT] Assuming timer clock is equal to system clock, 60 cycles may be sufficient for DMA, but AFAIK Cube/HAL does not use the Update event to load TIMx_CCRx but the CC event, which may leave much less time, and result in DMA not feeding the TIMx_CCRx fast enough. I don't say this *is* the problem here (as I don't know what are the symptoms, see my first question), but may be a thing to consider. Try longer times, or higher system clock frequency. 

JW

gbm
Principal

What is the declaration of wr_buf and where is it placed?

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice