L6470でステッピングモータを動かす

この記事について

L6470(を使用した既存のモータードライブキット)でステッピングモータを動かす記事です。

この記事は、サンプルコードを拾ってきて、とりあえず動かす(動かした)だけでは少しモヤモヤするという人に向けて書いています。

私もモヤモヤしたので、可能な範囲で調べてこの記事を書いています。そのため、記事内容に収まらない応用方法についてはお答えできないかもしれません。

L6470はバイポーラステッピングモータのドライブICですが、基本的には実装されたキット全体を指してL6470と書いています。ICのみを指すときには、L6470使用IC L6470などと書いています。

随時更新中(2019.11.8)

使ったもの

L6470使用 ステッピングモータードライブキット

秋月電子で購入

f:id:tyokota_0529:20170620034854p:plain:w300

L6470使用 ステッピングモータードライブキット: 組立キット 秋月電子通商-電子部品・ネット通販

バイポーラ ステッピングモーター ST-42BYH1004

秋月電子で購入

f:id:tyokota_0529:20170616191039p:plain:w300

バイポーラ ステッピングモーター ST−42BYH1004: パーツ一般 秋月電子通商-電子部品・ネット通販

モータの主な仕様

項目 詳細
ステータ バイポーラタイプ
相数
基本ステップ角 0.9度±5%
1回転ステップ数 400
絶縁抵抗 100MΩ(500VDC
コイル抵抗 5.0±10%Ω/相
入力定格電圧 5V
定格電流 1.0A/相
静止トルク 4.4kgf・cm
重量 0.34kg
注意 軸を回さない。感電する

配線

配線
A(A相) Black
C(_A相) Green
B(B相) Red
D(_B相) Blue

L6470でステッピングモータを回す

ピンの役割と接続

モータの制御はマイコンとL6470をピンで接続し、SPI通信によってコマンドを送受信することで行われる。 Master(制御する側)とSlave(制御される側)を以下としたときの各デバイスのピンの役割を理解し、正しい対応関係でピン同士を接続する。

  • Master: Arduin UNO R3
  • Slave: L6470 Driver

Adruino側

SPI通信のためのピン

※SSピン以外は変更することができない

ピン番号 名称 役割
D11 MOSI
(Master Out Slave In)
マスタからスレーブへデータを送るライン
D12 MISO
(Master In Slave Out)
スレーブからマスタへデータを送るライン
D13 SCK
(Serial Clock, Output)
データ転送を同期させるためマスタより生成されるクロック信号
D10 SS
(Slave Serect pin, Output)
デジタル信号を渡すことでスレーブを選択する。
LOWが渡されたスレーブはマスタとの通信をおこなう。
HIGHが渡されたときマスタからのデータを無視する。

L6470側

SPI通信のためのピン

ピン番号 名称 分類
5 SDO (SPI Data Out) Logic output
6 CK (SPI Clock) Logic input
7 SDI (SPI Data In) Logic input
8 #CS (SPI Chip Serect, = Slave Srect) Logic input, 負論理

ArduinoとL6470の各ピンを比較すると、以下の対応関係でピンを接続することがわかる。

  • D11 (MOSI) <-> 7 (SDI)
  • D12 (MISO) <-> 5 (SDO)
  • D13 (SCK) <-> 6 (CK)
  • D10 (SS) <-> 8 (#CS)

その他のピン

必要に応じてその他のピンも接続することで、L6470に機能を追加して利用することができる。

ピン番号 名称 分類 役割
1 #BUSY/SYNC Open Drain Output Busy Frag Mode(SYNC_EN bitがLOW(0)のときdefault)
・デフォルトの状態では、コマンド実行中はLOWになる。
・一定速度コマンド、絶対位置指定コマンド、移動コマンドが実行中のとき、ピン出力がLOW
・コマンドが実行されたとき(目標速度、目標座標に到達)、このBUSYピンは解放される。

Synchronization Signal Mode(SYNC_EN bitがHIGH(1)のとき)
・このモードでのステップクロック信号は、SYNC_SELとSTEP_SELパラメータの組み合わせに応じて出力される。
2 FRAG
(Status Frag)
Open Drain Output アラーム発生時にFRAGピンをGNDに接続する。
(内部のオープンドレイントランジスタによる)
3 GND (Ground)
4 EXT-VDD
(External-VDD)
Power ロジック出力ピンの電圧範囲を設定。
VDDpinは内部でVregまたは3.3V電源に接続されていない。
9 STCK
(Step-clock Input)
Logic Input Step-clock mode時に入力された信号によって
モータの動きが定義される。
10 #STBY/#RST
(Stepby and Reset)
Logic Input LOW logic levelでlogicをリセット、デバイスをスタンバイモードに。使わない場合はVDDにつなげておく。

ロジック電源の設定をする

ピンの接続によって信号を送受信する路はつながるが、IC L6470やモータを動かすためには当然電源が必要。モータードライブキットではモータを動かす電源の他に、MCU(Micro Control Unit = ここではIC L6470)を動かすロジック電源が必要である。キットではジャンパピンの挿入によって、MCUへの電源電圧の供給方法を設定することができる。

MCU3.3~5Vの間で動作し、MCUからマイコンへ入力されるデジタル信号の電圧もロジック電源の電圧によって決定される。IC L6470は内部のレギュレータによってモータ電源から3Vの電圧をMCUに回すことができるが、その場合はArduinoに入力するデジタル信号も3Vとなってしまう。Arduino5V駆動であるため、3Vのデジタル信号をArduinoに入力することは好ましくない。

よって、MCUの内部レギュレータは使用せずに、Arduinoの5VピンからEXT-VDDピンに電圧を供給してMCUを駆動させるのが良い。 (下図真ん中の方式)

f:id:tyokota_0529:20170620112724p:plain:w500

SPI通信の設定をする

L6470を使う際には、初めにコマンドを送るためのSPI通信の設定を以下のように記述する。
これらの設定はL6470のSPI通信の仕様に従って決めたものであり、仕様はデータシートで確認できる(データシートの確認については後述)。

void setup(){

        // ... 他の初期化設定 ...

        SPI.begin()
        SPI.setBitOrder( **MSBFIRST** )
        SPI.setDataMode( **SPI_MODE3** )
}

以下では、上の各設定についてそれぞれ説明する。

SPI.begin()

SPIバスを初期化する。 SCK、MOSI、SSの各ピンは出力に設定され、SCKとMOSIはlowに、SSはhighになる。

参考:Arduino 日本語リファレンス

SPI.setBitOrder()

SPI.transfer()という関数で送信する1バイト(8ビット)分の情報を、左端(最上位)と右端(最下位)のどちらから送信するかを決める。

設定には MSBFIRSST と LSBFRIST の2通りがあり、いずれかを選択する。

MSB と LSB

以下の表で示している通り。2進数で表された情報において

  • MSB (Most Significant Bit) = 最上位ビット
  • LSB (Most Significant Bit) = 最下位ビット

を指す。(ここでは8bit=1byte)

7 6 5 4 3 2 1 0
MSB LSB

SPI.setBitOrder() の記述方法

  • SPI.setBitOrder( MSBFIRST )
    • 最上位ビット(MSB)から順にデータを送信する
    • 7→6→5→4→3→2→1→0
  • SPI.setBitOrder( LSBFIRST )
    • 最下位ビット(LSB)から順にデータを送信する
    • 0→1→2→3→4→5→6→7

SPI.setDataMode()

信号におけるクロック位相(clock phase)とクロック極性(clock polarity)という2つの要素を決定する。

  • クロック位相:シフトされたデータを読み取るタイミング
    • クロック信号の 立ち下がりエッジ or 立ち上がりエッジ
  • クロック極性:アイドリング(待機)状態を示すクロック信号の状態
    • HIGH状態 or LOW状態

SPI.setDataMode()の記述方法

  • 例)SPI.getDataMode( SPI_MODE3 )
    • クロック信号の立ち上がりで送信(シフト)されたデータの読み取りを行う
    • また、クロック信号がHIGHの間をアイドリング状態とする
SPI_MODE一覧
立ち下がりエッジで読み取り 立ち上がりエッジで読み取り
LOW状態でアイドリング SPI_MODE0 SPI_MODE1
HIGH状態でアイドリング SPI_MODE2 SPI_MODE3

SPIの設定まとめ

SPI.setBitOrder()とSPI.setDataMode()の設定の組み合わせは以下の通り。

f:id:tyokota_0529:20170622050557p:plain:w900

(図はLinkより引用)

L6470のSPI通信仕様

L6470のSPI通信の仕様は、データシートから確認することができる(8. Serial Interface)。

(追記予定)

コマンドの送信方法

L6470は、SPI通信で内部のレジスタにコマンドをシフト(送信)することで制御することができる。そのとき、

  • MSBファーストでコマンドを8ビットずつに区切り、SPI.transfer() で送信する
  • 8ビットごとに、CS(SS)のHIGH->LOWを行う

ことが必要であり、以下のようなコマンド送信用の関数を用意すると良い。
モータ制御のために送信するコマンドについてはこの次に記述する。

void L6470_send( unsigned char add_or_val ){
        while( !digitalRead(PIN_BUSY) ){ 
        // BUSY(LOW状態)が解除されるまで待機する
        // L6470のBUSY/SYNCピンをArduinoに接続しておく必要がある
        }
        digitalWrite( PIN_SPI_SS, LOW);
        SPI.transfer( add_or_val ); //1バイト(8ビット)のデータを送信
        digitalWrite( PIN_SPI_SS, HIGH);
}

void L6470_transfer( int add, int bytes, long val ){
        // 内部レジスタ長が最大22ビットなので、3バイト(24ビット)のデータまで扱える配列を用意する
        int data[3];
        // 送信する値を8ビットごとに分けて配列に格納する
        for( int i = 0; i < bytes; i++) {
                // 0xffと論理積を取ることで、後ろから8ビット分のみを格納
                data[i] = val & 0xff;
                // 右に8ビットシフトすることで、次には配列に格納した部分をのぞいた値を扱う
                val = val >> 8;
        }
 
        // 送信バイト数に応じて、MSBファーストになるよう配列の後ろの要素から送信する
        if ( bytes == 3 ) {
                // はじめにレジスタを指定するためにアドレスを送信するので、一度に最大32ビット送信する       
                L6470_send( add );
                L6470_send( data[2] ) ;
                L6470_send( data[1] ) ;
                L6470_send( data[0] ) ;
        }
        else if ( bytes == 2 ) {
                L6470_send( add );
                L6470_send( data[1] ) ;
                L6470_send( data[0] ) ;
        }
        else if ( bytes == 1 ) {
                L6470_send( add );
                L6470_send( data[0] ) ;
        }

        // 3バイト以上送ろうとしたら回避する処理をちゃんと書いた方が良いと思う…
}

制御のパラメータを設定する

L6470には、モータの制御に関するパラメータを設定するための内部レジスタ(記憶回路)が多く存在する。レジスタのアドレスを指定したのちに値を送信することで、パラメータを設定することができる。

  • レジスタは可変長、22ビットや4ビット等がある。各レジスタの内部アドレスは0x01~0x19が割り当てられている
  • レジスタのパラメータには初期設定(デフォルト値)が決まっており、電源投入直後にはデフォルト値が設定される
  • 大体はデフォルトの値で動作する。変更が必要な場合もあり
  • レジスタの値を設定した後に、回転・ストップ等の指示を送ってモータを制御する

f:id:tyokota_0529:20170623040712p:plain

SetParam() によるレジスタの値の設定

モータの動作を指示する

Run() による定速回転

コマンド:Run( DIR, Spd )

  • 回転方向DIR(Direction)と、目標速度Spd(Speed)を指定してステッピングモータを定速回転させる

  • 32ビットの情報を4回に分けて送信する

f:id:tyokota_0529:20170630200712p:plain

初めの8ビット

  • 定速回転のコマンド+回転方向の指定
Command binary code
7 6 5 4 3 2 1 0
0 1 0 1 0 0 0 DIR
16進数
定速正回転の場合(DIR = 1) 定速負回転の場合(DIR = 0)
2進数 01010001 01010000
16進数 0x51 0x50

残りの24ビット

  • 回転速度の指定

    • Speedレジスタ(現在のモータ速度を格納しているレジスタ)内のデータと同じ表現形式

    • 実際にはMAX_SPEEDレジスタの値より小さく、MIN_SPEEDレジスタより大きい値である必要がある

      • これが満たされない場合、MAX(MIN)_SPEEDの値で実行される
    • 目標速度に達するまでBUSY状態

モータ速度の表現方法
  • Speed,MAX_SPEED,MIN_SPEEDレジスタでほぼ同じ表現が用いられる

  • レジスタにはステップ/動作クロックで表された値が格納されている

  • 1秒あたりのステップ数(ステップ/秒)には、それぞれ以下の式で変換される

Speedレジスタ(20ビット)

\rm\large\displaystyle[ステップ/秒]=\frac{SPEED\times2^{-28}}{動作クロック}

  • 初期値は0(0ステップ/動作クロック,0ステップ/秒)

  • 動作クロックは250ns

MAX_SPEEDレジスタ(10ビット)

\rm\large\displaystyle[ステップ/秒]=\frac{SPEED\times2^{-18}}{動作クロック}

  • 初期値は041

  • 動作クロックは250ns

# ステップ/動作クロックからステップ/秒への変換

\rm\displaystyle 041 → 65(step/tick)

  • \rm\displaystyle Max_{init} [ step/s ] = \frac{ 65 \times 2^{-18}}{250 \times 10^{-9}}

  • \rm\displaystyle Max_{init} = 991.82 [ step/s ]

MAX_SPEEDレジスタの最大値
  • 初期値041は7ビット

  • 10ビットの最大値1111111111は0x3FF, 1023

  • \rm\displaystyle Max_{max} [ step/s ] = \frac{ 1023 \times 2^{-18}}{250 \times 10^{-9}}

  • \rm\displaystyle Max_{max} = 155609.74 [ step/s ]

MIN_SPEEDレジスタ(13ビット)

\rm\large\displaystyle[ステップ/秒]=\frac{SPEED\times2^{-24}}{動作クロック}

  • 初期値は000(0ステップ/動作クロック、0ステップ/秒)

  • 動作クロックは250ns

バイスの初期化

  • Arduinoのvoid setup()内で、モータ駆動する前に以下の内容を実行する。
void L6470_resetDevice(){
   // nop命令
   L6470_send(0x00);
   L6470_send(0x00);        
   L6470_send(0x00);        
   L6470_send(0x00);
  // ResetDevice
   L6470_send(0xc0);
}
  • nop命令を4回(4byte分)送った後に、デバイスをリセットする(ResetDeviceコマンドを送る)。

    • これは、L6470に一度に送る情報が最大で4byteであるため
  • nop命令を4回送ることで、前のコマンドを確実に終了させてからデバイスをリセットする

ResetDevice (Application commands)

  • L6470デバイスを電源投入後の状態にリセットする

    • パラメータの初期化等

Command binary code

7 6 5 4 3 2 1 0
1 1 0 0 0 0 0 0
16進数
  • 0xc0

    • SPI.transfer(0xc0)で初期化

NOP (Application commands)

  • Nothing is performed

    • 何もしない

Command binary code

7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
16進数
  • 0x00

    • SPI.transfer(0x00)で何もしない命令

参考資料

SPI通信

L6470

(L6480の動かし方 [メモ][開発] ステッピングモータードライバL6470とL6480: ヤメ記者SEの徒然なるままに…)