DRV2605はバイブモーターを制御するモジュールである。モジュールはちょっと高いが、バイブの強弱、100種類以上の振動パターン、モーターの各種制御機能が備わっている。
https://www.switch-science.com/catalog/2178/
筆者がこのモジュールに接続して使用しているモーターはAmazonの安価なタイプ。
uxcell マイクロモーター 振動モーター 電動機 ブラシレス DC 1.5V-3V 10mm x 2.7mm 携帯電話用 5個セット
I2C通信で制御し、AdafruitやSparkfun等が出しているライブラリを利用して制御する事が出来る。チップに100種類以上の振動パターン内蔵されており、パターンを指定して鳴らしたり、別の入力と連動させたりと言った使い方が出来る。
ところが、最初は調子良く動いていたが、急に動かなくなった。パターンを指定しても全く動かないか、ちょっと動いたりする程度。モーターかモジュールを壊してしまったかと思い、マイコンを変えたりモーターを交換してみたりしたが回復せず。
ライブラリやデータシートを色々調べてみた所、DRV2605は単にモーターを回すだけでなく、かなり高度な制御を行っている事が分かった。
http://www.tij.co.jp/jp/lit/ds/symlink/drv2605l.pdf
かなり複雑なので深い所までは把握できていないが、モーターの過負荷による温度超過や過電流による停止機能、モーターの種別や電流の制御方法を設定・保存、自動調整、電圧を監視する機能等がついている。
ステータスレジスタ0x00を読み取ると、温度超過や過電流により停止した場合ビット0や1にフラグが立つらしい。DRV2605Lの場合正常時0xE0の値が返る。ステータスレジスタの読み取りによりこのフラグはクリアされるらしい。
レジスタ0x16~0x1Aには各種設定が入っており、この値は電源断後も保持される。このため、この値を狂わせた場合単に再起動しても元には戻らない。
ステータスレジスタの読み取りや0x16~0x1Aのレジスタにデータシート記載のデフォルト値を設定した所、正常に動作する様になった。なにかのはずみでエラー状態になっていたか、設定値が狂ったのかもしれない。
下記はSparkfunのライブラリを使い、起動時シリアルに現在の状態とレジスタ値を出力後、出荷時の設定に値を上書きし、再度設定値を出力、その後プリセットの振動パターンを順番に出力するスケッチ。
//data sheet
//http://www.tij.co.jp/jp/lit/ds/symlink/drv2605l.pdf?ts=1591282871686
#include <Sparkfun_DRV2605L.h> //SparkFun Haptic Motor Driver Library
#include <Wire.h> //I2C library
SFE_HMD_DRV2605L HMD; //Create haptic motor driver object
//0x16 - 0x1a nonvolatile device settings see ref. page 20, page 30 9.5.7
//0x1A setting
#define FD_ERM 0x00
#define FD_LRA 0x80
#define FD_FACT_1X 0x00
#define FD_FACT_2X 0x10 //default
#define FD_FACT_3X 0x20
#define FD_FACT_4X 0x30
#define FD_FACT_6X 0x40
#define FD_FACT_8X 0x50
#define FD_FACT_16X 0x60
#define FD_FACT_DIS 0x70
#define FD_GAIN_LOW 0x00
#define FD_GAIN_MID 0x04 //default
#define FD_GAIN_HIGH 0x08
#define FD_GAIN_MAX 0x0C
#define FD_ERM_0 0x00 //0.255x
#define FD_ERM_1 0x01 //0.7875x
#define FD_ERM_2 0x02 //1.365x default
#define FD_ERM_3 0x03 //3.0x
bool statusok = false;
char chbuff[128];
bool checkstatus() {
//The Status Register (0x00): The Device ID is bits 7-5. For DRV2605L it should be 7 or 111.
//bits 4 and 2 are reserved. Bit 3 is the diagnostic result. You want to see 0.
//bit 1 is the over temp flag, you want this to be 0
//bit 0 is over current flag, you want this to be zero.
// Ideally the register will read 0xE0.
uint8_t status = HMD.readDRV2605L(STATUS_REG);
Serial.print("Status Register 0x");
Serial.print(status, HEX);
if (status == 0xE0) {
Serial.println(" OK");
statusok = true;
}
else {
Serial.println(" NG");
statusok = false;
}
sprintf(chbuff, " Device id:%d\n", (status >> 5) & 0x07);
Serial.print(chbuff);
sprintf(chbuff, " Diag result:%d\n", (status >> 3) & 0x01);
Serial.print(chbuff);
sprintf(chbuff, " Overtemp:%d\n", (status >> 1) & 0x01);
Serial.print(chbuff);
sprintf(chbuff, " Overccurent:%d\n", (status >> 0) & 0x01);
Serial.print(chbuff);
return statusok;
}
void resettodefault() {
//bit 7 device reset
Serial.println("Device reset");
HMD.writeDRV2605L(MODE_REG, 0x80);
//set register to default (from data sheet)
HMD.writeDRV2605L(0x16, 0x3e);
HMD.writeDRV2605L(0x17, 0x8c);
HMD.writeDRV2605L(0x18, 0x0c);
HMD.writeDRV2605L(0x19, 0x6c);
HMD.writeDRV2605L(0x1A, 0x36);
}
void showsetting() {
sprintf(chbuff, "Reg 0x16 : %02X (Rated voltage DEF 0x3E)\n", HMD.readDRV2605L(0x16));
Serial.print(chbuff);
sprintf(chbuff, "Reg 0x17 : %02X (od clamp DEF 0x8C)\n", HMD.readDRV2605L(0x17));
Serial.print(chbuff);
sprintf(chbuff, "Reg 0x18 : %02X (Auto cal comp result DEF 0x0C)\n", HMD.readDRV2605L(0x18));
Serial.print(chbuff);
sprintf(chbuff, "Reg 0x19 : %02X (Auto cal BEMF result DEF 0x6C)\n", HMD.readDRV2605L(0x19));
Serial.print(chbuff);
byte reg = HMD.readDRV2605L(0x1A);
sprintf(chbuff, "Reg 0x1A : %02X (Feedback Control DEF 0x36)\n", reg);
Serial.print(chbuff);
sprintf(chbuff, " ERM/LRA:%d DEF 0\n", (reg >> 7) & 0x01);
Serial.print(chbuff);
sprintf(chbuff, " Brake Factor:%d DEF 3\n", (reg >> 4) & 0x07);
Serial.print(chbuff);
sprintf(chbuff, " Loop Gain:%d DEF 1\n", (reg >> 2) & 0x03);
Serial.print(chbuff);
sprintf(chbuff, " BEMF Gain:%d DEF 2\n", (reg >> 0) & 0x03);
Serial.print(chbuff);
reg = HMD.readDRV2605L(0x1D);
sprintf(chbuff, "Reg 0x1D : %02X (Control3 Register)\n", reg);
Serial.print(chbuff);
sprintf(chbuff, " Noise gate threshold:%d DEF 2\n", (reg >> 7) & 0x03);
Serial.print(chbuff);
sprintf(chbuff, " Open loop:%d DEF 1\n", (reg >> 5) & 0x01);
Serial.print(chbuff);
sprintf(chbuff, " Supply compensation:%d DEF 0\n", (reg >> 4) & 0x01);
Serial.print(chbuff);
sprintf(chbuff, " Data format:%d DEF 0\n", (reg >> 3) & 0x01);
Serial.print(chbuff);
}
void setup()
{
Wire.begin();
delay(1000);
Serial.println("\n-------------");
checkstatus();
showsetting();
if (!statusok) {
Serial.println("Invalid status!");
delay(5000);
}
Serial.println("-------------");
resettodefault();
checkstatus();
showsetting();
HMD.Mode(0); // Internal trigger input mode -- Must use the GO() function to trigger playback.
HMD.Library(1); //1-5 & 7 for ERM motors, 6 for LRA motors */
}
void goWait() {
//wait until pattern is done
while (HMD.readDRV2605L(0x0C) & 0x01) {
yield(); // needed for RTOS based ESP8266/ESP32, etc.
}
}
int wave;
unsigned long lastvib = 0;
void loop()
{
if (millis() - lastvib >= 1500 && statusok) {
runeffect(wave + 1);
wave = (wave + 1) % 122;
lastvib = millis();
}
}
void runeffect(int effect) {
if (effect == 1) Serial.println(F("1 - Strong Click - 100%"));
else if (effect == 2) Serial.println(F("2 - Strong Click - 60%"));
else if (effect == 3) Serial.println(F("3 - Strong Click - 30%"));
else if (effect == 4) Serial.println(F("4 - Sharp Click - 100%"));
else if (effect == 5) Serial.println(F("5 - Sharp Click - 60%"));
else if (effect == 6) Serial.println(F("6 - Sharp Click - 30%"));
else if (effect == 7) Serial.println(F("7 - Soft Bump - 100%"));
else if (effect == 8) Serial.println(F("8 - Soft Bump - 60%"));
else if (effect == 9) Serial.println(F("9 - Soft Bump - 30%"));
else if (effect == 10) Serial.println(F("10 - Double Click - 100%"));
else if (effect == 11) Serial.println(F("11 - Double Click - 60%"));
else if (effect == 12) Serial.println(F("12 - Triple Click - 100%"));
else if (effect == 13) Serial.println(F("13 - Soft Fuzz - 60%"));
else if (effect == 14) Serial.println(F("14 - Strong Buzz - 100%"));
else if (effect == 15) Serial.println(F("15 - 750 ms Alert 100%"));
else if (effect == 16) Serial.println(F("16 - 1000 ms Alert 100%"));
else if (effect == 17) Serial.println(F("17 - Strong Click 1 - 100%"));
else if (effect == 18) Serial.println(F("18 - Strong Click 2 - 80%"));
else if (effect == 19) Serial.println(F("19 - Strong Click 3 - 60%"));
else if (effect == 20) Serial.println(F("20 - Strong Click 4 - 30%"));
else if (effect == 21) Serial.println(F("21 - Medium Click 1 - 100%"));
else if (effect == 22) Serial.println(F("22 - Medium Click 2 - 80%"));
else if (effect == 23) Serial.println(F("23 - Medium Click 3 - 60%"));
else if (effect == 24) Serial.println(F("24 - Sharp Tick 1 - 100%"));
else if (effect == 25) Serial.println(F("25 - Sharp Tick 2 - 80%"));
else if (effect == 26) Serial.println(F("26 - Sharp Tick 3 - 60%"));
else if (effect == 27) Serial.println(F("27 - Short Double Click Strong 1 - 100%"));
else if (effect == 28) Serial.println(F("28 - Short Double Click Strong 2 - 80%"));
else if (effect == 29) Serial.println(F("29 - Short Double Click Strong 3 - 60%"));
else if (effect == 30) Serial.println(F("30 - Short Double Click Strong 4 - 30%"));
else if (effect == 31) Serial.println(F("31 - Short Double Click Medium 1 - 100%"));
else if (effect == 32) Serial.println(F("32 - Short Double Click Medium 2 - 80%"));
else if (effect == 33) Serial.println(F("33 - Short Double Click Medium 3 - 60%"));
else if (effect == 34) Serial.println(F("34 - Short Double Sharp Tick 1 - 100%"));
else if (effect == 35) Serial.println(F("35 - Short Double Sharp Tick 2 - 80%"));
else if (effect == 36) Serial.println(F("36 - Short Double Sharp Tick 3 - 60%"));
else if (effect == 37) Serial.println(F("37 - Long Double Sharp Click Strong 1 - 100%"));
else if (effect == 38) Serial.println(F("38 - Long Double Sharp Click Strong 2 - 80%"));
else if (effect == 39) Serial.println(F("39 - Long Double Sharp Click Strong 3 - 60%"));
else if (effect == 40) Serial.println(F("40 - Long Double Sharp Click Strong 4 - 30%"));
else if (effect == 41) Serial.println(F("41 - Long Double Sharp Click Medium 1 - 100%"));
else if (effect == 42) Serial.println(F("42 - Long Double Sharp Click Medium 2 - 80%"));
else if (effect == 43) Serial.println(F("43 - Long Double Sharp Click Medium 3 - 60%"));
else if (effect == 44) Serial.println(F("44 - Long Double Sharp Tick 1 - 100%"));
else if (effect == 45) Serial.println(F("45 - Long Double Sharp Tick 2 - 80%"));
else if (effect == 46) Serial.println(F("46 - Long Double Sharp Tick 3 - 60%"));
else if (effect == 47) Serial.println(F("47 - Buzz 1 - 100%"));
else if (effect == 48) Serial.println(F("48 - Buzz 2 - 80%"));
else if (effect == 49) Serial.println(F("49 - Buzz 3 - 60%"));
else if (effect == 50) Serial.println(F("50 - Buzz 4 - 40%"));
else if (effect == 51) Serial.println(F("51 - Buzz 5 - 20%"));
else if (effect == 52) Serial.println(F("52 - Pulsing Strong 1 - 100%"));
else if (effect == 53) Serial.println(F("53 - Pulsing Strong 2 - 60%"));
else if (effect == 54) Serial.println(F("54 - Pulsing Medium 1 - 100%"));
else if (effect == 55) Serial.println(F("55 - Pulsing Medium 2 - 60%"));
else if (effect == 56) Serial.println(F("56 - Pulsing Sharp 1 - 100%"));
else if (effect == 57) Serial.println(F("57 - Pulsing Sharp 2 - 60%"));
else if (effect == 58) Serial.println(F("58 - Transition Click 1 - 100%"));
else if (effect == 59) Serial.println(F("59 - Transition Click 2 - 80%"));
else if (effect == 60) Serial.println(F("60 - Transition Click 3 - 60%"));
else if (effect == 61) Serial.println(F("61 - Transition Click 4 - 40%"));
else if (effect == 62) Serial.println(F("62 - Transition Click 5 - 20%"));
else if (effect == 63) Serial.println(F("63 - Transition Click 6 - 10%"));
else if (effect == 64) Serial.println(F("64 - Transition Hum 1 - 100%"));
else if (effect == 65) Serial.println(F("65 - Transition Hum 2 - 80%"));
else if (effect == 66) Serial.println(F("66 - Transition Hum 3 - 60%"));
else if (effect == 67) Serial.println(F("67 - Transition Hum 4 - 40%"));
else if (effect == 68) Serial.println(F("68 - Transition Hum 5 - 20%"));
else if (effect == 69) Serial.println(F("69 - Transition Hum 6 - 10%"));
else if (effect == 70) Serial.println(F("70 - Transition Ramp Down Long Smooth 1 - 100 to 0%"));
else if (effect == 71) Serial.println(F("71 - Transition Ramp Down Long Smooth 2 - 100 to 0%"));
else if (effect == 72) Serial.println(F("72 - Transition Ramp Down Medium Smooth 1 - 100 to 0%"));
else if (effect == 73) Serial.println(F("73 - Transition Ramp Down Medium Smooth 2 - 100 to 0%"));
else if (effect == 74) Serial.println(F("74 - Transition Ramp Down Short Smooth 1 - 100 to 0%"));
else if (effect == 75) Serial.println(F("75 - Transition Ramp Down Short Smooth 2 - 100 to 0%"));
else if (effect == 76) Serial.println(F("76 - Transition Ramp Down Long Sharp 1 - 100 to 0%"));
else if (effect == 77) Serial.println(F("77 - Transition Ramp Down Long Sharp 2 - 100 to 0%"));
else if (effect == 78) Serial.println(F("78 - Transition Ramp Down Medium Sharp 1 - 100 to 0%"));
else if (effect == 79) Serial.println(F("79 - Transition Ramp Down Medium Sharp 2 - 100 to 0%"));
else if (effect == 80) Serial.println(F("80 - Transition Ramp Down Short Sharp 1 - 100 to 0%"));
else if (effect == 81) Serial.println(F("81 - Transition Ramp Down Short Sharp 2 - 100 to 0%"));
else if (effect == 82) Serial.println(F("82 - Transition Ramp Up Long Smooth 1 - 0 to 100%"));
else if (effect == 83) Serial.println(F("83 - Transition Ramp Up Long Smooth 2 - 0 to 100%"));
else if (effect == 84) Serial.println(F("84 - Transition Ramp Up Medium Smooth 1 - 0 to 100%"));
else if (effect == 85) Serial.println(F("85 - Transition Ramp Up Medium Smooth 2 - 0 to 100%"));
else if (effect == 86) Serial.println(F("86 - Transition Ramp Up Short Smooth 1 - 0 to 100%"));
else if (effect == 87) Serial.println(F("87 - Transition Ramp Up Short Smooth 2 - 0 to 100%"));
else if (effect == 88) Serial.println(F("88 - Transition Ramp Up Long Sharp 1 - 0 to 100%"));
else if (effect == 89) Serial.println(F("89 - Transition Ramp Up Long Sharp 2 - 0 to 100%"));
else if (effect == 90) Serial.println(F("90 - Transition Ramp Up Medium Sharp 1 - 0 to 100%"));
else if (effect == 91) Serial.println(F("91 - Transition Ramp Up Medium Sharp 2 - 0 to 100%"));
else if (effect == 92) Serial.println(F("92 - Transition Ramp Up Short Sharp 1 - 0 to 100%"));
else if (effect == 93) Serial.println(F("93 - Transition Ramp Up Short Sharp 2 - 0 to 100%"));
else if (effect == 94) Serial.println(F("94 - Transition Ramp Down Long Smooth 1 - 50 to 0%"));
else if (effect == 95) Serial.println(F("95 - Transition Ramp Down Long Smooth 2 - 50 to 0%"));
else if (effect == 96) Serial.println(F("96 - Transition Ramp Down Medium Smooth 1 - 50 to 0%"));
else if (effect == 97) Serial.println(F("97 - Transition Ramp Down Medium Smooth 2 - 50 to 0%"));
else if (effect == 98) Serial.println(F("98 - Transition Ramp Down Short Smooth 1 - 50 to 0%"));
else if (effect == 99) Serial.println(F("99 - Transition Ramp Down Short Smooth 2 - 50 to 0%"));
else if (effect == 100) Serial.println(F("100 - Transition Ramp Down Long Sharp 1 - 50 to 0%"));
else if (effect == 101) Serial.println(F("101 - Transition Ramp Down Long Sharp 2 - 50 to 0%"));
else if (effect == 102) Serial.println(F("102 - Transition Ramp Down Medium Sharp 1 - 50 to 0%"));
else if (effect == 103) Serial.println(F("103 - Transition Ramp Down Medium Sharp 2 - 50 to 0%"));
else if (effect == 104) Serial.println(F("104 - Transition Ramp Down Short Sharp 1 - 50 to 0%"));
else if (effect == 105) Serial.println(F("105 - Transition Ramp Down Short Sharp 2 - 50 to 0%"));
else if (effect == 106) Serial.println(F("106 - Transition Ramp Up Long Smooth 1 - 0 to 50%"));
else if (effect == 107) Serial.println(F("107 - Transition Ramp Up Long Smooth 2 - 0 to 50%"));
else if (effect == 108) Serial.println(F("108 - Transition Ramp Up Medium Smooth 1 - 0 to 50%"));
else if (effect == 109) Serial.println(F("109 - Transition Ramp Up Medium Smooth 2 - 0 to 50%"));
else if (effect == 110) Serial.println(F("110 - Transition Ramp Up Short Smooth 1 - 0 to 50%"));
else if (effect == 111) Serial.println(F("111 - Transition Ramp Up Short Smooth 2 - 0 to 50%"));
else if (effect == 112) Serial.println(F("112 - Transition Ramp Up Long Sharp 1 - 0 to 50%"));
else if (effect == 113) Serial.println(F("113 - Transition Ramp Up Long Sharp 2 - 0 to 50%"));
else if (effect == 114) Serial.println(F("114 - Transition Ramp Up Medium Sharp 1 - 0 to 50%"));
else if (effect == 115) Serial.println(F("115 - Transition Ramp Up Medium Sharp 2 - 0 to 50%"));
else if (effect == 116) Serial.println(F("116 - Transition Ramp Up Short Sharp 1 - 0 to 50%"));
else if (effect == 117) Serial.println(F("117 - Transition Ramp Up Short Sharp 2 - 0 to 50%"));
else if (effect == 118) Serial.println(F("118 - Long buzz for programmatic stopping - 100%"));
else if (effect == 119) Serial.println(F("119 - Smooth Hum 1 (No kick or brake pulse) - 50%"));
else if (effect == 120) Serial.println(F("120 - Smooth Hum 2 (No kick or brake pulse) - 40%"));
else if (effect == 121) Serial.println(F("121 - Smooth Hum 3 (No kick or brake pulse) - 30%"));
else if (effect == 122) Serial.println(F("122 - Smooth Hum 4 (No kick or brake pulse) - 20%"));
else if (effect == 123) Serial.println(F("123 - Smooth Hum 5 (No kick or brake pulse) - 10%"));
HMD.Waveform(0, wave + 1);
HMD.Waveform(1, 0);
HMD.go();
goWait();
}