timerstm32pwm

How can I set PB6 as a PWM port in STM32F103C6?


I want to rotate a servo motor 180 degree. So I decided use STM32F103C6 for controller. I downloaded driving code from github. There TIM2_CH1 is used and the PWM output port is PA0. But in my board, the motor pwm pin is pluged into PB6. Then how can I set PB6 as a PWM port. Should I change the timer? What do I do? Please help me. Thanks.

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "delay.h"
#include "lcd16x2.h"

#define DEGREE_0            0
#define DEGREE_45           45
#define DEGREE_90           90
#define DEGREE_135      135
#define DEGREE_180      180

void PWM_Init(void);
void displayServoPosition(int degree);

int main(void)
{
    DelayInit();
    lcd16x2_init(LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_OFF);
    
    // Initialize PWM
    PWM_Init();
    
    while (1)
    {
        // Set servo position to 0 degree
        displayServoPosition(DEGREE_0);
        TIM2->CCR1 = 520;
        DelayMs(2000);
        // Set servo position to 45 degree
        displayServoPosition(DEGREE_45);
        TIM2->CCR1 = 840;
        DelayMs(2000);
        // Set servo position to 90 degree
        displayServoPosition(DEGREE_90);
        TIM2->CCR1 = 1140;
        DelayMs(2000);
        // Set servo position to 135 degree
        displayServoPosition(DEGREE_135);
        TIM2->CCR1 = 1500;
        DelayMs(2000);
        // Set servo position to 180 degree
        displayServoPosition(DEGREE_180);
        TIM2->CCR1 = 1800;
        DelayMs(2000);
    }
}

void PWM_Init() 
{
    // Initialization struct
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_OCInitTypeDef TIM_OCInitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // Step 1: Initialize TIM2
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    // Create 50Hz PWM
    // Prescale timer clock from 72MHz to 720kHz by prescaler = 100
    TIM_TimeBaseInitStruct.TIM_Prescaler = 100;
    // TIM_Period = (timer_clock / PWM_frequency) - 1
    // TIM_Period = (720kHz / 50Hz) - 1 = 14399
    TIM_TimeBaseInitStruct.TIM_Period = 14399;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
    // Start TIM2
    TIM_Cmd(TIM2, ENABLE);
    
    // Step 2: Initialize PWM
    // Common PWM settings
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    // We initialize PWM value with duty cycle of 0%
    TIM_OCInitStruct.TIM_Pulse = 0;
    TIM_OC1Init(TIM2, &TIM_OCInitStruct);
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
    
    // Step 3: Initialize GPIOA (PA0)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    // Initialize PA0 as push-pull alternate function (PWM output) for LED
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void displayServoPosition(int degree)
{
    // Display servo position to the LCD
    lcd16x2_clrscr();
    if (degree == DEGREE_0)
    {
        lcd16x2_puts("0");
    }
    else if (degree == DEGREE_45)
    {
        lcd16x2_puts("45");
    }
    else if (degree == DEGREE_90)
    {
        lcd16x2_puts("90");
    }
    else if (degree == DEGREE_135)
    {
        lcd16x2_puts("135");
    }
    else if (degree == DEGREE_180)
    {
        lcd16x2_puts("180");
    }
    lcd16x2_putc(0xDF);
}


Solution

  • The alternate function table is listed in table 5 of the datasheet.

    Sadly for you, it looks like there is no timer function available on PB6. You will need to connect to one of the other pins with a timer function in that table.