nRF52 + DRV8825 Stepper Driver

This is a stepper motor controller built around the DRV8825 and the nRF52.

Some sample firmware is available below (or as files: nrf52-drv8825.ino and radio.h). This code defines a command set issued over the radio for moving a number of steps, changing stepping speed, setting microstepping parameters, and setting a current limit value.


#include "radio.h"
uint16_t pwms[1] = {0};
uint16_t step_period = 20000; //microseconds

const uint8_t pin_mode1 = 3; //A1
const uint8_t pin_mode0 = 0; //XL1
const uint8_t pin_step = 1; //XL2
const uint8_t pin_direction = 2; //A0
const uint8_t pin_nrst = 27; //p27
const uint8_t pin_ref = 26; //p26

int i=0; //counter

void stepper_setup(){
  NRF_GPIO->DIRSET = (1 << pin_nrst); //set nrst/nslp pins as output
  NRF_GPIO->OUTCLR = (1 << pin_nrst); //set nrst/nslp low to disable drv8825
  NRF_GPIO->OUT = (0 << pin_nrst);

  NRF_GPIO->DIRSET = (1 << pin_mode1) | (1 << pin_mode0); //set mode pins as output
  NRF_GPIO->OUTCLR = (1 << pin_mode1) | (1 << pin_mode0); //set to full step mode

  NRF_GPIO->DIRSET = (1 << pin_step) | (1 << pin_direction); //set step/dir pins as output

  //Use PWM module to generate aref/bref
  NRF_GPIO->DIRSET = (1 << pin_ref); //set ref pin as output
  NRF_GPIO->OUTCLR = (1 << pin_ref); //set ref pin low
  NRF_PWM0->PSEL.OUT[0] = (pin_ref << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); //set aref pin to pwm out[0]
  NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
  NRF_PWM0->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
  NRF_PWM0->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); //16MHz tick
  NRF_PWM0->COUNTERTOP = (1600 << PWM_COUNTERTOP_COUNTERTOP_Pos); //10 kHz pwm freq.
  NRF_PWM0->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
  NRF_PWM0->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
  pwms[0] = 1600-100; //100/1600 * 3.3v = .2V = 200 mA limit
  NRF_PWM0->SEQ[0].PTR = ((uint32_t)(pwms) << PWM_SEQ_PTR_PTR_Pos);
  NRF_PWM0->SEQ[0].CNT = (1 << PWM_SEQ_CNT_CNT_Pos);
  NRF_PWM0->SEQ[0].REFRESH = 0;
  NRF_PWM0->SEQ[0].ENDDELAY = 0;
  NRF_PWM0->TASKS_SEQSTART[0] = 1;
  delay(1); //give aref filter time to settle.
}

void parse_command(){
  //interpret command from radio for stepper actions
  if( radio_buffer[0] == 1 ){
    //move by commanded number of steps
    if (radio_buffer[1] > 0){
      NRF_GPIO->OUTSET = (1 << pin_direction); //set direction forwards      
    } else {
      NRF_GPIO->OUTCLR = (1 << pin_direction); //set direction backwards    
    }
    radio_buffer[1] = radio_buffer[1] > 0 ? radio_buffer[1] : -radio_buffer[1];
    for(i=0; i < radio_buffer[1]; i++){
      NRF_GPIO->OUTSET = (1 << pin_step);
      delayMicroseconds(step_period);
      NRF_GPIO->OUTCLR = (1 << pin_step);
      delayMicroseconds(10);        
    }
  } else if (radio_buffer[0] == 2){
    //change step speed
    step_period = radio_buffer[1];
  } else if (radio_buffer[0] == 3){
    //change microstepping
    if (radio_buffer[1] & 1){ 
      NRF_GPIO->OUTSET = (1 << pin_mode0);
    } else {
      NRF_GPIO->OUTCLR = (1 << pin_mode0);      
    }
    if (radio_buffer[1] & 2){ 
      NRF_GPIO->OUTSET = (1 << pin_mode1);
    } else {
      NRF_GPIO->OUTCLR = (1 << pin_mode1);      
    }
  } else if (radio_buffer[0] == 4){
    //change current limit
    pwms[0] = 1600-radio_buffer[1]; //100/1600 * 3.3v = .2V = 200 mA limit
    NRF_PWM0->SEQ[0].REFRESH = 1;
  }
  else{
  }

  //unrecognized command, set radio buffer to all -1
  //for(int i=0; i < PACKET_LENGTH; i++){
  //  radio_buffer[i] = -1;
  //}      

  //reset radio buffer
  for(i=0; i < PACKET_LENGTH; i++){
    radio_buffer[i] = 0;
  }
}


void setup() {
  
  //Switch to internal LFCLK to disconnect from XL1 and XL2
  NRF_CLOCK->LFCLKSRC = 0; //disconnect XL1 AND XL2 FROM LFCLK
  NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
  NRF_CLOCK->TASKS_LFCLKSTART    = 1;
  while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}

  stepper_setup();
  radio_setup();

  NRF_GPIO->OUTSET = (1 << pin_nrst); //set nrst/nslp high to enable drv8825

  while (true) {
    int result = radio_recv(); //wait until recieve
    parse_command(); 
  }
}

void loop() {}