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

> implement a TIM4 channel 1 as a PWM channel and connect it to DMA.

Elaborate. What does the DMA do? What do you mean exactly by "DMA disabled" and why would TIM output go to any state you call idle.

I don't think timer output is related to DMA enabled or disabled, except indirectly. If the DMA changes the timer registers, it's then the last transfer which determines the timer's future behaviour.

JW

NSR
Associate III

Hi waclawek.jan, thanks for taking the time to respond.

OK, in CubeMX, I have the following configured:

TIM4 -> Channel 1, PWM Gen CH1

 the parameters are configured accordingly for the clock running at 180MHz

 GPIO modified to allow maximum output speed to very high

DMA -> TIM4_CH1, DMA1 Stream 0, Memory to Peripheral

 circular, increment memory address with word widths

NVIC -> TIM4 global interrupt - check

NVIC -> DMA1 stream0 global interrupt - check

 /* USER CODE BEGIN TIM4_Init 2 */
 LL_TIM_OC_SetCompareCH1(TIM4, LL_TIM_GetAutoReload(TIM4) / 20 - 1);
 LL_TIM_CC_EnableChannel(TIM4, LL_TIM_CHANNEL_CH1);
 LL_TIM_EnableDMAReq_CC1(TIM4);
 /* USER CODE END TIM4_Init 2 */

and to switch on:

	LL_DMA_SetMode(DMA1, LL_DMA_STREAM_0, LL_DMA_MODE_CIRCULAR);
	LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_0, (uint32_t)data);
	LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_0, 48);
	LL_DMA_ClearFlag_TC0(DMA1);
	LL_DMA_ClearFlag_HT0(DMA1);
	LL_DMA_EnableIT_HT(DMA1, LL_DMA_STREAM_0);
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_0);
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_0);
	LL_TIM_CC_EnableChannel(TIM4, LL_TIM_CHANNEL_CH1);
	LL_TIM_EnableCounter(TIM4);

and to switch off:

	LL_TIM_CC_DisableChannel(TIM4, LL_TIM_CHANNEL_CH1);
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);

When the channel is switched off using the appropriate code above, the line goes high - this is desired.

Adding an additional channel:

TIM3 -> Channel 2, PWM Gen CH2

 the parameters are configured accordingly for the clock running at 180MHz

 GPIO modified to allow maximum output speed to very high

DMA -> TIM3_CH2, DMA1 Stream 5, Memory to Peripheral

 circular, increment memory address with word widths

NVIC -> TIM3 global interrupt - check

NVIC -> DMA1 stream5 global interrupt - check

 /* USER CODE BEGIN TIM3_Init 2 */
 LL_TIM_OC_SetCompareCH2(TIM3, LL_TIM_GetAutoReload(TIM3) / 20 - 1);
 LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH2);
 LL_TIM_EnableDMAReq_CC2(TIM3);
 /* USER CODE END TIM3_Init 2 */

and to switch on:

	LL_DMA_SetMode(DMA1, LL_DMA_STREAM_5, LL_DMA_MODE_CIRCULAR);
	LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_5, (uint32_t)data2);
	LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, 48);
	LL_DMA_ClearFlag_TC5(DMA1);
	LL_DMA_ClearFlag_HT5(DMA1);
	LL_DMA_EnableIT_HT(DMA1, LL_DMA_STREAM_5);
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_5);
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5);
	LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH2);
	LL_TIM_EnableCounter(TIM3);

and to switch off:

	LL_TIM_CC_DisableChannel(TIM3, LL_TIM_CHANNEL_CH2);
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_5);

When this channel is switched off using the appropriate code above, the line goes low - this is not desired.

Having moved from TIM3 Channel 2 to TIM3 Channel 3 and DMA1 Stream5 to DMA1 Stream7, I now have the desired output idle level. However, I would still like to use the TIM3 Channel 2 and would therefore like to know how to get the idle level to be high when using the code above to switch the channel off.

I hope this makes it a little more clearer.

Thanks

This has nothing to do with DMA.

LL_TIM_CC_DisableChannel(TIM3, LL_TIM_CHANNEL_CH2);

This is what you're looking for - it probably (I don't use Cube) clears TIMx_CCER.CCxE. In normal timers (i.e. not the advanced ones as TIM1, TIM8, TIM15) this makes the pin threestate. If you want to have it in a certain state, use pullup/pulldown in GPIO. You might have used that, or you have some external pullup/pulldown or some other connected device acting as pullup/pulldown - that would explain the difference.

JW

NSR
Associate III

Appreciate your comment regarding the DMA, indeed one of the instructions is to just stop (or disable) the DMA while the other is to stop (or disable) the timer. In the relative GPIO section I've tried

  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;

as well as to tie the output line high via a 10k resistor - both to no avail. I'm wondering if this is a characteristic of the odd/even channel configuration of the timers, especially having achieved the high idle state in TIM4 Channel1 and TIM3 Channel3?

I'll look further to find relative registers such as TIMx_CCER.CCxE that you've mentioned, thanks.

Read out and check/post/compare ("working" vs. "nonworking") the relevant TIM/GPIO registers at the moment of being "idle".

JW

DNiet.1
Associate II

Dear @NSR​ ,

Hoping to resurrect the thread enough for you to answer: did you solve the issue?

I have the exact same issue (but the other way around: TIM1 CH2 PWM goes high after I stop PWM DMA, and I want to have it low; setting internal pull-down doesn't work, neither does setting duty cycle to 0).

Which STM32?

What is "I stop PWM DMA"? Some Cube/HAL functionality? Find out what does that do to the TIM registers.

Or, maybe simpler, when you "stop PWM DMA", just change the given pin in GPIO_MODER from AF to Out, and then you can set it to whatever level you want.

JW

NSR
Associate III

Hi

I managed to find a different way of doing what I needed to do.

However, one thing that I have learned is that if you're using a Nucleo board, as one generally does to kick off development, you may find some of the connecting pins have a particular configuration in mind, which may involve using solder bridges to configure accordingly. While you can still configure the pin how you like, there may be pull-up/-down resistors or other external circuitry that may affect what you're trying to achieve. Check the Nucleo manual according to the board you're using, if that is the case, in the section that discusses configuration and solder bridges.

Hope​ this helps

NSR
Associate III

I've looked into this a little further. Pin function using TIM1_CH2 can be obtained using PE11 or PA9. This is of course assuming that you're using the same STM32F439ZI on a Nucleo-144 Development Board.

When using PA9, you will probably experience a configuration clash, please refer to https://www.st.com/resource/en/user_manual/um1974-stm32-nucleo144-boards-mb1137-stmicroelectronics.pdf p.27:

 PA9 USB VBUS

Configuration when using USB connector: SB127 ON

Configuration when using ST morpho connector: SB127 OFF

TIM1_CH2 when configured as using PA9 then it is either pin 19 of CN9 (D69) or pin 21 of CN12. I cannot tell what the default configuration of the solder bridge is as I don't have the board with me.

My advice would be to try using PE11, which is on pin 6 (D5) of CN10 or pin 56 of CN12. There doesn't appear to be any configuration clashes using this pin on Nucleo-144 boards,

Hope this helps.