cancel
Showing results for 
Search instead for 
Did you mean: 

Configuring Idle State for Timers

NSR
Associate III

Hi

I have successfully managed to configure and implement a TIM4 channel 1 as a PWM channel and connect it to DMA. Upon disabling the DMA after a transmit, the output goes high - this was the default and is desired. However, I've taken this further to incorporate TIM3 channel 2 but while everything works as expected, it sits idle low when DMA is disabled.

I'm using the LL drivers to configure this using the CubeMX utility with the STM32F439 MCU. Any help in what function to call and what parameter to pass in order to get the TIM3 channel 2 to sit idle high would be most appreciated.

I can supply code as necessary if required, but hoping that this would be a straight forward answer.

Many thanks

11 REPLIES 11
DNiet.1
Associate II

Sorry for the late response - such is life when you have a full-time job and just bought a house...

@Community member​ : With "Stop DMA" I meant using the HAL function: ç(&htim1, TIM_CHANNEL_2); (for my particular config).

After this, I wanted the pin to stay low, but I think it becomes hi-Z. Tried to solve that using pull-down (in CubeMX, not physically externally), but that didn't help.

Next, I thought to _not_ stop the PWM/DMA like this, but instead leave PWM working for ever, and just put an additional duty cycle byte '\0' at the end of the DMA buffer (so that the duty cycle stays at 0% - even if PWM stays active).

--> this indeed helped, the pin stays low. (I just commented out the HAL_TIM_PWM_Stop_DMA function call in the DMA completed callback;

Next up: how to re-enable a new 'send' of the DMA buffer. For this (and for future readers?) I used the HAL function: HAL_TIM_PWM_Start_DMA.

--> HOWEVER!! This did provide me with the problem that - after an initial delay of ca. 10-15 µs - the pin stays LOW for an amount of time, after which the PWM duty cycles were correctly working again.

After debugging this HAL_TIM_PWM_Start_DMA function, in my case, it executes 4 different things (can't remember which), one of which is a call to HAL_DMA_Start_IT, that triggers the actual DMA PWM cycle.

My final (working) solution is to:

1) Execute HAL_TIM_PWM_Start_DMA only once -> to properly setup certain registers I guess (if you use HAL)

2) Make sure the DMA PWM buffer ends with a 0x00 (to force a 0% PWM duty cycle)

3) Leave PWM ENABLED -> this makes sure the pin stays low (due to the 0% duty cycle as set in 2)

4) Only call HAL_DMA_Start_IT when sending the new PWM 'loop', NOT calling the higher-level HAL_TIM_PWM_Start_DMA function, which apparently does too much and sets the pin LOW for a small period of time, directly after starting DMA.

Thanks for your responses, and I hope this might help future users looking into this as well.

(For reference, the application for this piece of code/question is to drive a LED strip (SK6812-based))

Great answer; this method using "HAL_DMA_Start_IT" worked for me as well. Thank you!!!

static void PWMStartDMAOutput(uint32_t *data, uint16_t size)
{
  static bool first_run = true;
  if (first_run) {
    HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, data, size);
    first_run = false;
  } else {
    HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_CC1], (uint32_t)data, (uint32_t)&(htim2.Instance->CCR1), (uint32_t)size);
  }
}