Library for STMicroelectronics dSPIN L6470 stepper driver. "daisy-chain" supported.

Dependents:   L6470_daisy_chain l6470

Revision:
3:486fb90dc7d5
Parent:
1:db64ad30b4b3
Child:
4:4127dd195311
--- a/L6470SDC.cpp	Tue Jun 09 06:10:11 2015 +0000
+++ b/L6470SDC.cpp	Tue Jan 12 11:27:01 2016 +0000
@@ -1,9 +1,11 @@
 #include "L6470SDC.h"
 
-#define CS_ACTIVE       cs->write(0)
-#define CS_INACTIVE     cs->write(1)
+#define CS_ACTIVE cs->write(0)
+#define CS_INACTIVE cs->write(1)
 
-//充実のコンストラクタ
+/* ---------------------------------------------------------------------------
+ * Constructor (override +9)
+ -------------------------------------------------------------------------- */
 L6470SDC::L6470SDC(PinName tx, PinName rx, PinName mosi, PinName miso, PinName sclk, PinName csel){
     pc = new Serial(tx, rx);
     spi = new SPI(mosi, miso, sclk);
@@ -61,6 +63,19 @@
     cs = csel;
 }
 
+/* ---------------------------------------------------------------------------
+ * Destructor
+ -------------------------------------------------------------------------- */
+L6470SDC::~L6470SDC(){
+    delete[] Queue;
+    delete pc;
+    delete spi;
+    delete cs;
+}
+
+/* ---------------------------------------------------------------------------
+ * initializer
+ -------------------------------------------------------------------------- */
 void L6470SDC::init(bool initSPI){
     //SPI初期化
     if(initSPI){
@@ -82,6 +97,12 @@
         motor_count++;
     }while(rsv != 0xEE);
     CS_INACTIVE;
+    
+    //モーター個数分のキューを作成(要素番号とモーター番号を合わせるため+1している)
+    Queue = new L6470CMDQ[motor_count+1];
+
+    //キューをクリア
+    Qclear();
 
     //全てのモーターに空コマンドを送り、リセットをかける
     CS_ACTIVE;
@@ -101,10 +122,16 @@
     }
 }
 
+/* ---------------------------------------------------------------------------
+ * GET motor count
+ -------------------------------------------------------------------------- */
 int L6470SDC::getMotorCount(){
     return motor_count;
 }
 
+/* ---------------------------------------------------------------------------
+ * PRIVATE: command send to L6470
+ -------------------------------------------------------------------------- */
 void L6470SDC::setCmd(int motorNumber, unsigned char cmdAddress, unsigned long value, int bitLen){
 #ifdef DEBUG_L6470SDC
     if(hasSerial) pc->printf("[Command] Motor-No.%03d, CMD:0x%04X, VAL:0x%06X\r\n", motorNumber, cmdAddress, value);
@@ -141,6 +168,9 @@
     }
 }
 
+/* ---------------------------------------------------------------------------
+ * PRIVATE: parameter send to L6470
+ -------------------------------------------------------------------------- */
 void L6470SDC::setParam(int motorNumber, unsigned char regAddress, unsigned long value, int bitLen){
 #ifdef DEBUG_L6470SDC
     if(hasSerial) pc->printf("[SetParam] Motor-No.%03d, SetParam: REG:0x%04X, VAL:0x%06X\r\n", motorNumber, regAddress, value);
@@ -174,6 +204,9 @@
     }
 }
 
+/* ---------------------------------------------------------------------------
+ * PRIVATE: parameter get from L6470
+ -------------------------------------------------------------------------- */
 unsigned long L6470SDC::getParam(int motorNumber, unsigned char regAddress, int bitLen){
     //戻り値
     unsigned long ret = 0;
@@ -213,87 +246,327 @@
     return ret;
 }
 
-// cmd method ------------------------------------------------------------------------------
+/* ---------------------------------------------------------------------------
+ * COMMAND
+ -------------------------------------------------------------------------- */
+//@ GET busyflag
 bool L6470SDC::isBusy(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return false;
     return !((getStatus(motorNumber) & 0x02) >> 1);
 }
-
+//@ motor run
 void L6470SDC::run(int motorNumber, unsigned long hex_speed, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, (isClockwise) ? CMD_RUN_MINUS : CMD_RUN_PLUS, hex_speed, 20);
 }
-
+//@ motor step
 void L6470SDC::step(int motorNumber, unsigned int count, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     for(;count<=0;count--){
         while(isBusy(motorNumber));
         setCmd(motorNumber, (isClockwise) ? CMD_STEP_MINUS : CMD_STEP_PLUS, 0, 0);
     }
 }
-
+//@ motor move
 void L6470SDC::move(int motorNumber, unsigned long stepsCount, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, (isClockwise) ? CMD_ADDSTEP_MINUS : CMD_ADDSTEP_PLUS, stepsCount, 22);
 }
-
+//@ motor goto ABSpos(shortest path)
 void L6470SDC::goto1(int motorNumber, unsigned long ABSPos){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_GOTO, ABSPos, 22);
 }
-
+//@ motor goto ABSpos
 void L6470SDC::goto2(int motorNumber, unsigned long ABSPos, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, (isClockwise) ? CMD_GOTO_DIR_MINUS : CMD_GOTO_DIR_PLUS, ABSPos, 22);
 }
-
+//@ motor goto mark
 void L6470SDC::goUntil(int motorNumber, unsigned long hex_speed, bool isClockwise, bool setMark){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     unsigned short cmdAddr = (isClockwise) ? CMD_GO_UNTIL_MINUS : CMD_GO_UNTIL_PLUS;
     setCmd(motorNumber, (setMark) ? (cmdAddr | 0x08) : cmdAddr, hex_speed, 22);
 }
-
+//@ release sw
 void L6470SDC::releaseSwitch(int motorNumber, bool isClockwise, bool setMark){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     unsigned short cmdAddr = (isClockwise) ? CMD_RELEASE_SW_MINUS : CMD_RELEASE_SW_PLUS;
     setCmd(motorNumber, (setMark) ? (cmdAddr | 0x08) : cmdAddr, 0, 0);
 }
-
+//@ motor goto zero-position
 void L6470SDC::home(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_GO_HOME, 0, 0);
 }
-
-//zeroはhomeのエイリアス(別名)
+//@ alias:home
 void L6470SDC::zero(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_GO_HOME, 0, 0);
 }
-
+//@ motor goto MARK-position
 void L6470SDC::gotoMark(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_GO_MARK, 0, 0);
 }
-
+//@ reset zero-position
 void L6470SDC::resetHome(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_RESET_POS, 0, 0);
 }
-
-//resetZeroはresetHomeのエイリアス(別名)
+//@ alias:resetHome
 void L6470SDC::resetZero(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_RESET_POS, 0, 0);
 }
-
+//@ motor reset
 void L6470SDC::motorReset(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_RESET_DEVICE, 0, 0);
 }
-
+//@ motor soft-stop
 void L6470SDC::stop(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_SOFT_STOP, 0, 0);
 }
-
+//@ motor hard-stop
 void L6470SDC::stopImmidiate(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_HARD_STOP, 0, 0);
 }
-
+//@ motor HighImpedance
 void L6470SDC::stop_HighImpedance(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_SOFT_HIZ, 0, 0);
 }
-
+//@ motor HighImpedance hard-stop
 void L6470SDC::stopImmidiate_HighImpedance(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return;
     setCmd(motorNumber, CMD_HARD_HIZ, 0, 0);
 }
 
-// calc method ------------------------------------------------------------------------------
+/* ---------------------------------------------------------------------------
+ * COMMAND (Daisy-chain Enqueue)
+ -------------------------------------------------------------------------- */
+//@ enqueue NOP
+int L6470SDC::ENQ_nop(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_NOP;
+    Queue[motorNumber].val = CMD_NOP;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue run command
+int L6470SDC::ENQ_run(int motorNumber, unsigned long hex_speed, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = (isClockwise) ? CMD_RUN_MINUS : CMD_RUN_PLUS;
+    Queue[motorNumber].val = hex_speed;
+    Queue[motorNumber].bitLen = 20;
+    return motorNumber;
+}
+//@ enqueue move command
+int L6470SDC::ENQ_move(int motorNumber, unsigned long stepsCount, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = (isClockwise) ? CMD_ADDSTEP_MINUS : CMD_ADDSTEP_PLUS;
+    Queue[motorNumber].val = stepsCount;
+    Queue[motorNumber].bitLen = 22;
+    return motorNumber;
+}
+//@ enqueue goto(shortest) command
+int L6470SDC::ENQ_goto1(int motorNumber, unsigned long ABSPos){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_GOTO;
+    Queue[motorNumber].val = ABSPos;
+    Queue[motorNumber].bitLen = 22;
+    return motorNumber;
+}
+//@ enqueue goto command
+int L6470SDC::ENQ_goto2(int motorNumber, unsigned long ABSPos, bool isClockwise){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = (isClockwise) ? CMD_GOTO_DIR_MINUS : CMD_GOTO_DIR_PLUS;
+    Queue[motorNumber].val = ABSPos;
+    Queue[motorNumber].bitLen = 22;
+    return motorNumber;
+}
+//@ enqueue goUntil command
+int L6470SDC::ENQ_goUntil(int motorNumber, unsigned long hex_speed, bool isClockwise, bool setMark){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    unsigned short cmdAddr = (isClockwise) ? CMD_GO_UNTIL_MINUS : CMD_GO_UNTIL_PLUS;
+    Queue[motorNumber].addr = (setMark)? (cmdAddr | 0x08) : cmdAddr;
+    Queue[motorNumber].val = hex_speed;
+    Queue[motorNumber].bitLen = 22;
+    return motorNumber;
+}
+//@ enqueue release switch command
+int L6470SDC::ENQ_releaseSwitch(int motorNumber, bool isClockwise, bool setMark){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    unsigned short cmdAddr = (isClockwise) ? CMD_RELEASE_SW_MINUS : CMD_RELEASE_SW_PLUS;
+    Queue[motorNumber].addr = (setMark)? (cmdAddr | 0x08) : cmdAddr;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue goHome command
+int L6470SDC::ENQ_home(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_GO_HOME;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ alias:ENQ_home
+int L6470SDC::ENQ_zero(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_GO_HOME;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue gotoMark command
+int L6470SDC::ENQ_gotoMark(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_GO_MARK;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue reset_pos command
+int L6470SDC::ENQ_resetHome(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_RESET_POS;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ alias:ENQ_resetHome
+int L6470SDC::ENQ_resetZero(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_RESET_POS;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue reset motor command
+int L6470SDC::ENQ_motorReset(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_RESET_DEVICE;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue soft-stop command
+int L6470SDC::ENQ_stop(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_SOFT_STOP;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue hard-stop command
+int L6470SDC::ENQ_stopImmidiate(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_HARD_STOP;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue soft-stop(HIZ) command
+int L6470SDC::ENQ_stop_HighImpedance(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_SOFT_HIZ;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ enqueue hard-stop(HIZ) command
+int L6470SDC::ENQ_stopImmidiate_HighImpedance(int motorNumber){
+    if(motorNumber > motor_count || motorNumber < 1) return -1;
+    Queue[motorNumber].addr = CMD_HARD_HIZ;
+    Queue[motorNumber].val = 0;
+    Queue[motorNumber].bitLen = 0;
+    return motorNumber;
+}
+//@ command queue clear
+void L6470SDC::Qclear(){
+    for(int i=0; i<=motor_count; i++){
+        Queue[i].addr = 0;
+        Queue[i].val = 0;
+        Queue[i].bitLen = -1;
+    }
+}
+//@ queue execute
+int L6470SDC::Qexec(bool finallyClearQueue){
+    int bitLens[motor_count];
+    memset(bitLens, 0, sizeof(int) * motor_count);
+    int maxBitLen = 0;
+
+    //構造体の中のbitLenの最大値を抽出, 計算に使用するので別枠に格納
+    for(int i=0; i<motor_count; i++){
+        bitLens[i] = Queue[i+1].bitLen;
+        if(maxBitLen < bitLens[i]) maxBitLen = bitLens[i];
+    }
+
+    //bitLenの最大値が0未満、つまり構造体に値が入っていないのでここで終わる
+    if(maxBitLen < 0) return -1;
+
+    //コマンド送信
+    CS_ACTIVE;
+    for(int i=0; i<motor_count; i++){
+        spi->write(Queue[i+1].addr);
+#ifdef DEBUG_L6470SDC
+        if(hasSerial) pc->printf("[Queue:Command] Motor-No.%03d, CMD:0x%04X\r\n", i+1, Queue[i+1].addr);
+#endif
+    }
+    CS_INACTIVE;
+
+    //bitLenの最大値が0、つまり送る値がないのでここで終わる
+    if(maxBitLen < 1) return 0;
+
+    //モーター個数分×送信回数分の箱を作り、その中にあらかじめ値を入れ、それを順次送り出す
+    //bitLenが最も長いものから送信回数を求める
+    int maxSend8 = (maxBitLen - 1) >> 3;
+
+    //8bitに区切った場合の区切りの場所を算出
+    int top8bit[motor_count];
+    memset(top8bit, 0, sizeof(int) * motor_count);
+    for(int i=0, send8c=0; i<motor_count; i++){
+        send8c = (bitLens[i] - 1) >> 3;
+        top8bit[i] = bitLens[i] - (send8c << 3);
+    }
+
+    //箱の中に値を入れていく
+    ++maxSend8;
+    unsigned char valBox[motor_count * maxSend8];
+    memset(valBox, 0, sizeof(char) * motor_count * maxSend8);
+    for(int j=0; j<maxSend8; j++){
+        for(int i=0, slide=j*maxSend8; i<motor_count; i++){
+            bitLens[i] -= (j==0)? top8bit[i] : 8;
+            valBox[i+slide] = (bitLens[i]<0)? CMD_NOP : (unsigned char)(Queue[i+1].val >> bitLens[i]);
+        }
+    }
+
+    //値の送出
+    for(int j=0; j<maxSend8; j++){
+        CS_ACTIVE;
+        for(int i=0, slide=0; i<motor_count; i++){
+            slide = i*maxSend8;
+            spi->write(valBox[j+slide]);
+#ifdef DEBUG_L6470SDC
+            if(hasSerial) pc->printf("[Queue:Values]>>>> Motor-No.%03d, VAL[%d]:0x%02X\r\n", i+1, j, valBox[j+slide]);
+#endif
+        }
+        CS_INACTIVE;
+    }
+
+    //キューの値を空に
+    if(finallyClearQueue) Qclear();
+
+    return 1;
+}
+
+/* ---------------------------------------------------------------------------
+ * CALCULATE
+ -------------------------------------------------------------------------- */
 unsigned long L6470SDC::calcSpd(float stepPerSecond){
     stepPerSecond = (stepPerSecond < 0) ? 0 : stepPerSecond;
     //SPEED = ステップ毎秒 * 250ナノ秒 / 2^-28