Skip to content
Snippets Groups Projects
Select Git revision
  • 1392c27cf9ff1a7f5f5477d23880f2e5c59c898e
  • master default protected
  • v0.10.0
  • v0.10.0-rc2
  • v0.10.0-rc1
  • v0.9.0
  • v0.9.0-rc1
  • v0.8.0
  • v0.8.0-rc2
  • v0.8.0-rc1
  • v0.7.0
  • v0.7.0-rc2
  • v0.7.0-rc1
  • v0.6.1
  • v0.6.0
  • v0.6.0-rc2
  • v0.6.0-rc1
  • v0.5.0
  • v0.5.0-rc2
  • v0.5.0-rc1
  • v0.4.0
  • v0.4.0-rc2
22 results

NEWS-0.10.0

Blame
  • To find the state of this project's repository at the time of any of these versions, check out the tags.
    index.html 5.37 KiB
    <html>
    <head>
    <style>
    pre code {
      background-color: #eee;
      border: 1px solid #999;
      display: block;
      padding: 20px;
    }
    </style>
    </head>
    <body>
    <h1>nRF52 + DRV8825 Stepper Driver</h1>
    
    <a href='nrf52-stepper-layout.png'><img src='nrf52-stepper-layout.png' height=300px></a>
    <a href='nrf52-stepper-traces.png'><img src='nrf52-stepper-traces.png' height=300px></a>
    <a href='nrf52-stepper-interior.png'><img src='nrf52-stepper-interior.png' height=300px></a>
    <a href='nrf52-stepper-mounted.jpg'><img src='nrf52-stepper-mounted.jpg' height=300px></a>
    <p>This is a stepper motor controller built around the DRV8825 and the nRF52.  The nRF52 receives commands over the radio and controls the motor, which means we only need to deliver power to the motor, no data lines.</p>
    
    <p>This board uses a PWM output and a low pass filter to deliver a voltage level to control the current limiting value for the DRV8825.  A 10K resistor and a 1uF capacitor do a reasonably good job smoothing the 10kHz PWM into a constant voltage level.</p>
    
    <p>Some sample firmware is available below (or as files: <a href='nrf52-drv8825/nrf52-drv8825.ino'>nrf52-drv8825.ino</a> and <a href='nrf52-drv8825/radio.h'>radio.h</a>).  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.</p>
    
    <p>For help getting started programming the nRF52, see <a href='https://gitlab.cba.mit.edu/pub/hello-world/nrf52'>this page.</a></p>
    
    <pre>
    <code>
    #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() {}
    
    </code>
    </pre>
    
    </body>
    </html>