Skip to main content
JSzem.1
Associate II
March 2, 2020
Question

STM32F411 multiple Channels on timer with DMA

  • March 2, 2020
  • 10 replies
  • 3300 views

Is it possible to run two or more channels on timer with DMA PWM mode?

This code starts only first Channel.

uint32_t PrawoPWM = 100; 

uint32_t LewoPWM = 100; 

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_1 , &PrawoPWM, 1); 

HAL_TIM_PWM_Start_DMA(&htim4, TIM_CHANNEL_2 , &LewoPWM, 1);

How can I start two channels?

This topic has been closed for replies.

10 replies

waclawek.jan
Super User
March 2, 2020

You probably want to use the TIMx_DCR/TIMx_DMAR-based mechanism. Read the TIM chapter in RM.

I don't Cube, but you may be able to find an example in Cube, it appears that in Cube lingo this is called "DMA Burst".

JW

berendi
Principal
March 3, 2020

Why do you want to use DMA with a single value per channel? What do you want to achieve exactly?

JSzem.1
JSzem.1Author
Associate II
March 3, 2020

I have an application where I need 4 channels with the same frequency but independent duty. This is for 4 motors.

berendi
Principal
March 3, 2020

Do the duty cycle values change in every cycle?

JSzem.1
JSzem.1Author
Associate II
March 3, 2020

No. It is independent. Duty will be change from another part of program.

waclawek.jan
Super User
March 3, 2020

This is the very purpose of the mechanism I mentioned above.

JW

JSzem.1
JSzem.1Author
Associate II
March 3, 2020

I will try DMA Burst.

Do you know how to use HAL for this purpose?

berendi
Principal
March 3, 2020

I still don't think that DMA is required for this.

I have no idea how to use HAL functions properly, here an example using the register interface.

Set period and duty cycle for all channels.

TIM4->ARR = period - 1;
TIM4->CCR1 = duty1 - 1;
TIM4->CCR2 = duty2 - 1;
TIM4->CCR3 = duty3 - 1;
TIM4->CCR4 = duty4 - 1;

Set PWM mode 1 and enable preload on all channels

TIM4->CCMR1 = TIM_CCMR1_OC2M_1|TIM_CCMR1_OC2M_2|TIM_CCMR1_OC2PE | TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_2|TIM_CCMR1_OC1PE;
TIM4->CCMR2 = TIM_CCMR2_OC4M_1|TIM_CCMR2_OC4M_2|TIM_CCMR2_OC4PE | TIM_CCMR2_OC3M_1|TIM_CCMR2_OC3M_2|TIM_CCMR2_OC3PE;

Enable channel outputs

TIM4->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E;

Enable the counter

TIM4->CR1 = TIM_CR1_CEN;

Now you can change duty cycle values any time directly writing the CCR1 - CCR4 registers.

If perfectly synchronized changes are required, write the CCR registers just after the update event, either polling for it, or from the update interrupt handler.

volatile uint32_t duty1, duty2, duty3, duty4;
/* assign values to duty1 - duty 4 */
TIM4->DIER = TIM_DIER_UIE; // enable update interrupt
void TIM4_IRQHandler(void) {
 TIM4->SR = 0; // reset status flags
 TIM4->DIER = 0; // disable interrupts, they are no longer needed after the update
 TIM4->CCR1 = duty1;
 TIM4->CCR2 = duty2;
 TIM4->CCR3 = duty3;
 TIM4->CCR4 = duty4;
}

Laurent Ca...
Senior III
October 16, 2020

Dear @JSzem.1​ 

Did any of the answers here help you solve your problem?

Best regards

Laurent Ca...

Laurent Ca...
Senior III
November 2, 2020

Dear @JSzem.1​ 

As you do not answer, I guess you don't have to solve this problem anymore, therefore I consider this thread closed.

If not, feel free to reopen it by posting a new answer.

Best regards

Laurent Ca...