cancel
Showing results for 
Search instead for 
Did you mean: 

Advanced timer 1 with DMA hangs if compare register equals 0

ELowe
Associate III

Hi!

I have NUCLEO H743-ZI board, and I am trying to create PWM sequence with advanced timer 1, by utilizing DMA feature.

Code is mostly generated by cubeMX.

I am using PWM mode 2, Center-aligned mode 1.

Code works, untill DMA loads into compare register (TIMx_CCR1 register) value 0, than it hangs.

After some digging through HAL code, and manual, I presume this happens because timer stops generating interrupts, which force DMA to load new values into compare register (TIMx_CCR1).

My theory is that interrupts are generated when counter gets bigger than compare value, which never happens (lowest counter value is zero, and zero is not higher than zero, thus no interrupt).

Now how to resolve this issue…..

TIMx DMA/interrupt enable register (TIMx_DIER) has flag „Bit 8 UDE: Update DMA request enable“, but enebling it did not help. Simultaneously I set flag „Bit 0 UIE: Update interrupt enable“, but to no avail, I am still stuck…..

Did anyone came across this problem, and how was it resolved?

At this moment I am not eager to limit lowest compare value to 1 (bigger than zero), because I am using two complementary outputs with dead time, and even a 1 cycle switch-over will cause visible output signal dip.

1 ACCEPTED SOLUTION

Accepted Solutions
ELowe
Associate III

I am writing this for all other fellow MCU enthusiasts, so they don't need to waste time fixing HAL code.

… after 2 weeks of searching, this is what needed to be changed in code generated by CubeMX, to get the required functionality:

My calling function:

	if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)timerCompareValuesTEST, 20) != HAL_OK)
	{
		// Error
		InitializationErrorHandler("ERROR - Unable to start timer 1 DMA, start aborted!");
	}

Commented code needed to be replaced with new lines:

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{
......
//    hdma_tim1_ch1.Init.Request = DMA_REQUEST_TIM1_CH1;
    hdma_tim1_ch1.Init.Request = DMA_REQUEST_TIM1_UP;
.....
//    __HAL_LINKDMA(htim_pwm,hdma[TIM_DMA_ID_CC1],hdma_tim1_ch1);
    __HAL_LINKDMA(htim_pwm,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_ch1);
.....
}
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
{
....
  switch (Channel)
  {
    case TIM_CHANNEL_1:
    {
      /* Set the DMA Period elapsed callback */
//      htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = HAL_TIM_DMADelayPulseCplt;
			htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = HAL_TIM_DMADelayPulseCplt;
     
      /* Set the DMA error callback */
//      htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = HAL_TIM_DMAError ;
      htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = HAL_TIM_DMAError ;
			
      /* Enable t  he DMA Stream */
//      HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1, Length);
			HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1, Length);
      
      /* Enable the TIM Capture/Compare 1 DMA request */
//      __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
			__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_UPDATE);
    }
    break;
....
}

View solution in original post

2 REPLIES 2
RMcCa
Senior II

Set the ccr preload bit and use the update event to trigger the dma. With the preload, the compare register is loaded at the end of cycle, just before the update event and you have nearly the whole cycle to load the next ccr value and the process isn't dependant upon the the value of the ccr register.​

ELowe
Associate III

I am writing this for all other fellow MCU enthusiasts, so they don't need to waste time fixing HAL code.

… after 2 weeks of searching, this is what needed to be changed in code generated by CubeMX, to get the required functionality:

My calling function:

	if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)timerCompareValuesTEST, 20) != HAL_OK)
	{
		// Error
		InitializationErrorHandler("ERROR - Unable to start timer 1 DMA, start aborted!");
	}

Commented code needed to be replaced with new lines:

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{
......
//    hdma_tim1_ch1.Init.Request = DMA_REQUEST_TIM1_CH1;
    hdma_tim1_ch1.Init.Request = DMA_REQUEST_TIM1_UP;
.....
//    __HAL_LINKDMA(htim_pwm,hdma[TIM_DMA_ID_CC1],hdma_tim1_ch1);
    __HAL_LINKDMA(htim_pwm,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_ch1);
.....
}
HAL_StatusTypeDef HAL_TIM_PWM_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)
{
....
  switch (Channel)
  {
    case TIM_CHANNEL_1:
    {
      /* Set the DMA Period elapsed callback */
//      htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = HAL_TIM_DMADelayPulseCplt;
			htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = HAL_TIM_DMADelayPulseCplt;
     
      /* Set the DMA error callback */
//      htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = HAL_TIM_DMAError ;
      htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = HAL_TIM_DMAError ;
			
      /* Enable t  he DMA Stream */
//      HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1, Length);
			HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1, Length);
      
      /* Enable the TIM Capture/Compare 1 DMA request */
//      __HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
			__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_UPDATE);
    }
    break;
....
}