The method of outputting PWM pulses from a microcontroller
Hedy

Hedy @carolineee

About: Publish some interesting electronic articles

Joined:
Dec 18, 2023

The method of outputting PWM pulses from a microcontroller

Publish Date: Aug 27
1 0

PWM (Pulse Width Modulation) is one of the most common microcontroller outputs — used in motor control, LED dimming, audio, power regulation, etc. Let’s go step by step.

1. What is PWM?

PWM is a digital signal with a fixed frequency but a variable duty cycle (the proportion of HIGH vs LOW in one cycle).

  • Duty cycle (%) = (Ton / Tperiod) × 100
  • Example: at 1 kHz, 50% duty = 0.5 ms HIGH, 0.5 ms LOW.

2. Methods of Generating PWM
A) Software (bit-banging / timer interrupt method)

  • Use a timer interrupt to toggle a GPIO pin ON/OFF at the desired duty ratio.
  • Steps:
  1. Configure a timer to tick at high resolution (e.g., 1 µs).
  2. Inside ISR, compare a counter with duty value.
  3. Set GPIO HIGH when counter < duty, else LOW.
  • Pros: Simple, works on any MCU.
  • Cons: CPU overhead, limited frequency, jitter if ISR latency is high.

Example (pseudo-code):

volatile uint16_t counter = 0;
volatile uint16_t duty = 50; // duty out of 100

void TIM_IRQHandler() {
    counter++;
    if (counter >= 100) counter = 0;  // 100 steps per cycle
    if (counter < duty)
        GPIO_SetPin(PWM_PIN);
    else
        GPIO_ClearPin(PWM_PIN);
}
Enter fullscreen mode Exit fullscreen mode

B) Using a Dedicated Timer/Counter Peripheral (preferred)

Most MCUs (8051, STM32, AVR, PIC, ARM Cortex, etc.) have hardware timers with PWM mode.

Principle:

  1. Timer counts up (or up/down) with a prescaler.
  2. A compare register (CCR) defines the duty cycle.
  3. When the timer counter < CCR → output pin = HIGH, else = LOW.
  4. The ARR (auto-reload register) sets the PWM frequency.

Steps (generic):

  • Choose a timer (e.g., Timer1).
  • Configure ARR = (fclk / (Prescaler × fPWM)) – 1.
  • Set CCRx = (Duty% × ARR).
  • Enable PWM mode on that timer channel.
  • Enable pin’s alternate function (e.g., TIMx_CHy on STM32).

Example on STM32 (HAL code):

TIM_HandleTypeDef htim2;

void PWM_Init(void) {
    // TIM2 @ 1 MHz clock
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 84 - 1;    // APB1=84 MHz → 1 MHz
    htim2.Init.Period = 1000 - 1;     // 1 kHz PWM
    HAL_TIM_PWM_Init(&htim2);

    TIM_OC_InitTypeDef sConfig;
    sConfig.OCMode = TIM_OCMODE_PWM1;
    sConfig.Pulse = 500;              // 50% duty
    sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfig.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfig, TIM_CHANNEL_1);

    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // Start PWM on pin
}
Enter fullscreen mode Exit fullscreen mode

C) Using Dedicated PWM Peripheral

Some MCUs (esp. dsPIC, STM32 advanced timers, ESP32, etc.) have enhanced PWM modules with:

  • Dead-time insertion (for motor/half-bridge).
  • Center-aligned PWM.
  • Complementary outputs.
  • Synchronization with ADC triggers.
  • Hardware fault shutdown.

These are hardware-controlled, so the CPU only updates duty values occasionally.

3. Frequency and Resolution

PWM frequency (fPWM):

Resolution (bits):

Example: ARR = 255 → 8-bit PWM resolution.

4. Applications

  • LED dimming → 500 Hz–1 kHz (avoid flicker).
  • Motors (DC/servo) → 1 kHz–20 kHz (above audible range).
  • Switching power supplies / inverters → 50–200 kHz.
  • Audio output → > 40 kHz PWM, then filtered.

Summary:

  • Software PWM = timer interrupt + GPIO toggle (simple but CPU heavy).
  • Hardware PWM (recommended) = use timer/capture-compare registers for precise, low-CPU PWM.
  • Dedicated PWM peripherals = for motor drives / advanced control.

Comments 0 total

    Add comment