1
\$\begingroup\$

I wrote a stepper motor driver with the use of DMA and TIM1. I accelerate the signal using the so-called Ramps. I calculate the times and load them into the DMA table and pass them to the TIM PERIOD value. The program works as it should (accelerates and brakes with the principle of the ramp), but it worries me why Timer starts working only after 1 minute. I suspect that this is due to calculations because if random values ​​are loaded without these values, it works immediately. Can I make this speed demon run TIMER a little faster? Will I do nothing. For those interested, I paste the code.

#include "stm32f10x.h"
#include "stm32f1xx_nucleo.h"
#include "stm32f10x.h"

#include <math.h>

int i = 0;

//============Dane==========
float vMin = 1.0;
float vMax = 10.0;

int accelerationTime = 10;
int decelerationTime = 10;

volatile int totalSteps = 100;
volatile int currentStep = 0;
//============Szukane==========
float accelerationPerMs = 0;
float decelerationPerMs = 0;

int stepsAcceleration = 0;
int stepsDeceleration = 0;

//============================
float currentSpeed = 0.0;
int period = 0;
u16 PWM_Buf[100];

void TIMInit(void);
void GPIOInit(void);
void DMAInit(void);
void PWMInit(void);
void generateSignal(int totalSteps, float vMin, float vMax,int accelerationTime, int decelerationTime);

int main(void) {
        GPIOInit();
        TIMInit();
        DMAInit();
        PWMInit();
        generateSignal(totalSteps,vMin,vMax,accelerationTime,decelerationTime);

        while (1) {
        }
}
void generateSignal(int totalSteps, float vMin, float vMax,int accelerationTime, int decelerationTime) {

                accelerationPerMs = (vMax - vMin) / (accelerationTime);
                decelerationPerMs = (vMax - vMin) / (decelerationTime);

                stepsAcceleration = ceil(((vMin * accelerationTime) +
                                (accelerationPerMs * (accelerationTime * accelerationTime)) / 2));
                stepsDeceleration = ceil(((vMin * decelerationTime) +
                                (decelerationPerMs * (decelerationTime * decelerationTime)) / 2));

                if (totalSteps <= stepsAcceleration + stepsDeceleration)
                        totalSteps = stepsAcceleration + stepsDeceleration + 1;
                for (currentStep = 0; i < totalSteps; currentStep++){
                        if(currentStep == 0)
                                currentSpeed = vMin;
                        else if(currentStep < stepsAcceleration)
                                currentSpeed += accelerationPerMs;
                        else if(currentStep >= stepsAcceleration)
                                currentSpeed = vMax;
                        else if(currentStep >= totalSteps - stepsDeceleration)
                                currentSpeed -= decelerationPerMs - 1;
                        period = 1000/currentSpeed;
                        PWM_Buf[currentStep] = period;
                }
}
void TIMInit(void) {
        TIM_TimeBaseInitTypeDef TIMInit;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

        //TIMInit.TIM_Period = 1000 - 1;
        TIMInit.TIM_Prescaler = 64000 - 1;
        TIMInit.TIM_ClockDivision = TIM_CKD_DIV1;
        TIMInit.TIM_CounterMode = TIM_CounterMode_Up;
        TIMInit.TIM_RepetitionCounter = 0;

        TIM_TimeBaseInit(TIM1, &TIMInit);
}

void GPIOInit(void) {
        GPIO_InitTypeDef GPIOInit;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

        GPIOInit.GPIO_Pin = GPIO_Pin_8;
        GPIOInit.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIOInit.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA, &GPIOInit);
}

void DMAInit(void) {

        DMA_InitTypeDef DMAInit;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        DMA_DeInit(DMA1_Channel5);
        DMAInit.DMA_PeripheralBaseAddr = (u32)&TIM1 -> ARR;
        DMAInit.DMA_MemoryBaseAddr = (u32) PWM_Buf;
        DMAInit.DMA_DIR = DMA_DIR_PeripheralDST;
        DMAInit.DMA_BufferSize = totalSteps;
        DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
        DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMAInit.DMA_Mode = DMA_Mode_Circular;
        DMAInit.DMA_Priority = DMA_Priority_High;
        DMAInit.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel5, &DMAInit);

        DMA_Cmd(DMA1_Channel5, ENABLE);
}

void PWMInit(void) {
        TIM_OCInitTypeDef PWMInit;

        PWMInit.TIM_OCMode = TIM_OCMode_PWM1;
        PWMInit.TIM_OutputState = TIM_OutputState_Enable;
        PWMInit.TIM_Pulse = 30;
        PWMInit.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OC1Init(TIM1, &PWMInit);
        //TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
        //TIM_ARRPreloadConfig(TIM1, ENABLE);
        TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
        TIM_Cmd(TIM1, ENABLE);
        TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
\$\endgroup\$
0
\$\begingroup\$

The registers are buffered or shadowed (and they are updated on the UP event) so the first update happens when the counter riches its maximum value (and it takes this one minute)

You need to generate the UG event yourself. It is easy to archive using registers (just write the UG bit in the EGR register) but you will need to find how to archive it in the HAL.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.