This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Stepper motor pulses; how to perform acceleration?

Hi,

Experimenting on a stepper motor control (DRV8834). I want to be able to send a single square wave output, with a specified number of pulses. I managed to put together something that works ok using two timers and PPI after reading posts on DevZone. Now I need to find a way to modify this to achieve acceleration / decceleration. I would prefer in the same style using PPI if possible. Any suggestions?

typedef enum {
  MICROSTEP_1 = 1,
  MICROSTEP_2 = 2,
  MICROSTEP_4 = 4,
  MICROSTEP_8 = 8,
  MICROSTEP_16 = 16,
  MICROSTEP_32 = 32
}step_mode_t; 

void move_linear(uint32_t travel_distance_um, uint32_t mm_per_sec, step_mode_t step_mode)
{
    const uint8_t step_len_um = 13;
    
    float nbr_pulses = (float)(travel_distance_um*step_mode)/step_len_um;
    uint32_t nbr_toggles = (uint32_t)(nbr_pulses*2);
    float pt_pulses_us = ((float)travel_distance_um*1000/mm_per_sec)/nbr_toggles;
    uint32_t timer_ticks_reload = (uint32_t)(pt_pulses_us / 0.0625) + 3;
  
    // Stop timers before change
    NRF_TIMER1->TASKS_STOP = 1; 
    NRF_TIMER2->TASKS_STOP = 1;
    
    //Setup pulse out pin
    NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
    GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
    LED_1 << GPIOTE_CONFIG_PSEL_Pos | 
    GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos; 

    //Setup pulse counter
    NRF_TIMER2->MODE = 1; //Counter mode
    NRF_TIMER2->BITMODE = 3; //32 bit
    NRF_TIMER2->TASKS_CLEAR = 1; //Clear counter value
    NRF_TIMER2->CC[1] = nbr_toggles; //Stop after <nbr> of pulses
    NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;
    
    //Setup pulse out timer
    NRF_TIMER1->MODE = 0; //Timer mode
    NRF_TIMER1->BITMODE = 3; //32 bit
    NRF_TIMER1->PRESCALER = 0; //16Mhz 
    NRF_TIMER1->CC[1] = timer_ticks_reload;
    NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;

    //PPI connections
    NRF_PPI->CH[0].EEP = (uint32_t) &NRF_TIMER1->EVENTS_COMPARE[1]; // input = compare event of timer1
    NRF_PPI->CH[0].TEP = (uint32_t) &NRF_GPIOTE->TASKS_OUT[0]; // output = polarity toggle of the selected gpio 
    NRF_PPI->FORK[0].TEP = (uint32_t) &NRF_TIMER2->TASKS_COUNT;
    NRF_PPI->CH[1].EEP = (uint32_t) &NRF_TIMER2->EVENTS_COMPARE[1]; // input = compare event of timer2
    NRF_PPI->CH[1].TEP = (uint32_t) &NRF_TIMER2->TASKS_CAPTURE[1]; 
    NRF_PPI->FORK[1].TEP = (uint32_t) &NRF_TIMER1->TASKS_STOP; //Stop pulse timer afer X pulses counted
    
    NRF_PPI->CHENSET = (PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos);
    NRF_PPI->CHENSET = (PPI_CHENSET_CH1_Enabled << PPI_CHENSET_CH1_Pos);

    //*(uint32_t*)0x40009C0C = 1; // pan73_workaround
    NRF_TIMER2->TASKS_START = 1; // Start counter
    NRF_TIMER1->TASKS_START = 1; // Start timer
}

int main(void)
{
    move_linear(13, 10, MICROSTEP_16);
    while(1);
}

BR

//Ola  

Parents
  • By acceleration/decceleration I suppose you are talking about the speed of the stepper motor? I am not too familiar with the DRV8834 sensor, and how you control the speed. Is it the frequnecy of the square wave or the duty cycle? Or something else?

    Best regards,

    Simon

  • Sorry, I should have given some more details. As I get it, the speed is controlled by the frequency of the square wave. There are several examples using pwm driver for instance where duty cycle is controlled, but here I want a fixed 50% duty cycle and increasing/decreasing frequency. The challenge, I guess, is to find a solution that minimizes the involvement of sw, controlling the frequency of the pulses, with possibilty of acc/deccl, and also keeping track of the exact pulses sent

Reply
  • Sorry, I should have given some more details. As I get it, the speed is controlled by the frequency of the square wave. There are several examples using pwm driver for instance where duty cycle is controlled, but here I want a fixed 50% duty cycle and increasing/decreasing frequency. The challenge, I guess, is to find a solution that minimizes the involvement of sw, controlling the frequency of the pulses, with possibilty of acc/deccl, and also keeping track of the exact pulses sent

Children
  • Ok. I thought of one solution that might work:


    • The solution requires you to make multiple timers, each using two CC registers.
    • CC1 determines the frequency and CC2 determines the amount of toggles for each timer
    • When CC1 triggers you toggle the output pin and when CC2 triggers you stop the current timer and start the next one

    I have not tested this, and don't know if it actually works. There also may be some simpler solutions to this, but this is the best I could think of right now,

    Best regards,

    Simon

  • Thank you for the effort Simon and sorry for the late feedback. The problem as I see with the timer suggestion you provided is that the speed steps possible is limited to the number of timers used. I am trying to achieve something with a bit more resolution

     

Related