Skip to main content
Mbp.1
Visitor II
May 16, 2021
Solved

How to generate and control a PWM with registers (NO HAL) in STM32F446RE?

  • May 16, 2021
  • 4 replies
  • 4103 views

I am working on controlling of a stepper motor with STM32F446 and want to generate a PWM with variable frequency (trapezoidal) and stop it after some specified (n) pulses. I want to do this with register programming not HAL functions. So I want to know three steps bellow:

  1. How can I generate a PWM pulse with registers?
  2. How I can change its frequency?
  3. How I can count generated pulses and stop generating after som pulses?

could someone help me in register programming?

This topic has been closed for replies.
Best answer by waclawek.jan

Start by reading the TIM chapter in RM. It won't be clear at the first reading, so repeat until it starts to be a bit clearer.

  1. Set up the required pin - enable GPIO clock in RCC, then in given GPIO set respective bits in GPIOx_MODER so that pin is set to AF, and set in AFR[] the proper AF according to the table in Datasheet. Set up timer to run, i.e. enable its clock in RCC, set TIMx_ARR to the period you want and enable the timer to run by setting TIMx_CR1.CEN=1. For given channel, set one of the PWM modes in TIMx_CCMRx.OCxM, set duty cycle by setting respective TIMx_CCRx to a value between 0 and ARR, and enable given channel in TIMx_CCER. If it's TIM1 or TIM8, set TIMx_BDTR.MOE.
  2. By changing TIMx_ARR. If you want to do it on the fly, you should enable ARR preload by setting TIMx_CR1.ARPE.
  3. There are several ways to do it, but it's a bit tricky and you should leave it until you manage basic PWM operation.

JW

4 replies

waclawek.jan
waclawek.janBest answer
Super User
May 16, 2021

Start by reading the TIM chapter in RM. It won't be clear at the first reading, so repeat until it starts to be a bit clearer.

  1. Set up the required pin - enable GPIO clock in RCC, then in given GPIO set respective bits in GPIOx_MODER so that pin is set to AF, and set in AFR[] the proper AF according to the table in Datasheet. Set up timer to run, i.e. enable its clock in RCC, set TIMx_ARR to the period you want and enable the timer to run by setting TIMx_CR1.CEN=1. For given channel, set one of the PWM modes in TIMx_CCMRx.OCxM, set duty cycle by setting respective TIMx_CCRx to a value between 0 and ARR, and enable given channel in TIMx_CCER. If it's TIM1 or TIM8, set TIMx_BDTR.MOE.
  2. By changing TIMx_ARR. If you want to do it on the fly, you should enable ARR preload by setting TIMx_CR1.ARPE.
  3. There are several ways to do it, but it's a bit tricky and you should leave it until you manage basic PWM operation.

JW

Broman3100
Associate III
April 3, 2023

Hi, I was curious, is there an official documentation that gives the steps listed by you? I went through reference manual and datasheet, but still, without this comment of yours, I would have missed some of the steps since I couldn't find any other clear step by step list.

Broman3100
Associate III
April 3, 2023

I know most of this should be intuitive, but it wont be for beginners, that's why I'm asking.

waclawek.jan
Super User
April 3, 2023

> is there an official documentation that gives the steps listed by you?

I don't know, but given that "officially" you are supposed to click in CubeMX, I don't think so.

Maybe if you click in CubeMX and then let it generate Cube/LL code, you'll see the individual steps, if you don't mind the "name mangling" of LL. I don't use Cube so don't know.

You can also look at AN4776 and AN4013. Not exactly what you're looking for, but maybe englightening. Maybe not.

> I know most of this should be intuitive

I wouldn't call it intuitive. What I did is exactly wrote above: I read the TIM chapter (plus the relevant portions of rest of RM and DS) multiple times, while experimenting. After you set up the timers a dozen of times and make a dozen of errors, it then starts to be sort of "intuitive" ("familiar", rather).

JW