cancel
Showing results for 
Search instead for 
Did you mean: 

Software PWM, best approach?

Javier1
Principal

It finally happened, i need two pins without pwm functionality to output pwm signals (minimum 1kHz)

Im using an STM32f072R8Tx clocked with HSI48Mhz, my TIM1 is available.

0693W00000BbfhsQAB.pngMy idea is:

TIM1 channels 1 and 2 set up as PWM NO OUTPUT with interruption enabled, discriminate the source of the interruption (channel).

Toggle the corresponding GPIOs inside the IRQ function.

Is there another magical way that doesnt interrupt my programm every milisecond?

1 ACCEPTED SOLUTION

Accepted Solutions

@Community member​ thanks for your help.

0693W00000BcvCTQAZ.gifIt works now, i had some issues with choosing the incorrect timer/trigger and i didnt know this very important function

__HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);//https://metebalci.com/blog/stm32h7-gpio-toggling/

tim6 update trigering dma does the job for me.

0693W00000Bcv3vQAB.png 

0693W00000BcuxFQAR.png 

/* USER CODE BEGIN PV */
uint32_t data[2]={GPIO_PIN_6,GPIO_PIN_6<<16};
/* USER CODE END PV */
 
 
....
 
 
 
 
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim6);
HAL_DMA_Start(&hdma_tim6_up, (uint32_t)&(data[0]), (uint32_t)&(GPIOC->BSRR), sizeof(data)/sizeof(data[0]));
__HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);
  /* USER CODE END 2 */

 https://www.hackster.io/javier-munoz-saez/all-pins-as-pwm-at-the-same-time-baremetal-stm32-1df86f

View solution in original post

12 REPLIES 12

Use a TIM-driven DMA from memory to GPIO.

JW

@Community member​ but wouldnt DMA (mem-peripheral) override the entire GPIO bank? not just the ones i need.

Use GPIO_BSRR.

JW

@Community member​ okay i will look into that.

So i need to set DMA (mem -mem) to set the register GPIOA->BSRR= whateveriwant;

Yes.

whateveriwant should have bits set in lower 16 bits wherever you want to set a pin high, and bits set in higher 16 bits to set a pin low.

Experiment in the debugger by manually writing into GPIO_BSRR to get a grip on this. Start with one pin.

Then set up a simple array of two words in memory, with the whateveriwant values to set and clear the pin, and in a timer-driven DMA transfer cyclically from that array to given GPIO_BSRR. Start simply, with DMA driven from timer's Update (i.e. TIMx_SR.UDE=1); this will yield a toggling pin, i.e. 50% PWM.

Now how do you proceed from that depends on what exactly do you want to achieve. One simple method might be to expand the array in memory e.g. to 100 words (and setting DMA's NDTR to 100), strategically placing the whateveriwants so that the pin is set to any time pieces out of 100 as you want.

JW

So im setting up a

uint32_t softpwm_values[100];

And i would like to use a (mem to mem) DMA channel in a circular mode with each transaction being triggered by a timer (timer freq= pwmfreq*100).

memory source is &softpwm_values (index increment) ,

memory dest is GPIOC->BSRR register

The problems i have now is:

  • How to trigger mem to mem DMA with a timer?, there is not a mem to mem available option

0693W00000BbmROQAZ.png 

  • How to set the mem to mem DMA in Circular mode?, there is not circular mode available0693W00000BbmQAQAZ.png

I found this interesting discussion, they point to the AN4666 app note

> And i would like to use a (mem to mem)

No. The "direction" is quite misleading, it implies different variants of DMA behaviour of which "direction" is just one portion. M2M ignores the triggers. You want M2P.

I don't know how to click this in CubeMX. DMA is quite simple to set up normally by writing into DMA registers.

JW

@Community member​ 

My best unssuccesfull attempt so far:

No dma is triggered, but tim_up interruptions are hapening

uint32_t data[100];
 
 
HAL_DMA_Start(&hdma_tim1_up, data, &(GPIOC->BSRR), sizeof(data));

Ill do some more clicks in cubeMX to see if i get somewhere

0693W00000BctznQAB.png0693W00000Bcu02QAB.png 

Interesting links:

some guy doing this with an stm32f205 and arduino

this other guy deeper lower level explanation <--- thisone was the winner for me

@Community member​ thanks for your help.

0693W00000BcvCTQAZ.gifIt works now, i had some issues with choosing the incorrect timer/trigger and i didnt know this very important function

__HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);//https://metebalci.com/blog/stm32h7-gpio-toggling/

tim6 update trigering dma does the job for me.

0693W00000Bcv3vQAB.png 

0693W00000BcuxFQAR.png 

/* USER CODE BEGIN PV */
uint32_t data[2]={GPIO_PIN_6,GPIO_PIN_6<<16};
/* USER CODE END PV */
 
 
....
 
 
 
 
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim6);
HAL_DMA_Start(&hdma_tim6_up, (uint32_t)&(data[0]), (uint32_t)&(GPIOC->BSRR), sizeof(data)/sizeof(data[0]));
__HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);
  /* USER CODE END 2 */

 https://www.hackster.io/javier-munoz-saez/all-pins-as-pwm-at-the-same-time-baremetal-stm32-1df86f