cancel
Showing results for 
Search instead for 
Did you mean: 

dynamically changing Timer ARR and CCR1

Smar
Associate II

Hi everyone,

I am currently working on controlling a stepper motor using a PWM signal. I want to dynamically update the speed of the motor using different ARR and CCR1 values. Controlling the stepper works fine until an uncertain amount of time when the PWM signal appears to disappear completely.

 

I have read that something like enabling the preload register should help but this still doesn't fix my problem.

 

Here is my code so far:

 

#include "main.h"

#define C

#define F_CLK 24000000

uint16_t arr_from_freq(uint16_t freq){
    return F_CLK/(freq*(TIM2->PSC+1)) - 1;
}

int main(void){

    EPL_SystemClock_Config();

    // Enable the GPIOA and TIM2 peripherals
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

    // Set the mode of the GPIOA pin 5 to alternate function mode 2
    GPIOA->MODER |= GPIO_MODER_MODER5_1;
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;
    GPIOA->AFR[0] |= 0b0010 << 20;
    
    // Disable the timer before setting the prescaler and overflow values
    TIM2->CR1 &= ~TIM_CR1_CEN;
    
    // Set the prescaler and overflow values
    TIM2->PSC = 3; // 10 seems to be optimal for now
    TIM2->ARR = 64000;
    TIM2->CCR1 = 0;

    // Set the PWM mode 1
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
    TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
    // Set the output polarity to active high
    TIM2->CCER |= TIM_CCER_CC1E;

    // Enable the main output
    TIM2->BDTR |= TIM_BDTR_MOE;
    
    // Enbable the timer
    // Set the center-aligned mode 
    TIM2->CR1 |= TIM_CR1_CMS_0 | TIM_CR1_CEN;

    uint16_t lower_limit = 1000; // One rotation per minute because of step/8 microstepping
    uint16_t upper_limit = 3000;
    uint16_t pwm_frequency = lower_limit;
    uint16_t duty = arr_from_freq(lower_limit)/2;
    uint8_t state = 0;

    
    for(;;){
        if (pwm_frequency <= upper_limit && state == 0){
            pwm_frequency += 1;
        } else {state = 1;}

        if (pwm_frequency >= lower_limit && state == 1){
            pwm_frequency -= 1;
        } else {state = 0;}
        
        TIM2->ARR = arr_from_freq(pwm_frequency);
        duty = arr_from_freq(pwm_frequency)/2;
        TIM2->CCR1 = duty;
        delay(5000);
    }
}

 

 

Thanks in advance for anyone willing to help!

Cheers

1 ACCEPTED SOLUTION

Accepted Solutions

 

Which STM32?

> I have read that something like enabling the preload register should help but this still doesn't fix my problem.

You mean setting TIMx_CR1.ARPE did not help?

Show how did you try. 

JW

PS TIM2 does not have BDTR.

 

View solution in original post

2 REPLIES 2

 

Which STM32?

> I have read that something like enabling the preload register should help but this still doesn't fix my problem.

You mean setting TIMx_CR1.ARPE did not help?

Show how did you try. 

JW

PS TIM2 does not have BDTR.

 

Setting TIMx_CR1_ARPE did actually manage to fix this, I must have either tried the wrong register or just a completely wrong one. I am very new to programming on a low level basis, so thanks a lot for the quick and easy fix!