Generating PWM waveform using Timer - Output compare mode | 50% duty cycle | STM32F103C8T6 | Arm Cortex M3 | Arduino Oscilloscope

For a detailed Timer configuration, refer previous post

Program:

/***************
Generating waveform using output compare mode in Timer 2 - Channel 2

SysClk = 72 MHz
Prescaler = 10000
f = 72000000 / 10000 = 7200 Hz clock for Timer 2
Auto_reloader = CCR2 = 14400

so, Timer counts till:
= 1 / 7200 * 14400 = 2 sec

****************/

#include "stm32f10x.h"
void TIM2_IRQHandler(void);
void RCC_config(void);

void RCC_config() // RCC clock configuration
{
  RCC -> CR |= RCC_CR_HSEON;                               // HSE ON
  RCC -> CFGR |= (RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);    
// Setting PLL - HSE * 9
  RCC -> CFGR |= RCC_CFGR_SW_1;                            // SysClk = PLLCLK
  RCC -> CR |= RCC_CR_PLLON;                                              
  // Turn ON PLL after above PLL configurations, making SysClk = HSE * 9 = 8 * 9 = 72 MHz
RCC -> CFGR |= RCC_CFGR_PPRE1_DIV2;
// APB1 = AHB / 2 = 72 / 2 = 36 MHz (max)
}

void TIM2_IRQHandler()
{
  TIM2 -> SR &= ~TIM_SR_CC2IF;       // Clear Capture/compare 2 interrupt flag
  GPIOC -> ODR ^= GPIO_ODR_ODR13;    // Toggle PC13 LED pin
}

int main()
{
  RCC_config();
 
  /* Port C - pin 13 settings for LED*/
 
  RCC -> APB2ENR |= RCC_APB2ENR_IOPCEN;         // Enable Port-C Clock
 
  /* Select PortC_Pin 13 as output @2MHZ
   * Configure Pin 13 with open-drain */
 
  GPIOC -> CRH |= GPIO_CRH_MODE13_1 | GPIO_CRH_CNF13_0;
  GPIOC -> BSRR = GPIO_BSRR_BS13;             // Initialize PC13 LED - OFF
 
  /* Timer 2 settings
     TIM2 -> CR1 &= ~ TIM_CR1_DIR  - by default - UP counter */
 
  RCC -> APB1ENR |= RCC_APB1ENR_TIM2EN;       // Enable clock for Timer 2
  TIM2 -> CR1 &= ~TIM_CR1_CEN;                // CEN = 0 - Counter disable
  TIM2 -> PSC = (10000 - 1);                  // Prescaler
 
  /* Output Compare mode Setup */
    /* Configure output pin PA1 as Alternate functionality */
  RCC -> APB2ENR |= RCC_APB2ENR_IOPAEN;                   // Enable Port-A Clock
  GPIOA -> CRL |= (GPIO_CRL_CNF1_1 | GPIO_CRL_MODE1_1);   // Alternate push-pull @ 2MHz
  GPIOA -> CRL &= ~ GPIO_CRL_CNF1_0; // clear default reset value
  //CC1S = 00 -> Channel configured as output
  TIM2 -> ARR = 14400;                                    // Auto reload value
  TIM2 -> CCR2 = 14400;                                   // Value to be compared with counter
  NVIC_EnableIRQ(TIM2_IRQn);                              // Enable Timer 2 global interrupt in NVIC
  TIM2 -> DIER |= TIM_DIER_CC2IE;                         // Capture/Compare 2 interrupt enable
  TIM2 -> CCMR1 |=  TIM_CCMR1_OC2M_0 | TIM_CCMR1_OC2M_1;  // Toggle output on compare match
  TIM2 -> CCER |= TIM_CCER_CC2E;                          // Channel output active and its active high
 
  TIM2 -> CNT = 0;                            // Counter initialized to 0    
  TIM2 -> CR1 |= TIM_CR1_CEN;                 // CEN = 1 - Counter enable

  while(1)
  {
    // Do nothing
  }
  return 0;
}

Timer - Output Compare mode:

1. Enable Timer 2 clock and set the prescaler to 10000, So each timer count occurs at 0.14ms.

2. Observe the output waveform in Timer 2 - Channel 2 output pin:
- Check the datasheet for the pin information = PA1
- Configure the pin as Alternate functionality (reference manual)






We are also using in-built LED at PC13 to also observe the output.

3. Write the value to which the counter value will be compared to in ARR and CCR2 registers.

CCR2 = 14400
0.14 ms * 14400 = 2 sec
So, output toggles every 2 seconds
TON = TOFF = 2 sec (50 % duty cycle)
total = 4 sec = 0.25 Hz

4. Enable compare 2 interrupt in DIER register.

Timer 2 has a global interrupt handler in STM32F103C8T6, unlike Timer 1. So for compare/capture or update interrupt, we can use the common handler: TIM2_IRQHandler

5. We want to toggle the output (in PA1) to create a waveform, so set OC2M = 011 in CCMR1 register.
Which toggles the output at compare match (TIMx_CNT=TIMx_CCR2)

6. Enable channel output in CC2E in CCER register.

7. Start the counter.

We can observe the output in pins: PC13 or in PA1 using Digital analyzer or an Oscilloscope.

Below is the waveform from pin PC13, read using Arduino Nano:

1. Connect the ground pin of Arduino and STM32
2. Connect PC13 to analog pin in Arduino - A1
3. Program Arduino to read the analog pin -> convert value to analog -> serial print it and observe the waveform in Serial plotter - choose suitable baud rate



Arduino Program:

int val;
float volt;

void setup()
{
  Serial.begin(300);
}

void loop()
{
  val = analogRead(A2);
  volt = val * 0.0049;
  Serial.println(volt, 2);
}

For UART in STM32, see this post

Comments