cancel
Showing results for 
Search instead for 
Did you mean: 

Synchronous Phase-Shifted PWM Controls with STM32F411RE/407VG 50MHZ Timer Freq.

erincyldz
Associate III

Hello people, i want to create 4 different PWM signals that has total period of 100 microseconds and working with %25 duty cycle. My timers are working with 50 MHz Speed but it is not necessary to do so. I need them to be shifted 25 microseconds apart from eachother. What i mean by this is actually; PWM1 starts-> 25 microseconds later PWM1 Pulse goes LOW and PWM2 goes HIGH -> 25 microseconds later PWM2 goes LOW and PWM3 goes HIGH and so on. Is there anyway to do this with STM32F411RE/407VG mcu's? I have both eva-boards for those mcu's. I know it will be slight differences between those signals because it is not a FPGA board but i am willing to see what i can achieve with those 2 controllers. Thank you all!

1 ACCEPTED SOLUTION

Accepted Solutions
AScha.3
Chief III

Hi, just for fun...

i tried on an old F103 (blue pill) , most simple way to do this with one timer:

switch out/channel/compare with UI , timer update (=end of cycle), in round robin way;

so just on 2 ch shown:   100us loop, 25us / channel ON time.

AScha3_0-1702928616301.png

here the crossover at 10ns /div (just with probes, that were at the scope, about 60MHz typ. )

AScha3_0-1702932375424.png

 

 

F103 at 64MHz core; tim1 set:

AScha3_0-1702930262986.png

the "program" :)

  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim1);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);

  /* USER CODE END 2 */

and in xx_it.c :

void TIM1_UP_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_IRQn 0 */
	switch (++out)
	{
	case 1: TIM1->CCR1 = 25; TIM1->CCR4 = 0; break;
	case 2: TIM1->CCR2 = 25; TIM1->CCR1 = 0; break;
	case 3: TIM1->CCR3 = 25; TIM1->CCR2 = 0; break;
	default:TIM1->CCR4 = 25; TIM1->CCR3 = 0; out=0; break;

	}
  /* USER CODE END TIM1_UP_IRQn 0 */
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_IRQn 1 */

  /* USER CODE END TIM1_UP_IRQn 1 */
}

 

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

17 REPLIES 17
TDK
Guru

A few possibilities to achieve this:

  1. It is possible with timers, but you will need to use different timers to achieve this. Timers can be synchronized so they count in lock step.
  2. If all 4 pins are on the same port, it would also be possible to do this in DMA with a single timer. Set up a timer with an update time of 25 ms, then transfer to GPIOx->BSRR from a circular buffer to set the appropriate pins. Buffer length should be 4, then it'll repeat. I'd do this.
  3. Since you're dealing in the milliseconds range as opposed to the microseconds range, you could also do this within an interrupt. Set an interrupt to trigger every 25ms, and adjust pins accordingly within the update interrupt.

 

If you feel a post has answered your question, please click "Accept as Solution".

I am actually dealing with microseconds range. Actually i am almost working on nanoseconds range because i obtained the desired signal by using output compare of the pwm1 to ITR0 of timer 2 and so on when the desired signal is happened. but there is a thing that i literally need EXACTLY 25 microseconds delay between the signals but somehow the rising/falling time of my signals are shifting the delay between my signals for 20/30 nanoseconds. I do believe only way to deny this is using an FPGA but converting the whole project to FPGA is kinda so hard right now for me because of this im trying my best on STM. But i wonder if getting a faster STM like STM32H723ZG would solve my problem because the functions and comparisons it makes at the back might get my code working slower i dont believe the delays are caused because of the hardware- dependent constraints. But thanks anyway

Well, nothing is exact, but if you mean 25 us +/- 50 ppm or whatever your clock accuracy is, that is certainly doable with method 1 or 2 as outlined above.

HSI will have jitter. HSE driven by a crystal will be much more precise. Might want to look into how your clock is produced.

A faster STM32 won't help much.

If you feel a post has answered your question, please click "Accept as Solution".

i see your point and the way i used actually the method 1 but the problem is while STM pulls down/up the signals a little amount of time (20-30 nanoseconds) passes and it actually affects me i dont want that. i assumed a faster processor (like 550 MHz) would do that faster because the comparisons it does in the background would be faster wont it ? 

Are you talking about slew rate? Faster processors probably have about the same slew rate/drive strength, and if not they are not dramatically different. I don't see how slew rate is an issue since it will be the same for all 4 synchronous signals. Perhaps we have strayed from the original question.

If you feel a post has answered your question, please click "Accept as Solution".

> i obtained the desired signal by using output compare of the pwm1 to ITR0 of timer 2

How exactly?

> rising/falling time of my signals are shifting the delay between my signals for 20/30 nanoseconds

How do you observe that? Post pictures/screenshots.

JW

AScha.3
Chief III

Hi, just for fun...

i tried on an old F103 (blue pill) , most simple way to do this with one timer:

switch out/channel/compare with UI , timer update (=end of cycle), in round robin way;

so just on 2 ch shown:   100us loop, 25us / channel ON time.

AScha3_0-1702928616301.png

here the crossover at 10ns /div (just with probes, that were at the scope, about 60MHz typ. )

AScha3_0-1702932375424.png

 

 

F103 at 64MHz core; tim1 set:

AScha3_0-1702930262986.png

the "program" :)

  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim1);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);

  /* USER CODE END 2 */

and in xx_it.c :

void TIM1_UP_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_IRQn 0 */
	switch (++out)
	{
	case 1: TIM1->CCR1 = 25; TIM1->CCR4 = 0; break;
	case 2: TIM1->CCR2 = 25; TIM1->CCR1 = 0; break;
	case 3: TIM1->CCR3 = 25; TIM1->CCR2 = 0; break;
	default:TIM1->CCR4 = 25; TIM1->CCR3 = 0; out=0; break;

	}
  /* USER CODE END TIM1_UP_IRQn 0 */
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_IRQn 1 */

  /* USER CODE END TIM1_UP_IRQn 1 */
}

 

If you feel a post has answered your question, please click "Accept as Solution".

appreciated for your answer. will take a look out for this thank you for your efforts.

here is my configurations for timer1, timer2 and timer3. timer4 doesnt have an output compare output but it has an trigger event section on the outputcompare(OC2REF) like all the timers. since it does not trigger any other timers it doesnt requires any output compare channels. All of the timers output compare no output Pulse parameters has been set to 25-1. and i achieved 4 signals that has 25microseconds phase shift between each and total 100 microseconds period but my problem is when timer1 goes low and timer 2 goes high there is 20-30 nanoseconds falling/rising time and i saw that on the oscilosscope but i dont have the screenshots. Today i'll try what AScha.3 recommended below and ill feedback you guys. thank you all for helping out.

TIM_1_CONFIG.png

TIM_2_CONFIG.png

TIM_3_CONFIG.png