for controlling stepper motor with A4980

Dependents:   HIDTympDeviceWithPIDController

Files at this revision

API Documentation at this revision

Comitter:
piniels
Date:
Mon Oct 06 11:57:45 2014 +0000
Commit message:
jkhasd

Changed in this revision

A4980ControlRegi.h Show annotated file Show diff for this revision Revisions of this file
motorControl.cpp Show annotated file Show diff for this revision Revisions of this file
motorControl.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/A4980ControlRegi.h	Mon Oct 06 11:57:45 2014 +0000
@@ -0,0 +1,99 @@
+/*-----------------------------------------------------------
+*                   COPYRIGHT (C) 2010.
+*          GN Otometrics. All rights reserved.
+*-----------------------------------------------------------
+*            P R O P R I E T A R Y   R I G H T S
+* This document must not be used, nor copied in any form or
+* handed over to third party, without prior written
+* permission from GN Otometrics.
+*-----------------------------------------------------------
+*
+* This source file is part of the 1082 Turtle project.
+*
+* P4 Info: (P4-filetype must be "ktext" for these to work!)
+* Last edit by: $Author:$
+* Date:         $DateTime:$
+* Filename:     $File:$
+* Revision:     $Revision:$
+*
+* File Info:
+* Original author: peilni
+* Creation date:   Nov 19, 2013
+*
+* Doxygen Info: *//*!
+* @file
+* @brief Blah blah blah.
+*
+* @htmlonly
+* @endhtmlonly
+*
+* Blah blah
+*/
+#ifndef A4980CONTROLREGI_H_
+#define A4980CONTROLREGI_H_
+#include <stdint.h>
+
+/*
+ * (*) are default
+ */
+typedef union
+{
+    uint16_t I;
+
+    struct
+    {
+        uint16_t pwm              : 1;    // bit0 PWM configuration *0=Fixed off-time, 1=Fixed frequency
+        uint16_t tofFrq           : 3;    // bit3-1 Off time (only valid when PWM bit = 0).Replaces FRQ bits(Assumes 4-MHz clock) 000=20us, 001=24us, 010=28us, 011=32us, 100=36us, 101=40us, *110=44us, 111=48us//        Frequency )(only valid when PWM bit = 1)Replace TOF bits(Assumes 4-MHz clock) 000=24us/41.7kHz, 001=32us/31.3kHz, 010=40us/25kHz, 011=46us/21.7kHz, 100=52us/19.2kHz 101=56us/17.9kHz, *110=60us/16.7kHz, 111=64us/15.6kHz
+        uint16_t tbk              : 2;    // bit5-4 Blank Time (Assumes 4-MHz clock) 00=1us, *01=1.5us, 10=2.5us, 11=3.5us
+        uint16_t pfd              : 3;    // bit8-6 Fast decay time for mixed decay. Assumes 4-MHz clock 000=2us, 001=3us, 010=4us, 011=6us, 100=8us, 101=10us, 110=14us, 111=20us
+        uint16_t mx               : 2;    // bit10-9. Max phase current as a percentage of I(SMAX) 00=25% 01=50% 10=75% *11=100%
+        uint16_t ms               : 2;    // bit12-11. Microstep mode for external STEP input control *00=Full Step 01=Half Step 10=Quarter Step 11=Sixteenth Step
+        uint16_t syr              : 1;    // bit13. Synchronous rectification 0=Diode recirculation *1=Synchronous
+        uint16_t addr             : 2;    // bit15-14 Address config0 = 0b00
+
+    } B;
+} t_config_control_regi_0;
+
+/*
+ * (*) are default
+ */
+typedef union
+{
+    uint16_t I;
+
+    struct
+    {
+        uint16_t diag             : 2;    // bit1-0 Selects signal routed to DIAG output *00=Fault-low true, 01=ST-low true, 10=PWN-on Phase A, 11=Temperature
+        uint16_t cd               : 4;    // bit5-2 PWM count difference for ST detection default to 8
+        uint16_t notInUse         : 5;    // bit10-6 Not in use value = 0
+        uint16_t tsc              : 2;    // bit12-11 Overcurrent fault delay(Assumes 4-MHz clock) 00=0.5us, 01=1us, *10=2us, 11=3us
+        uint16_t osc              : 1;    // bit13 Selects clock source *0=internal, 1=external
+        uint16_t addr             : 2;    // bit15-14 Address config0 = 0b01
+
+    } B;
+}t_config_control_regi_1;
+
+/*
+ * (*) are default
+ */
+typedef union
+{
+    uint16_t I;
+
+    struct
+    {
+        uint16_t sc               : 6;    // bit5-0 Step change number 2’s complement format. Positive value increases Step Angle Number. Negative value decreases Step Angle Number
+        uint16_t dcy              : 2;    // bit7-6 Decay mode selection 00=Slow, *01=Mixed-PFD fixed, 10=Mixed-PFD auto, 11=Fast
+        uint16_t brk              : 1;    // bit8 Brake enable *0=Normal operation 1=Brake active
+        uint16_t slew             : 1;    // bit9 Slew rate control 0=Disable *1=Enable
+        uint16_t hlr              : 1;    // bit10. Selects slow decay and brake recirculation path *0=High side, 1=Low side
+        uint16_t ol               : 2;    // 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%
+        uint16_t en               : 1;    // bit13. Phase current enable OR with ENABLE pin *0=Output bridges disabled if ENABLE pin = 0, 1=Output bridges enabled
+        uint16_t addr             : 2;    // bit15-14 Address run = 0b10
+
+    } B;
+}t_run_regi;
+
+
+
+#endif /* A4980CONTROLREGI_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motorControl.cpp	Mon Oct 06 11:57:45 2014 +0000
@@ -0,0 +1,509 @@
+/*
+############################################
+##           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
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/motorControl.h	Mon Oct 06 11:57:45 2014 +0000
@@ -0,0 +1,67 @@
+/*
+############################################
+##           Motor Control v0.1 Library   ##
+##          created by Peter Ilsoee       ##
+############################################
+        ---- piniels@gmail.com -----
+This library was made for 4-Phase Stepper Motors for A4980 SPI device from Allegro
+I don't take any resposability for the damage caused to your equipment.
+
+*/
+#ifndef MOTOR_CONTROL_H
+#define MOTOR_CONTROL_H
+
+#include "mbed.h"
+#include "A4980ControlRegi.h"
+
+class motorControl {
+public:
+
+    motorControl(int numberOfSteps, PinName step, PinName dir, PinName ms1, PinName ms0, PinName enable, PinName reset, PinName diag); //motor constructor
+    void step(int num_steps, int direction, int speed);
+
+    void initSpi();
+    int setConfigRegi0(t_config_control_regi_0 value);
+    int setConfigRegi1(t_config_control_regi_1 value);
+    int setRunRegi(t_run_regi value);
+    int getStepCount();
+    void setStepCount(int value);
+    void setMicroSteps(int value);
+    int getMicroSteps();
+    t_config_control_regi_0 getConfigRegi0();
+    t_config_control_regi_1 getConfigRegi1();
+    t_run_regi getRunRegi();
+    void runStepperAtSpeed(bool startStop, int whatSpeed, int direction);
+    void runStepperAtSpeedWithSPI(bool startStop, int whatSpeed, int direction);
+    void goToZeroPosition(int whatSpeed);
+    void openCloseValve(bool openTrue);
+    /** Call back member for timer tick
+     *
+     */
+    void runMotor(void);
+    void doRamp(int numberOfRampsteps,float endDelay);
+    float calculateStepDelay(int whatSpeed);
+    void step(int num_steps, int delay, bool direction);
+    
+private:
+    int _Number_OF_STEPS;
+    int _Step_Counter;
+    bool _Bool_Direction;
+    PwmOut _STEP;
+    DigitalOut _DIR;
+    DigitalOut _MS1;
+    DigitalOut _MS0;
+    DigitalOut _ENABLE;
+    DigitalOut _RESET;
+    DigitalIn  _DIAG;
+    float step_delay;
+    t_config_control_regi_0 _REGI_0;
+    t_config_control_regi_1 _REGI_1;
+    t_run_regi              _REGI_RUN;
+    
+
+
+
+};
+
+#endif