for controlling stepper motor with A4980
Dependents: HIDTympDeviceWithPIDController
motorControl.cpp
- Committer:
- piniels
- Date:
- 2014-10-06
- Revision:
- 0:9156e6b6bf46
File content as of revision 0:9156e6b6bf46:
/* ############################################ ## motorControl v0.1 Library ## ## created by Peter Ilsoee ## ############################################ ---- piniels@gmail.com ----- This library was made for 4-Phase Stepper Motors I don't take any resposability for the damage caused to your equipment. */ #include "motorControl.h" #include "mbed.h" #include "globalt.h" SPI spi(PTE1, PTE3, PTE2); // mosi, miso, sclk DigitalOut cs(PTE4); //struct for holding run register information //GPIO DigitalOut valve(PTD0); DigitalIn centerInput(PTD4); //Ticker for running at a specified speed Ticker runTickMotorControl; /** * ! @brief Construct including the pins for "manual(not SPI cmd)" control of A4980 * @param step Step logic input. Motor advances on rising edge. Filtered input with hysteresis. * @param dir Direction logic input. Direction changes on the next STEP rising edge. When high, the Phase Angle Number is increased * on the rising edge of STEP. Has no effect when using the serial * interface. Filtered input with hysteresis. * @param ms1 Microstep resolution select input. * @param ms0 Microstep resolution select input. * @param enable Controls activity of bridge outputs. When held low, deactivates the outputs, that is, turns off all output bridge FETs. * Internal logic continues to follow input commands. * @param reset Resets faults when pulsed low. Forces low-power shutdown(sleep) when held low for more than the Reset Shutdown * Width, tRSD . Can be pulled to VBB with 30 kΩ resistor. * @param diag Diagnostic output. Function selected via the serial interface, * setting Configuration Register 1. Default is Fault output. */ motorControl::motorControl(int numberOfSteps, PinName step, PinName dir, PinName ms1, PinName ms0, PinName enable, PinName reset, PinName diag): _Number_OF_STEPS(numberOfSteps), _STEP(step), _DIR(dir), _MS1(ms1), _MS0(ms0), _ENABLE(enable), _RESET(reset), _DIAG(diag){ this->_RESET = 0; this->_STEP = 0; // duty cycle on 50 % this->_DIR = 0; this->_MS1 = 0; this->_MS0 = 0; this->_ENABLE = 0; //Setting default values to run regi this->_REGI_RUN.B.sc = 0x1; //1 steps positive value this->_REGI_RUN.B.dcy = 0x1; // bit7-6 Decay mode selection 00=Slow, *01=Mixed-PFD fixed, 10=Mixed-PFD auto, 11=Fast this->_REGI_RUN.B.brk = 0x0; // bit8 Brake enable *0=Normal operation 1=Brake active this->_REGI_RUN.B.slew = 0x1; // bit9 Slew rate control 0=Disable *1=Enable this->_REGI_RUN.B.hlr = 0x0; // bit10. Selects slow decay and brake recirculation path *0=High side, 1=Low side this->_REGI_RUN.B.ol = 0x1; // bit12-11. Open load current threshold as a percentage of maximum current defined by ISMAX and MXI[1..0] 00=20%, *01=30%, 10=40%, 11=50% this->_REGI_RUN.B.en = 1; // bit13. Phase current enable OR with ENABLE pin *0=Output bridges disabled if ENABLE pin = 0, 1=Output bridges enabled this->_REGI_RUN.B.addr = 0x2; // bit15-14 Address run = 0b10 //Setting default value to control regi. 0 this->_REGI_0.B.pwm = 0x0; this->_REGI_0.B.tofFrq = 0x6; this->_REGI_0.B.tbk = 0x1; this->_REGI_0.B.pfd = 0x4; this->_REGI_0.B.mx = 0x03; // bit10-9. Max phase current as a percentage of I(SMAX) 00=25% 01=50% 10=75% *11=100% this->_REGI_0.B.ms = 0x0; this->_REGI_0.B.syr = 0x1; this->_REGI_0.B.addr = 0x0; //Setting default value to control regi. 1 this->_REGI_1.B.diag = 0x0; this->_REGI_1.B.cd = 0x8; this->_REGI_1.B.notInUse = 0x0; this->_REGI_1.B.tsc = 0x2; this->_REGI_1.B.osc = 0x0; this->_REGI_1.B.addr = 0x1; wait(0.1); this->_RESET = 1; this->_Step_Counter = 0; } void motorControl::initSpi() { // rotate the motor 1 step anticlockwise cs = 1; spi.format(8,3); spi.frequency(1000000); } /** * ! @brief set the step counter * @param value an int counting the steps */ void motorControl::setStepCount(int value) { this->_Step_Counter = value; } /** * ! @brief get the step counter * @return an int counting the steps */ int motorControl::getStepCount() { return this->_Step_Counter; } /** * ! @brief set configuration and control register 0 * @param t_config_control_regi_0 an union with represents some seetings (see datasheet A4980 data sheet) */ int motorControl::setConfigRegi0(t_config_control_regi_0 value) { this->_REGI_0 = value; cs = 0; int response = (spi.write(value.I >> 8)) << 8; response |= spi.write(value.I & 0xff); cs = 1; return response; } /** * ! @brief get configuration and control register 0 * @return t_config_control_regi_0 an union with represents some seetings (see datasheet A4980 data sheet) */ t_config_control_regi_0 motorControl::getConfigRegi0() { return this->_REGI_0; } /** * ! @brief open or close the GPIO controlling the valve * @parm openTrue Boolean true for open */ void motorControl::openCloseValve(bool openTrue) { if(openTrue) { valve = 0; } else { valve = 1; } } /** * ! @brief set configuration and control register 1 * @param t_config_control_regi_1 an union with represents some seetings (see datasheet A4980 data sheet) */ int motorControl::setConfigRegi1(t_config_control_regi_1 value) { this->_REGI_1 = value; cs = 0; int response = (spi.write(value.I >> 8)) << 8; response |= spi.write(value.I & 0xff); cs = 1; return response; } /** * ! @brief set micro step bits * @param int from 0 to 3 */ void motorControl::setMicroSteps(int value) { printf("Value for microsteps: %i",value); printf("\r\n"); this->_MS1 = (value & 0x2) >> 1; this->_MS0 = value & 0x1; } /** * ! @brief get micro step bits * @param int from 0 to 3 */ int motorControl::getMicroSteps() { return this->_MS1 << 1 | this->_MS0; } /** * ! @brief get configuration and control register 1 * @return t_config_control_regi_1 an union with represents some seetings (see datasheet A4980 data sheet) */ t_config_control_regi_1 motorControl::getConfigRegi1() { return this->_REGI_1; } /** * ! @brief set configuration and run register * @param t_run_regi an union with represents some seetings (see datasheet A4980 data sheet) */ int motorControl::setRunRegi(t_run_regi value) { this->_REGI_RUN = value; cs = 0; int response = (spi.write(value.I >> 8)) << 8; response |= spi.write(value.I & 0xff); cs = 1; return response; } /** * ! @brief get run control register * @return t_run_regi an union with represents some seetings (see datasheet A4980 data sheet) */ t_run_regi motorControl::getRunRegi() { return this->_REGI_RUN; } /** * ! @brief Run at a specified speed, none blocking * @param startStop If true start moter if false stop motor * @param whatSpeed speed in RPM * @param direction if 1 then postive phase, if 0 negative phase */ // void motorControl::runStepperAtSpeed(bool startStop, int whatSpeed, int direction) { this->_DIR = direction; this->step_delay = calculateStepDelay(whatSpeed); if(this->step_delay > MAX_STEP_DELAY) { this->step_delay = MAX_STEP_DELAY; } else if(this->step_delay < MIN_STEP_DELAY) { this->step_delay = MIN_STEP_DELAY; } if(startStop) { this->_ENABLE = 1; _STEP = 0.5; //duty cycle 50% _STEP.period_us((int) this->step_delay); } else { _STEP = 0; //Duty-cycle 0 _ENABLE = 0; _STEP = 0; } } void motorControl::doRamp(int numberOfRampsteps,float endDelay) { //Test do ramping int delay_us_start = 10000; int diff_delay_us = delay_us_start - endDelay; int ramping_step_us = diff_delay_us/numberOfRampsteps; int delay_ramp = 0; for(int i = 0;i < numberOfRampsteps; i++) { delay_ramp = delay_us_start - (i*ramping_step_us); printf("Ramping Delay is in us: %i", delay_ramp); printf("\r\n"); _STEP.period_us(delay_ramp); wait_us(delay_ramp); } } float motorControl::calculateStepDelay(int whatSpeed) { if(whatSpeed != 0) { this->step_delay = 60L * 1000000L / ((float)this->_Number_OF_STEPS * (float)whatSpeed); int microStep = getMicroSteps(); if(microStep > 0) { if(microStep == 1) { this->step_delay = this->step_delay/2; } else if(microStep == 2) { this->step_delay = this->step_delay/4; } else { this->step_delay = this->step_delay/16; } } } else { this->step_delay = 60L * 1000L / (float) this->_Number_OF_STEPS / (float) 1; } return this->step_delay; } // tick event handler for running the motor at a specified speed void motorControl::runMotor(void) { setRunRegi(this->_REGI_RUN); //1 steps positive value if(this->_Bool_Direction) { this->_Step_Counter++; } else { this->_Step_Counter--; } } void motorControl::goToZeroPosition(int whatSpeed) { float step_delay = (60 / (float)this->_Number_OF_STEPS / (float)whatSpeed); bool runMotorBool = true; bool runMotorBack = false; openCloseValve(true); while(runMotorBool)//this->_Step_Counter != 0 || centerInput ) { this->_REGI_RUN.B.en = 1; if(whatSpeed > 0) { this->_Bool_Direction = true; this->_REGI_RUN.B.sc = 0x10; // 1 steps positive value runMotor(); wait(step_delay); if(centerInput) { runMotorBool = false; this->_Step_Counter = 0; } } else { this->_Bool_Direction = false; this->_REGI_RUN.B.sc = 0x30; // 1 steps positive value runMotor(); wait(-1*step_delay); if(centerInput) { runMotorBack = true; } else if(runMotorBack && !centerInput) { runMotorBool = false; this->_Step_Counter = 0; } } } this->_REGI_RUN.B.en = 0; } // Run at a specified speed, no blocking void motorControl::runStepperAtSpeedWithSPI(bool startStop, int whatSpeed, int direction) { if(whatSpeed != 0) { this->step_delay = (60L * 1000000L / this->_Number_OF_STEPS / whatSpeed); } else { this->step_delay = 60L * 1000000L / this->_Number_OF_STEPS / 1; } //pc.printf("Step dealy: %d",this->step_delay); //pc.printf("\r\n"); if(direction) { this->_Bool_Direction = true; if(whatSpeed > 50)//HACK: for testing micro step { this->_REGI_RUN.B.sc = 0x10; // 1 steps positive value } else { this->_REGI_RUN.B.sc = 0x10; // 1 steps positive value //this->_REGI_RUN.B.sc = 0x4; // 1/8 steps positive value //this->step_delay = this->step_delay/4; printf("Step dealy micro step: %d",this->step_delay); printf("\r\n"); } } else { this->_Bool_Direction = false;; if(whatSpeed > 50) //HACK: for testing micro step { this->_REGI_RUN.B.sc = 0x30; // 1 steps negative value } else { this->_REGI_RUN.B.sc = 0x30; // 1 steps negative value //this->_REGI_RUN.B.sc = 0x3C; // 1/16 steps negative value //this->step_delay = this->step_delay/4; printf("Step dealy micro step: %d",this->step_delay); printf("\r\n"); } // } if(startStop) { this->_REGI_RUN.B.en = 1; runTickMotorControl.attach_us(this, &motorControl::runMotor, (this->step_delay)); // the address of the function to be attached } else { this->_REGI_RUN.B.en = 0; setRunRegi(this->_REGI_RUN); runTickMotorControl.detach(); } } void motorControl::step(int num_steps, int delay, bool direction) {// steper function: number of steps, direction (0- right, 1- left), this->_REGI_RUN.B.en = 1; if(direction) { if(getMicroSteps() == 0) { this->_REGI_RUN.B.sc = 0x10; // 1 steps positive value } else if(getMicroSteps() == 1) { this->_REGI_RUN.B.sc = 0x8; // 1 steps positive value } else if(getMicroSteps() == 2) { this->_REGI_RUN.B.sc = 0x4; // 1 steps positive value } else if(getMicroSteps() == 3) { this->_REGI_RUN.B.sc = 0x2; // 1 steps positive value } } else { if(getMicroSteps() == 0) { this->_REGI_RUN.B.sc = 0x30; // 1 steps positive value } else if(getMicroSteps() == 1) { this->_REGI_RUN.B.sc = 0x38; // 1 steps positive value } else if(getMicroSteps() == 2) { this->_REGI_RUN.B.sc = 0x3C; // 1 steps positive value } else if(getMicroSteps() == 3) { this->_REGI_RUN.B.sc = 0x3E; // 1 steps positive value } } for(int i = 0;i < num_steps;i++) { setRunRegi(this->_REGI_RUN); //1 steps positive value wait_ms(delay); } this->_REGI_RUN.B.en = 0; setRunRegi(this->_REGI_RUN); //1 steps positive value }