Showing results for 
Search instead for 
Did you mean: 

How to get 0% and 100% duty cycle for PWM using DMA, in STM32F103C8T6.

Associate II

My board is STM32F103C8T6.

I am generating complementary PWM using TIMER 1 with DMA for changing duty cycle.

to be precise SINE WAVE PWM (or SPWM) using CENTRE ALIGNED MODE 2.

Now i also want to generate SQUARE wave from channel2 , the wave should have time period of DMA length.

so lets say DMA(sPWM) contains 100 elements , channel2 should generate square wave,

which is HIGH for first 50 elements and LOW for last 50 elements of DMA(of sPWM)(see Picture attatched).

Now I know I can't have different frequency on same timer .

To do this I have created another DMA buffer for channel 2 which contains ,

first 50 element equals to ARR and last 50 elements 0.

But if I put 0 or max The generated square period sometime becomes small or extends or sometime stops

  HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *) sinebuffer, 60);
  HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t *) sqbuffer, 61);
  HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);


I can't put ARR-1(in place of ARR) or 1(in place of 0) in second DMA , as there can be short circuit in my circuit due to small wrong pulse.

NOW i don't know how to generate 0% and 100% duty cycle any other way.

Or is there a better way to do this?

Thank You.0693W00000Sv46OQAR.png


Don't use HAL_TIM_PWM_Start_DMA(), as it triggers DMA from the given channel's Compare signal, and that's inappropriate for values close to ARR or 0.

Instead, use DMA triggered from Update, and preloaded TIMx_CCRx. You can use the TIMx_DMAR/TIMx_DCR mechanism to load both TIMx_CCR1 and TIMx_CCR2 at the same Update event. I don't use Cube, but there are examples showing this in the Projects directory of Cube.

Generally, for whatever you cannot simply click in CubeMX, you are better off not using Cube at all, reading the manual and programming directly registers.


Thanks man.

To understand your answer better , I first need to read regarding the registers you mentioned.

Also, just migrated from arduino to stm32 a week ago. So thought of cubeMX as good starting point.

Also In the code attached below ,I updated duty cycle buffer using half and full DMA complete interrupt , So is this right method for doing double buffer (except for me using HAL library) ?

void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim){
   if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
   HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1, (uint32_t)&base1, (uint32_t)&sinebuffer, 30);
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){
    if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
    HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1, (uint32_t)&base2,(uint32_t)&sinebuffer, 30);		     

 works fine.