おやじ のすべての投稿

IOT(?)な日常を目指して、学習しています。

Raspberry Pi Pico でL6480ステッピングモータードライバーを使う

概要

 ストロベリー・リナックス社で販売されているL6480ドライバーを使ってみました。インターネット上で使い方などあまり見つけることが出来なかったので、忘備録として概要を残しておきます。
 ・L6480 大電流ステッピングモータ ドライバー
 ・57mm 大型ステッピングモータ(ST-57BYG076-3004D)

 発熱・モーター出力等も大きくなりますので、参考にされる場合は安全面等に注意して自己責任でお願い致します。

接続

 少し前にRaspberryPiPicoとL6470の接続について書きましたが、そこに下図の通りL6480を追加しました。改めて見るとL6470と同じ様なピンの配置になっていると判りました。
 L6480の場合は、Pin10(~STBY)を多く接続しています。~STBY信号を入力しないと動作しない様に理解しています。

テストプログラム

 テストプログラムです。L6470,L6480 を使って2つのモータを動かしています。原点センサー等をつけていないので、しっかり確認できていませんが、原点設定、位置決め等も出来そうです。

#include <SPI.h>

// ピン定義。
#define PIN_SPI_MOSI 19               // ■SPI TX
#define PIN_SPI_SCK 18                // ■SPI SCK
#define PIN_SPI_MISO 16               // ■SPI RX

#define L6470_SPI_SS 17               // ▽L6470 デバイス選択
#define L6470_BUSY 20                 // ▽L6470 BUSY

#define L6480_STBY 26                 // ▲L6480 STAND BY
#define L6480_SPI_SS 27               // ▲L6480 デバイス選択
#define L6480_BUSY 28                 // ▲L6480 BUSY

#define PIN_LMT_ORG 21                // 原点SW
#define PIN_LMT_END 22                // 端部SW

#define PIN_DRV_LED 14                // LED1
#define PIN_LMT_LED 15                // LED2

int spi_dvs = 0;
int val_org = 0;
int val_end = 0;
int val_bsy = 0;
int sts_origin=0;                     // 原点復帰ステータス


// 起動時実行
void setup()
{
  Serial.begin(9600);
  delay(1000);

  pinMode(PIN_SPI_MOSI, OUTPUT);      // SPI送信
  pinMode(PIN_SPI_MISO, INPUT);       // SPI受信
  pinMode(PIN_SPI_SCK, OUTPUT);       // SPIクロック
  
  pinMode(L6470_SPI_SS, OUTPUT);      // L6480 SPIスレーブセレクト
  pinMode(L6470_BUSY, INPUT);         // L6470 BUSY

  pinMode(L6480_STBY, OUTPUT);        // L6480 STAND BY
  pinMode(L6480_SPI_SS, OUTPUT);      // L6480 SPIスレーブセレクト
  pinMode(L6480_BUSY, INPUT);         // L6480 BUSY
  
  pinMode(PIN_LMT_ORG, INPUT_PULLUP); // 原点SW入力
  pinMode(PIN_LMT_END, INPUT_PULLUP); // 駆動端SW入力
  
  pinMode(PIN_LMT_LED, OUTPUT);       // LED出力(リミット入力有)
  pinMode(PIN_DRV_LED, OUTPUT);       // LED出力(L6470-BUSY)

  digitalWrite(L6480_STBY, HIGH);     // L6480 STAND BY(PICO → L6480 DRIVER)
  delay(1000);
   
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(MSBFIRST);
  
  spi_dvs_disenable();                          // SPIデバイス選択解除

  spi_dvs = 0;
  L64X0_rst_device();                           // L6470・L6480リセット
  L64X0_set_parameter();                        // L6470・L6480パラメータ設定(設定後、spi_dvsは元に戻す)

  L6480_MOVE_TEST_1();
  spi_dvs = 1;
}

// メインループ
void loop(){
  val_org = !digitalRead(PIN_LMT_ORG);          // 入力ピンを読む
  val_end = !digitalRead(PIN_LMT_END);          // 入力ピンを読む
  val_bsy = digitalRead(L6470_BUSY);
  
  digitalWrite(PIN_LMT_LED, val_org | val_end); // LEDのピンを読み取った値に変更
  digitalWrite(PIN_DRV_LED, val_bsy);           // LEDのピンを読み取った値に変更

  if (sts_origin==0){
    // 原点復帰処理 400(step/rot)→3200(step/rot) ※マイクロステップ  ※減速
    get_origin_L6470();                         // L6470原点復帰
    sts_origin = 1;

    spi_dvs = 2;
    L6480_MOVE_TEST_2();
    
    spi_dvs = 1;
  }
}


// L6480 デモ2
void L6480_MOVE_TEST_2(){
  int dvs_tmp = spi_dvs ;
  spi_dvs = 2;  

  L64X0_data_transfer(0x70,0,0);                // 原点移動
  L64X0_NOT_BUSY(200);

  L64X0_data_transfer(0x60,3,32000);            // 絶対位置移動            
  L64X0_NOT_BUSY(1000);
  
  L64X0_data_transfer(0x60,3,0);                // 絶対位置移動(原点)
  L64X0_NOT_BUSY(500);

  spi_dvs = dvs_tmp;   
}


// L6480 デモ1
void L6480_MOVE_TEST_1(){
  int dvs_tmp = spi_dvs ;
  spi_dvs = 2;  
  
  L64X0_data_transfer(0x51,3,8000);             // 反-原点方向(右)中速移動
  DELAY_CHKECKING_INP( 3000 );
    
  L64X0_data_transfer(0xb0,0,0);                // 回転停止(トルク保持)
  L64X0_NOT_BUSY( 3000 );

  L64X0_data_transfer(0x50,3,9000);             // 原点方向(右)中速移動
  DELAY_CHKECKING_INP( 3000 );
    
  L64X0_data_transfer(0xb0,0,0);                // 回転停止(トルク保持)
  L64X0_NOT_BUSY( 3000 );

  L64X0_data_transfer(0xd8,0,0);                // 原点情報初期化
  L64X0_NOT_BUSY(500);

  L64X0_data_transfer(0x60,3,9600);             // 200X16=3200(pls/rot) 3200X3(rot)=9600
  L64X0_NOT_BUSY(200);

  spi_dvs = dvs_tmp;   
}


// L6470 原点復帰
void get_origin_L6470(){
  int dvs_tmp = spi_dvs ;

  spi_dvs = 1;  
  if(!digitalRead(PIN_LMT_ORG)){
    L64X0_data_transfer(0x51,3,8000);           // 反-原点方向(右)中速移動
    DELAY_CHKECKING_INP( 100 );
    
    while(!digitalRead( PIN_LMT_ORG )){ }
    DELAY_CHKECKING_INP( 1000 );
    L64X0_data_transfer(0xb0,0,0);              // 回転停止(トルク保持)
    L64X0_NOT_BUSY(500);
  }
  
  L64X0_data_transfer(0x50,3,8000);             // 原点方向(左)中速移動
  while(digitalRead( PIN_LMT_ORG )){} 
  L64X0_data_transfer(0xb0,0,0);                // 回転停止(トルク保持)
  L64X0_NOT_BUSY(500);

  L64X0_data_transfer(0x51,3,500);              // 反-原点方向(右)低速移動
  DELAY_CHKECKING_INP( 50 );
  while(!digitalRead( PIN_LMT_ORG )){}

  L64X0_data_transfer(0xb0,0,0);                // 回転停止(トルク保持)
  L64X0_NOT_BUSY(500);

  L64X0_data_transfer(0x41,3,600);              // 反-原点方向(右)長さ指定移動
  L64X0_NOT_BUSY(100);
  
  L64X0_data_transfer(0xd8,0,0);                // 原点情報初期化
  L64X0_NOT_BUSY(100);

  spi_dvs = dvs_tmp;
}

// ■■■【以下、共通】■■■■■■■■■■■■■■■■
// L64X0データ送信(BUSY解除待機)
void L64X0_data_send(unsigned char add_or_val){
  if( spi_dvs == 0 ){ while(!digitalRead(L6470_BUSY) || !digitalRead(L6480_BUSY)){} }
  if( spi_dvs == 1 ){ while(!digitalRead(L6470_BUSY)){} }
  if( spi_dvs == 2 ){ while(!digitalRead(L6480_BUSY)){} }

  spi_dvs_enable();
  SPI.transfer(add_or_val);              // アドレスもしくはデータ送信。
  spi_dvs_disenable();
}

// BUSY解除待機
void L64X0_NOT_BUSY(long time){
  int cnt_brk=0;
  while(1){ 
    chk_sw_input();
    if( spi_dvs == 0 ){
      if(digitalRead(L6470_BUSY) && digitalRead(L6480_BUSY)){cnt_brk++;}else{cnt_brk=0;} 
    }else if( spi_dvs == 1 ){ 
      if(digitalRead(L6470_BUSY)){cnt_brk++;}else{cnt_brk=0;} 
    } else if( spi_dvs == 2 ){
      if(digitalRead(L6480_BUSY)){cnt_brk++;}else{cnt_brk=0;} 
    }else{ cnt_brk++; }
    if(cnt_brk>20){ break; }
  }

  if(time > 0){ DELAY_CHKECKING_INP( time ); }
}

// 指定時間待機(対象入力監視:入力による処理分岐なし)
void DELAY_CHKECKING_INP(unsigned long time ){
  // BUSY解除待機
  unsigned long tm_bgn = millis();
  unsigned long tm_now = millis();
  unsigned long tm_dif = tm_now - tm_bgn ; 

  while( tm_dif < time ){
    chk_sw_input();
    tm_now = millis();
    tm_dif = tm_now - tm_bgn ; 
  }
}

// 対象SW入力確認・LED出力
void chk_sw_input(){
  val_bsy = digitalRead(L6470_BUSY);
  val_org = !digitalRead(PIN_LMT_ORG);
  val_end = !digitalRead(PIN_LMT_END);
  digitalWrite(PIN_DRV_LED, val_bsy);             // LEDのピンを読み取った値に変更
  digitalWrite(PIN_LMT_LED, val_org | val_end );  // LEDのピンを読み取った値に変更
}

// L64X0送信データ加工
void L64X0_data_transfer(int add,int bytes,long val){
  int data[3];
  L64X0_data_send(add);
  for(int i=0;i<=bytes-1;i++){
    data[i] = val & 0xff;  
    val = val >> 8;
  }
  
  if(bytes==3){ L64X0_data_send(data[2]); }
  if(bytes>=2){ L64X0_data_send(data[1]); } 
  if(bytes>=1){ L64X0_data_send(data[0]); }  
}

// L6470 / L6480リセット
void L64X0_rst_device(){
  L64X0_data_send_u(0x00);      //nop命令
  L64X0_data_send_u(0x00);
  L64X0_data_send_u(0x00);
  L64X0_data_send_u(0x00);
  L64X0_data_send_u(0xc0);
}

// L6470・L6480データ送信(BUSY状態関係なし)
void L64X0_data_send_u(unsigned char add_or_val){
  spi_dvs_enable();
  SPI.transfer( add_or_val );                 // アドレスもしくはデータ送信。
  spi_dvs_disenable();
}

// SPIデバイス選択
void spi_dvs_enable(){
  if(spi_dvs==1){
    digitalWrite( L6470_SPI_SS , LOW );       // L6470 ~SS有効化 
    digitalWrite( L6480_SPI_SS , HIGH );      // L6480 ~SS無効化
  }else if(spi_dvs==2){
    digitalWrite( L6470_SPI_SS , HIGH );      // L6470 ~SS無効化  
    digitalWrite( L6480_SPI_SS , LOW );       // L6480 ~SS有効化  
  }else{
    digitalWrite( L6470_SPI_SS , LOW );       // L6470 ~SS有効化 
    digitalWrite( L6480_SPI_SS , LOW );       // L6480 ~SS有効化  
  }
}

// SPIデバイス選択解除
void spi_dvs_disenable(){
  digitalWrite( L6470_SPI_SS , HIGH );        // L6470 ~SS無効化 
  digitalWrite( L6480_SPI_SS , HIGH );        // L6480 ~SS無効化
}

// 初期設定
void L64X0_set_parameter(){
  int dvs_tmp = spi_dvs ;

  // ■ DVS1(L6470) ■
  spi_dvs = 1;
  L64X0_data_transfer(0x05,2,0x0e);   // 加速係数(初期値:0x08A)(12bit) 
  L64X0_data_transfer(0x06,2,0x0e);   // 減速係数(初期値:0x08A)(12bit)  
  L64X0_data_transfer(0x07,2,0x0e);   // 最大速度(初期値:0x041)(10bit)
  L64X0_data_transfer(0x08,2,0x01);   // 最小速度(初期値:0x000)(13bit) 
  L64X0_data_transfer(0x09,1,0x29);   // 停止時励磁電圧(初期値:0x29)(8bit)
  L64X0_data_transfer(0x0a,1,0x50);   // 定速回転時励磁電圧(初期値:0x29)(8bit)
  L64X0_data_transfer(0x0b,1,0x50);   // 加速時励磁電圧(初期値:0x29)(8bit)
  L64X0_data_transfer(0x0c,1,0x50);   // 減速時励磁電圧(初期値:0x29)(8bit)
  L64X0_data_transfer(0x15,2,0x3ff);  // μステップ→フルステップ切替点速度(初期値:0x27)(10bit)
  L64X0_data_transfer(0x16,1,0x03);   // マイクロステップ設定:0x03→1/8

  // ■ DVS2(L6480) ■
  spi_dvs = 2;
  L64X0_data_transfer(0x05,2,0x06);   // 加速係数(初期値:0x08A)(12bit)
  L64X0_data_transfer(0x06,2,0x06);   // 減速係数(初期値:0x08A)(12bit)   
  L64X0_data_transfer(0x07,2,0x15);   // 最大速度(初期値:0x041)(10bit)
  L64X0_data_transfer(0x08,2,0x01);   // 最小速度(初期値:0x000)(12bit) 

  L64X0_data_transfer(0x09,1,0x25);   // 停止時励磁電圧(初期値:0x29)(8bit) ※停止時発熱するので大きくしない。  
  L64X0_data_transfer(0x0a,1,0xD5);   // 定速回転時励磁電圧(初期値:0x29)(8bit)   
  L64X0_data_transfer(0x0b,1,0xD5);   // 加速時励磁電圧(初期値:0x29)(8bit)   
  L64X0_data_transfer(0x0c,1,0xD5);   // 減速時励磁電圧(初期値:0x29)(8bit)
 
  L64X0_data_transfer(0x0d,2,0x05);   // Intersect speed(初期値:0x0408)(14bit)
  L64X0_data_transfer(0x0e,1,0x04);   // Start slope(初期値:0x19)(8bit)
  L64X0_data_transfer(0x0f,1,0x04);   // Acceleration final slope(初期値:0x29)(8bit)
  L64X0_data_transfer(0x10,1,0x04);   // Deceleration final slope(初期値:0x29)(8bit)

  L64X0_data_transfer(0x13,1,0x0F);   // OCD threshold(初期値:0x08)(5bit)
  L64X0_data_transfer(0x14,1,0x7F);   // STALL threshold(初期値:0x08)(5bit)

  L64X0_data_transfer(0x15,2,0xff);   // μステップ→フルステップ切替点速度(初期値:0x27)(10bit) 
  L64X0_data_transfer(0x16,1,0x04);   // マイクロステップ設定:0x04→1/16, 0x05→1/32
  L64X0_data_transfer(0x17,1,0xFF);   // アラーム有効化(初期値:0xFF)(8bit) 
  L64X0_data_transfer(0x1A,2,0x1E01); // 環境設定(初期値:0x2C88)(16bit) 

  spi_dvs = dvs_tmp;                  // 通信デバイスを戻す
}

まとめ

 操作方法を理解出来ていないのですが、ArduinoIDEからPicoに書き込む操作に頻繁に戸惑っています。
 一方、L6480設定には、難儀しましたが、何となく使えそうな感覚を持つことが出来ました。