HIDE NAV

Lab 2 - Bipolar Stepper Motor Driving

Driving multiple step-direction boards

Step-Direction Board Library


main.c


#include "pico/stdlib.h"
#include "stepper_driver_A4988.h"
void main(){
  stepper_motor_t stepper;
  stepmot_setup(&stepper, 19, 20, 18, FULL, 0.65f);

  while(true){
    stepmot_move(&stepper, 100, 10000);
    sleep_ms(6000);
    stepmot_move(&stepper, -50, 20000);
    sleep_ms(6000);
  }

}

stepper_driver_A4988.h


#include "pico/stdlib.h"
#include "hardware/pwm.h"

#define STEPMOT_SLEEP_PWM_WRAP 3125

enum microstep_modes {
  FULL,
  HALF,
  QUARTER,
  EIGHTH,
  SIXTEENTH
};

typedef struct stepper_motor_t {
    // config
    uint step_gp, dir_gp, sleep_gp;
    enum microstep_modes microstep_mode;
    float sleep_hold_duty;
    // state
    bool step_pulse_state;
    bool dir_current;
    long step_delay_us;
    long step_position;
    long step_target;
} stepper_motor_t;

void stepmot_setup(stepper_motor_t* sm, uint step_pin,
  uint dir_pin, uint sleep_pin, enum microstep_modes mode,
  float sleep_duty_cycle);

int64_t stepmot_alarm_callback(alarm_id_t id, void *user_data);

void stepmot_move(stepper_motor_t* sm, long steps, long delay_us_per_step);

stepper_driver_A4988.c


#include "stepper_driver_A4988.h"

void stepmot_setup(stepper_motor_t* sm, uint step_pin,
  uint dir_pin, uint sleep_pin, enum microstep_modes mode,
  float sleep_duty_cycle) {

    sm->step_gp = step_pin;
    sm->dir_gp = dir_pin;
    sm->sleep_gp = sleep_pin;
    sm->microstep_mode = mode;
    sm->sleep_hold_duty = sleep_duty_cycle;
    //default values
    sm->step_pulse_state = false;
    sm->dir_current = true; // true = forward
    sm->step_delay_us = 10000; //10ms pulse rate
    sm->step_position = 0;
    sm->step_target = 0;

    //gpio, pwm and alarm setup
    gpio_init(sm->step_gp);
    gpio_set_dir(sm->step_gp, GPIO_OUT);
    gpio_put(sm->step_gp, sm->step_pulse_state);

    gpio_init(sm->dir_gp);
    gpio_set_dir(sm->dir_gp, GPIO_OUT);
    gpio_put(sm->dir_gp, sm->dir_current);

    //setup a 40kHz PWM for sleep/hold mode
    gpio_set_function(sm->sleep_gp, GPIO_FUNC_PWM);
    uint sleep_pwm_slice_no = pwm_gpio_to_slice_num(sm->sleep_gp);
    pwm_set_clkdiv_int_frac(sleep_pwm_slice_no, 1, 0); //clock divider = 1.0
    pwm_set_wrap(sleep_pwm_slice_no, STEPMOT_SLEEP_PWM_WRAP); // should be 40kHz (?)
    uint16_t level = (STEPMOT_SLEEP_PWM_WRAP + 1) * sm->sleep_hold_duty;
    pwm_set_gpio_level(sm->sleep_gp , level);
    pwm_set_enabled(sleep_pwm_slice_no, true);

    add_alarm_in_us(sm->step_delay_us,stepmot_alarm_callback, sm, true);
  }

  int64_t stepmot_alarm_callback(alarm_id_t id, void *user_data) {
      //cast user_data to stepper motor struct pointer
      stepper_motor_t* sm = (stepper_motor_t*) user_data;

      //check if at target pos.
      if(sm->step_target != sm->step_position){

        //set direction
        if(sm->step_target >  sm->step_position){
          sm->dir_current = true;
          gpio_put(sm->dir_gp, sm->dir_current);
        } else {
          sm->dir_current = false;
          gpio_put(sm->dir_gp, sm->dir_current);
        }

        //start stepping...
        //duty cycle 100%
        uint16_t level = (STEPMOT_SLEEP_PWM_WRAP + 1);
        pwm_set_gpio_level(sm->sleep_gp, level);

        //check pulse state
        if(sm->step_pulse_state == false){
          //currently low - set it to high, wait 1 us
          sm->step_pulse_state = true;
          gpio_put(sm->step_gp, sm->step_pulse_state);
          return -1;
        } else {
          //step pulse is high
          sm->step_pulse_state = false;
          gpio_put(sm->step_gp, sm->step_pulse_state);
          if(sm->dir_current == true) sm->step_position++;
          else sm->step_position--;
          return -1 * sm->step_delay_us;
        }

      } else {
        //put motor in low power duty
        uint16_t level = (STEPMOT_SLEEP_PWM_WRAP + 1) * sm->sleep_hold_duty;
        pwm_set_gpio_level(sm->sleep_gp, level);
        return -1 * sm->step_delay_us;
      }
  }

  void stepmot_move(stepper_motor_t* sm, long steps, long delay_us_per_step) {
    sm->step_target = (sm->step_position + steps);
    sm->step_delay_us = delay_us_per_step;
  }