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 Reply Children
  • 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

  • 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