#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);
}
}
#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);
#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;
}