STM32 F4 General-purpose Timers for PWM

Goal: generating edge-aligned PWM using the 16-bit TIM3.

TIM3 has 4 PWM channels available, however I only have 2 oscilloscope probes so I will set up 2 channels only.
PWM frequency: 10kHz
Duty cycle: Channel 1 - 50%, Channel 2 - 25%


@parameters PWM_FREQ, PWM_DC_CH1, PWM_DC_CH2
@output [Channel 1 - PC6], [Channel 2 - PC7]


#include <stm32f4xx.h>
#include "other_stuff.h"

#define   APB1_FREQ       42000000                            // Clock driving TIM3
#define   CNT_FREQ        21000000                            // TIM3 counter clock (prescaled APB1)
#define   PWM_FREQ        10000                               // PWM frequency in (320Hz~21MHz) range
#define   PWM_DC_CH1      50                                  // Channel 1 duty cycle
#define   PWM_DC_CH2      25                                  // Channel 2 duty cycle

#define   TIM_PULSE_CH1    (((PWM_DC_CH1) * (APB1_FREQ)) \
                          / ((PWM_FREQ) * (200)))             // Output Compare 1 reg value
#define   TIM_PULSE_CH2    (((PWM_DC_CH2) * (APB1_FREQ)) \
                          / ((PWM_FREQ) * (200)))             // Output Compare 2 reg value
#define   TIM_PERIOD       (((CNT_FREQ) / (PWM_FREQ))-1)      // Autoreload reg value
#define   TIM_PRESCALER    (((APB1_FREQ) / (CNT_FREQ))-1)     // APB1 prescaler


int main()
{
 
  GPIO_InitTypeDef        gpio_C;                             // GPIOC structure
  TIM_TimeBaseInitTypeDef TIM3_TimeBase;                      // Time Base structure
  TIM_OCInitTypeDef       TIM3_OC;                            // Output Compare structure
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);       // Clocking GPIOC (AHB1 = 84MHz)
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        // Clocking TIM3  (APB1 = 42MHz)
 
  gpio_C.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;                // Ch.1 (PC6), Ch.2 (PC7) 
  gpio_C.GPIO_Mode  = GPIO_Mode_AF;                           // PWM is an alternative function
  gpio_C.GPIO_Speed = GPIO_Fast_Speed;                        // 50MHz
  gpio_C.GPIO_OType = GPIO_OType_PP;                          // Push-pull
  gpio_C.GPIO_PuPd  = GPIO_PuPd_UP;                           // Pulling-up
  GPIO_Init(GPIOC, &gpio_C);                                  // Initializing GPIOC structure
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);     // Routing TIM3 output to PC6
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_TIM3);     // Routing TIM3 output to PC7
 
  TIM3_TimeBase.TIM_ClockDivision = 0;                        // Not dividing
  TIM3_TimeBase.TIM_CounterMode   = TIM_CounterMode_Up;       // Upcounting configuration
  TIM3_TimeBase.TIM_Period        = TIM_PERIOD;               // Autoreload value (ARR) 
  TIM3_TimeBase.TIM_Prescaler     = TIM_PRESCALER;            // dividing APB1 by 2
  TIM_TimeBaseInit(TIM3, &TIM3_TimeBase);                     // Initializing Time Base structure
 
  TIM3_OC.TIM_OCMode      = TIM_OCMode_PWM1;                  // Edge-aligned mode
  TIM3_OC.TIM_OutputState = TIM_OutputState_Enable;           // Enabling the Output Compare state
  TIM3_OC.TIM_OCPolarity  = TIM_OCPolarity_High;              // Regular polarity (low will inverse it)
  TIM3_OC.TIM_Pulse       = TIM_PULSE_CH1;                    // Output Compare 1 reg value
  TIM_OC1Init(TIM3, &TIM3_OC);                                // Initializing Output Compare 1 structure
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);          // Disabling Ch.1 Output Compare preload
 
  TIM3_OC.TIM_OutputState = TIM_OutputState_Enable;           // Enabling again in case the values changed
  TIM3_OC.TIM_Pulse       = TIM_PULSE_CH2;                    // Output Compare 2 reg value
  TIM_OC2Init(TIM3, &TIM3_OC);                                // Initializing Output Compare 2 structure
  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);          // Disabling Ch.2 Output Compare preload

  TIM_Cmd(TIM3, ENABLE);                                      // Ready, Set, Go!
 
  while(1)
  {
    //os_sys_init(init_task);                                 // Starting the RTX kernel
  }

}

Here's what we actually get.

2 comments:

  1. Very good ! I'm a pic32 programmer and I was curious to know if the operation of the output comparator was similar to the STM32 and yes they are almost the same but I prefer the simplicity of using the output comparator under the PIC32 (without the ugly framework harmony of course)

    ReplyDelete
  2. The timer diagram is well done ! thank you for sharing it !

    ReplyDelete