Skip to main content
mosine
Associate III
July 5, 2013
Question

PWM

  • July 5, 2013
  • 12 replies
  • 1685 views
Posted on July 05, 2013 at 12:20

Hi,

I'm very demoralized to study PWM for stm3220G evaluation board. I need a tutorial/example to understand concepts.

For example: why does gpio_moder configure in AF (alternate function)?

I configured GPIOA1   in my sample project, but I don't see anything with my oscilloscope in that pin (CN1  - 36 PA1| MII_RX_CLK| JP6 open). 

Help me!

    This topic has been closed for replies.

    12 replies

    waclawek.jan
    Super User
    July 5, 2013
    Posted on July 05, 2013 at 12:59

    > For example: why does gpio_moder configure in AF (alternate function)?

    Because AF is the way how to attach pins to the function modules (Timers, USART, I2S, SPI, Ethernet...). Otherwise, it's a plain input or a plain ''hand-manipulated'' output.

    Read RM0033, chapter 6.

    > I configured GPIOA1   in my sample project

    How?

    JW

    mosine
    mosineAuthor
    Associate III
    July 5, 2013
    Posted on July 05, 2013 at 16:32

    Thanks for reply. My project is: GPIO (A1) set as output with ODR=1 for 20 msec. After 20msec, ODR=0 and PWM starts in the same GPIO (A1). I'm working with STM3220G evaluation board and I want use tasks (RTOS). I need (problem) set timer (i.e. TIM1) for 20 msec with right systick. How can I do?

    Tesla DeLorean
    Guru
    July 5, 2013
    Posted on July 05, 2013 at 17:30

    This all pretty hopeless.

    Here's a quick blind implementation doing 50 Hz (20 ms - servo) out of PA.1

    // STM32 PWM 50 Hz (20 ms) STM32F2 PA.1 - sourcer32@gmail.com
    #include ''stm32f2xx.h''
    /**************************************************************************************/
    void TIM2_IRQHandler(void)
    {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    // Modulate PA.1 width here 
    }
    }
    /**************************************************************************************/
    void RCC_Configuration(void)
    {
    /* --------------------------- System Clocks Configuration -----------------*/
    /* TIM2 clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    /* GPIOA clock enable */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    }
    /**************************************************************************************/
    void NVIC_Configuration(void)
    {
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the TIM1 gloabal Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    }
    /**************************************************************************************/
    void GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    /*-------------------------- GPIO Configuration ----------------------------*/
    /* GPIOD Configuration: Pins 1 in output push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /* Connect TIM2 pins to AF */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2); // PA1 TIM2_CH2
    }
    /**************************************************************************************/
    void TIM2_Configuration(void)
    {
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    /* Time base configuration - SystemCoreClock = 120000000 for 120 MHz board */
    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
    TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20ms)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    /* Enable TIM2 Preload register on ARR */
    TIM_ARRPreloadConfig(TIM2, ENABLE);
    /* TIM PWM1 Mode configuration: Channel */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1500; // Servo Top-Center
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    /* Output Compare PWM1 Mode configuration: Channel2 PA.1 */
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    /* TIM2 Interrupts enable */
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    /* TIM2 enable counter */
    TIM_Cmd(TIM2, ENABLE);
    }
    /**************************************************************************************/
    int main(void)
    {
    RCC_Configuration();
    GPIO_Configuration();
    NVIC_Configuration();
    TIM2_Configuration();
    while(1)
    {
    // Add code to do something here
    }
    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    mosine
    mosineAuthor
    Associate III
    July 8, 2013
    Posted on July 08, 2013 at 08:32

    Hi,

    THANKS Clive!!!! I have sample another question: is there a formula to calculate time? I need a formula to understand this:

    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); // Shooting for 1 MHz, (1us)
    TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20ms)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;

    Thanks. Simone
    mosine
    mosineAuthor
    Associate III
    July 8, 2013
    Posted on July 08, 2013 at 10:59

    If I want stop the pwm, can I do? I see an item of forum, and the timer is stopped to stop pwm. Is there an alternative?

    THANKS

    Tesla DeLorean
    Guru
    July 8, 2013
    Posted on July 08, 2013 at 13:15

    The computation is one of factors, which are then divided into the TIMCLK. If APB1 is running at DIV4, then TIMCLK2 is at DIV2 (ie 60 MHz in a 120 MHz system). If I divide 60 MHz by 60 I have a 1 MHz time base. The period of each tick is 1000 ns or 1 us, 20000 ticks of that is 20 ms. This thus defines the periodicity of the pulses. The duty is controlled by the CCRx register for the channel.

    TIM2->CCR2 = 0 should have the impact of turning off the pulse (ie always low), TIM2->CCR2 = 20000 should have it be on (ie always high). The timer still ticks, the update interrupt keeps firing.
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    mosine
    mosineAuthor
    Associate III
    July 8, 2013
    Posted on July 08, 2013 at 15:37

    Hi,

    thanks clive1 for your reply. I used two counters to control tick in timer interrupt handler. If I want use internal register to compare time, how can I do? 

    thanks

    Tesla DeLorean
    Guru
    July 8, 2013
    Posted on July 08, 2013 at 17:18

    I used two counters to control tick in timer interrupt handler. If I want use internal register to compare time, how can I do?

    Not sure I understand the question. The counter timebase ticks in TIMx->CNT, values of which can be latched in TIMx->CCRx in certain timer modes.

    If you are counting interrupts by incrementing a ticker value, you can compute a simple delta. The STM32 M3/M4 parts also have a 32-bit cycle counter (120 MHz on an F2 running at that rate), which can be used to make fine granularity measurements.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    mosine
    mosineAuthor
    Associate III
    July 9, 2013
    Posted on July 09, 2013 at 10:03

    Hi,

    thanks clive1. I create my project by your helps, but now I have a problem to synchronize two timers (I think). I see in myoscilloscope that my wave form is not regular, sometimes (random) start of my wave form is moved. This is my code:

    #include ''stm32f2xx.h''
    #include <RTL.h>
    #include ''stm32f2xx_rcc.h''
    #include ''stm32f2xx_tim.h''
    #include ''stm32f2xx_gpio.h''
    int
    start = 0;
    int
    doPwm = 0;
    unsigned 
    int
    counterTimeStart = 0;
    unsigned 
    int
    counterTimePwm = 0;
    unsigned 
    int
    period = 0;
    OS_TID t_pwm_start;
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    void
    RCC_Configuration(
    void
    )
    {
    /*TIM3*/
    //RCC->APB1ENR |= (1<<1);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    /*TIM2*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    /* GPIOA clock enable */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    }
    /**************************************************************************************/
    void
    GPIO_ConfigurationStart(unsigned 
    int
    mod)
    {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIOA->ODR = mod; 
    //0x0002;
    }
    /**************************************************************************************/
    void
    NVIC_Configuration(
    void
    )
    {
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the TIM2 gloabal Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    /* Enable the TIM3 gloabal Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    }
    void
    TIM3_Configuration(
    void
    ){
    /* Time base configuration - SystemCoreClock = 120000000 for 120 MHz board */
    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); 
    // Shooting for 1 MHz, (1us)
    TIM_TimeBaseStructure.TIM_Period = 100 - 1; 
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    /* Enable TIM2 Preload register on ARR */
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    /* TIM3 Interrupts enable */
    TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
    //TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);
    }
    void
    TIM2_Configuration(
    void
    )
    {
    /* Time base configuration - SystemCoreClock = 120000000 for 120 MHz board */
    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (((SystemCoreClock / 1000000) / 2) - 1); 
    // Shooting for 1 MHz, (1us)
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1; 
    // 1 MHz / 20000 = 50 Hz (20ms)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    /* Enable TIM2 Preload register on ARR */
    TIM_ARRPreloadConfig(TIM2, ENABLE);
    /* TIM PWM1 Mode configuration: Channel */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 300; 
    // Servo Top-Center
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    /* Output Compare PWM1 Mode configuration: Channel1 PA.1 */
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    /* TIM2 Interrupts enable */
    TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
    /* TIM2 enable counter */
    TIM_Cmd(TIM2, DISABLE);
    }
    void
    GPIO_Configuration(
    void
    )
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    /* Connect TIM2 pins to AF */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_TIM2); 
    // PA1 TIM2_CH2
    }
    void
    enableTIM2(
    char
    com){
    if
    (com == 1){
    TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
    }
    else
    {
    TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
    TIM_Cmd(TIM2, DISABLE);
    }
    }
    void
    TIM3_IRQHandler(
    void
    )
    { 
    if
    (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
    {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
    //------------------------
    // 20 MSEC
    //------------------------
    if
    (start == 0){
    if
    (counterTimeStart == 199){
    counterTimeStart = 0;
    start = 1;
    }
    else
    {
    counterTimeStart = counterTimeStart + 1;
    }
    }
    //------------------------
    // PWM
    //------------------------
    if
    (start == 1){
    if
    (doPwm == 0){
    GPIO_Configuration();
    enableTIM2(1);
    }
    doPwm = 1;
    }
    //------------------------
    // STOP PERIOD
    //------------------------
    if
    (start == 2){
    if
    (period == 500){
    period = 0;
    start = 0;
    doPwm = 0;
    GPIO_ConfigurationStart(0x0002);
    }
    else
    {
    period = period + 1;
    }
    }
    }
    }
    void
    TIM2_IRQHandler(
    void
    )
    {
    if
    (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    if
    (counterTimePwm == 5){
    counterTimePwm = 0;
    enableTIM2(0);
    GPIO_ConfigurationStart(0x0000);
    start = 2;
    }
    else
    {
    counterTimePwm = counterTimePwm + 1;
    }
    }
    }
    int
    main(
    void
    )
    {
    RCC_Configuration();
    GPIO_ConfigurationStart(0x0002);
    NVIC_Configuration();
    TIM3_Configuration();
    TIM2_Configuration();
    while
    (1){
    } 
    }

    Amel NASRI
    ST Technical Moderator
    July 9, 2013
    Posted on July 09, 2013 at 17:49

    Hello,

    For synchronization purpose, you can refer to example in the STM32F2 Standard Peripheral library.

    There are examples for synchronization in cascade or parallel modes.

    -Mayla-

    To give better visibility on the answered topics, please click on "Best Answer" on the reply which solved your issue or answered your question.