Xiao ESP32S3 モータドライバTC78H653FTG駆動

2024.1.28 Coskx Lab  

1 はじめに

Xiao ESP32S3で小型モータを制御します。


モータドライバIC TC78H653FTGを使用して,小型ブラシDCモータの130モータを駆動します。モータ駆動電圧は3Vです。
TC78H653FTGはDCモータを対象と考えた場合,2つのHブリッジ回路を持っていて,2つのモータを別々に駆動できるSMALLモードと2つのHブリッジ回路を並列にして1つのモータを駆動するLARGEモードがあります。
なお電流監視抵抗付加による電流制限機能は使いません。

参考 モータドライバIC TC78H653FTG(東芝デバイス&ストレージ)
データシート https://toshiba.semicon-storage.com/info/docget.jsp?did=63588&prodName=TC78H653FTG
アプリケーションノート https://toshiba.semicon-storage.com/info/docget.jsp?did=70283&prodName=TC78H653FTG

参考 モータドライバIC TC78H653FTG 入出力ファンクション
   LARGE = H or L, MODE = L, STBY = H(論理レベル) で使用する
IN1IN2OUT1(OUT2)OUT3(OUT4)モード
LLOFF(Hi-Z)OFF(Hi-Z)ストップ
HLHL正転
LHLH逆転
HHLLブレーキ

参考 モータドライバIC TC78H653FTG 動作範囲
項目最小標準最大
モータ電源電圧1.8V3.0V7.5V
モータ出力電流
small mode
2A
モータ出力電流
small mode
Peak 10ms
2.5A
モータ出力電流
large mode
4A
モータ出力電流
large mode
Peak 10ms
5A
ロジックHレベル2.0V(Vm=5.0のとき)5.5V
ロジックLレベル-0.3V0.5V
ロジック最大周波数500kHz

参考 モータドライバIC TC78H653FTG基板実装(秋月電子販売)
https://akizukidenshi.com/catalog/g/gK-14746/

回路図でわかるように,秋月電子の基板上で,論理系のGNDとモータ駆動系のGNDが接続されています。

2 使用環境

3 実験用配線

2つのHブリッジ回路を持っていて,2つのモータを別々に駆動できるSMALLモードと2つのHブリッジ回路を並列にして1つのモータを駆動するLARGEモードがあります。
配線はSMALLモード・LARGEモードによって異なります。
1つのモータを駆動することを考え,SMALLモード・LARGEモードを試します。
モータドライバIC TC78H653FTG のIN1,IN2には,Xiao ESP32S3 のD0,D1を接続します。
万が一,電流保護回路が働いたときには,STBY信号も使うので,Xiao ESP32S3 のD3につないでおきます。

○SMALLモード

○LARGEモード


実際の配線(smallmode)は次のようになりました。


4 モータ駆動デモプログラム

モータ駆動では,通電状態と絶縁状態を繰り返す駆動をしています。
PWMモジュール(PWMチャンネル)は2つ,PWM出力用のGPIOピンは2つ必要になります。
設定値は次の通りです。
 PWM生成に使用するビット数: 8bit
 PWM周波数:1000Hz
 使用するPWMモジュール(PWMチャンネル):1,2
 PWM出力に使用するPIN番号:D0,D1
 STBY信号:D3

SMALLモード・LARGEモードともに同じプログラムで動作します。
2秒間隔でPWMデューティ比を-100%から100%まで10%刻みで変化させます。(正のデューティ比は正転,負のデューティ比は逆転を表します。)

プログラムでは,モータ駆動クラスを利用しています。


  PWMの動作テスト用プログラム本体

//** motordrivetest.ino **//

#include "MotorDriverESP32.h"

//DCブラシモータを1つ正転逆転駆動するテスト
//class MotorDriver 利用

//1つのモータを正逆駆動するためには,正転用と逆転用の2つのPWM信号が必要です。
//そのため,2つのPWMモジュール(PWMチャンネル)と2つのピンを割り当てます.
//ピン番号はGPIOピン番号ではなく,ESP32のピン番号で0ではなく1から始まります
//正転(Forward) PWMチャンネル:1 GPIOピン:1
//逆転(Reverse) PWMチャンネル:2 GPIOピン:2

const uint8_t nBits_forPWM = 8; // PWMに使用するビット数 n=1~16[bit]
const double PWM_Frequency = 1000.0;   // PWM周波数 Maxfreq=80000000.0/2^n[Hz]

const uint8_t PWM_F_CH = 1;  // PWMチャンネル Forward
const uint8_t PWM_R_CH = 2;  // PWMチャンネル Reverse

const uint8_t PWM_F_PIN = D0; // PWM出力に使用するGPIO PIN番号 Forward
const uint8_t PWM_R_PIN = D1; // PWM出力に使用するGPIO PIN番号 Reverse

const uint8_t Standby_PIN = D3; //standbyに使用するGPIO PIN番号

int Led_PIN = LED_BUILTIN;
int LEV_Value = 1;

const double Motor_Drive_dutyRatios[] = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
      0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
const int nRatios = sizeof(Motor_Drive_dutyRatios)/sizeof(double);
//Motor_Drive_dutyRatios[]はモータ指令デューティー比の候補(-1.0 <= dutyRatio <= 1.0)
//モータ指令値:正の時は正転側のデューティ比,負のときは逆転側のデューティ比を表す

int dutyRatioIndex = (nRatios>>1); //モータ指令値番号 初期値
double dutyRatio_Value = Motor_Drive_dutyRatios[dutyRatioIndex];
int naverage = 30;
int value;
int step = 1;

MotorDriverESP32 mMotorDriver; //class MotorDriver のインスタンス

void setup() {
  Serial.begin(115200);
  //while(!Serial);
  Serial.println("\n\n\n*** Single Motor Drive Test ***");

  mMotorDriver.setPins(PWM_F_PIN, PWM_R_PIN, PWM_F_CH, PWM_R_CH);
  mMotorDriver.setPWM(nBits_forPWM, PWM_Frequency);

  Serial.printf("duty ratio = %.4f\n",dutyRatio_Value);
  value = mMotorDriver.driveMotor(dutyRatio_Value);
  Serial.printf("value = %5d\n",value);

  pinMode(Standby_PIN, OUTPUT);
  digitalWrite(Standby_PIN, HIGH);
  pinMode(Led_PIN, OUTPUT);
}

void loop() {
  digitalWrite(Led_PIN, LEV_Value = 1 - LEV_Value);
  dutyRatioIndex += step;
  if (nRatios-1 <= dutyRatioIndex) step = -1;
  if (dutyRatioIndex < 1) step = 1;
  dutyRatio_Value = Motor_Drive_dutyRatios[dutyRatioIndex];
  value = mMotorDriver.driveMotor(dutyRatio_Value);
  Serial.printf("duty ratio = %.4f value = %d\n",dutyRatio_Value, value);
  delay(2000);
}

  モータ駆動クラスのヘッダーファイル

//** MotorDriverESP32.h **//

#ifndef MotorDriverESP32_h
#define MotorDriverESP32_h

class MotorDriverESP32 {
  public:
    void setPins(int forwardPin, int reversePin, int forwardChannel, int reverseChannel);
    void setPWM(int nBits_forPWM, double PWM_Frequency);
    int driveMotor(double dutyRatio); // -1.0 <= dutyRatio <= 1.0
    void setHighImpedance();
  private:
    int fwdPin, rvsPin;
    int fwdChl, rvsChl;
    int pwmMaxValue;
};
#endif

モータ駆動クラスのCPPファイル

Arduino ESP32 coreのバージョンが2.Xから3.0になり,
ledcSetup(), ledcAttachPin() は廃止され,ledcAttachChannel()を使うことになりました。
https://github.com/espressif/arduino-esp32/blob/master/docs/en/migration_guides/2.x_to_3.0.rst#id4

//** MotorDriverESP32.cpp **//

#include <Arduino.h>

#include "MotorDriverESP32.h"

/*
  XIAO ESP32S3 pin assignment
  1 D0(A0)
  2 D1(A1)
  3 D2(A2)
  4 D3(A3)
  5 D4(A4)
  6 D5(A5)
  7 D8(A8)
  8 D9(A9)
  9 D10(A10)
*/

void MotorDriverESP32::setPins(int forwardPin, int reversePin, int forwardChannel, int reverseChannel) {
  fwdPin = forwardPin; //GPIO PIN NUMBER
  rvsPin = reversePin; //GPIO PIN NUMBER
  fwdChl = forwardChannel;
  rvsChl = reverseChannel;
  pinMode(fwdPin, OUTPUT); //出力したいピンを出力用途に設定 ピン番号はA0,A1,... or D0,D1,...
  pinMode(rvsPin, OUTPUT); //出力したいピンを出力用途に設定 ピン番号はA0,A1,... or D0,D1,...
}

void MotorDriverESP32::setPWM(int nBits_forPWM, double PWM_Frequency) {
  pwmMaxValue = 1<<nBits_forPWM;
  /*
  // 指定PWMチャンネルにPWM周波数と使用ビット数を設定
  ledcSetup(fwdChl, PWM_Frequency, nBits_forPWM);
  ledcSetup(rvsChl, PWM_Frequency, nBits_forPWM);
  // 出力したいピンにPWMチャンネル出力をつなげる設定
  ledcAttachPin(fwdPin, fwdChl);
  ledcAttachPin(rvsPin, rvsChl);
  from versions 2.X (based on ESP-IDF 4.4) to version 3.0 (based on ESP-IDF 5.1) of the Arduino ESP32 core
  への移行で次のように変更された
  https://github.com/espressif/arduino-esp32/blob/master/docs/en/migration_guides/2.x_to_3.0.rst#id4
  */
  ledcAttachChannel(fwdPin, PWM_Frequency, nBits_forPWM, fwdChl);
  ledcAttachChannel(rvsPin, PWM_Frequency, nBits_forPWM, rvsChl);
}

//Slow decay mode での駆動
//モータ指令値が正のときはPWM_F_PINに デューティfullのPWMを出力,
//                        PWM_R_PINに full - デューティのPWMを出力
//モータ指令値が負のときはPWM_R_PINに デューティfullのPWMを出力,
//                        PWM_F_PINに full + デューティのPWMを出力
//デバッグのためにdrivevalueを返す
int MotorDriverESP32::driveMotor(double dutyratio) {
  int drivevalue = (int)(pwmMaxValue * dutyratio);
  if (drivevalue == 0) {
    ledcWrite(fwdChl, pwmMaxValue);
    ledcWrite(rvsChl, pwmMaxValue);
  } else if (0<drivevalue) {
    ledcWrite(fwdChl, pwmMaxValue);
    ledcWrite(rvsChl, pwmMaxValue - drivevalue);
  } else { //drivevalue<0
    ledcWrite(fwdChl, pwmMaxValue + drivevalue);
    ledcWrite(rvsChl, pwmMaxValue);
  }
  return drivevalue;
}

void MotorDriverESP32::setHighImpedance() {
    ledcWrite(fwdChl, 0);
    ledcWrite(rvsChl, 0);
}

5 駆動信号の様子

オシロスコープのCh1はIN1,Ch2はIN2の信号を表しています。

(1) 正転
デューティ比25%を与えて正転駆動時のIN1(D0),IN2(D1)の信号は次のようになっています。
IN1=HでIN2=Lの区間が正転駆動区間で,IN1=IN2=Hの区間はブレーキ区間になります。


(2) 逆転
デューティ比-25%を与えて逆転駆動時のIN1(D0),IN2(D1)の信号は次のようになっています。
IN1=LでIN2=Hの区間が逆転駆動区間で,IN1=IN2=Hの区間はブレーキ区間になります。



6 実行の様子

モータ駆動用の電源は定電圧電源装置を用い3.0Vを供給しました。 予定通り,2秒ごとに10%ずつのデューティ比変化で130モータを駆動することが出来ました。
動画では,Xiao ESP32S3のLEDが2秒ごとにON-OFFし,それに合わせてモータ駆動PWM信号のデューティ比が10%ずつ変化しています。10%のデューティ比でも動作していることがわかります。




7 まとめ

Xiao ESP32S3およびモータドライバTC78H653FTGのsmallモードによるブラシDCモータ駆動テストを行ないました。
ここではPWM周波数1000Hzで駆動しましたが,10000Hz,20000Hzでも同様の動作は確認できています。(1000Hzですと電磁音が耳障りです。)
なお,Largeモードでも同様の結果が得られています。

重要
「5 駆動信号の様子」を見てわかるように,使用したプログラムではPWMモータ駆動方式が「駆動 ー ブレーキ」の繰り返しを採用しています。 「駆動 ー ストップ」の繰り返しの方式でも駆動出来ますが,低いデューティ比での駆動が不安定になります。

使用する130モータにはコンデンサを付けて,ノイズに対策をする必要があります。これがないと,ノイズの影響で電流制限安全回路が働いてしまうことが多く,STBY信号にH→L→Hを与えるか電源ON→OFF→ONをしないと復旧しません。