SW3516とArduinoをi2cで繋いでいろいろ読む

投稿者: | 1月 12, 2023

きっかけ

昔にAliExpressでPDやQCが使えるモジュールを購入して3Dプリンターでケースを作って使用していたのですが、踏んでケースを壊してしまった時に、もっと立派な充電器を作ろうと思いました。使われているチップ(SW3516)について調べてると、データーシート(ミラー日本語訳版)曰くi2cが出ているらしく、色々読めるっぽい(値についての資料(ミラー))ので試してみることにしました。

使用機材・事前準備

今回はArduino UNO(の互換機)を使用しました。
使用したモジュール(DC Quick Chage Adapter)にはi2cようのパターンがないため、ハンダで外付けしました。下に記した図のように20ピンがSDA、21ピンがSCKであるためそこにはんだ付けします。

配線は、Arduino UNOのDCL、SDAとGNDをそのまま繋ぐだけです。

Arduinoのプログラム(動作確認)

i2cであっても、レジスタを読まないといけないので、Qiitaを参考にしました。

Qiita-ArduinoのI2C通信でデバイスのレジスタにアクセスする。

これを参考に書いたコードがこちらです

#include <Wire.h>

const int Device_Address = 0x3C; //i2cアドレス
const int Register_Address[] = {0x01,0x06,0x07,0x12,0x13,0x30,0x31,0x32,0x33,0x34,0x35,0x37,0x38,0x3A,0x3B,0x3C,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5};//レジトリアドレス

int Register_Data[22]; //取得したデータを入れる配列

void setup() {
    Wire.begin();
    Serial.begin(9600);
    Serial.println("end setup");
}

void loop() {
    for (int i = 0; i <= 21; i++){ //レジストリの読み取り
        //Serial.print("reading...");
        //Serial.println(Register_Address[i],HEX);
        Wire.beginTransmission(Device_Address); //i2cデバイスのアドレス指定
        Wire.write(Register_Address[i]); //アドレスの指定
        Wire.endTransmission(false); //request後もコネクションを維持
        Wire.requestFrom(Device_Address, 1,true); //出力の指定
        Register_Data[i] = Wire.read(); //読み出す
        delay(0);
    }
    for (int i = 0; i <= 21; i++){ //Register_Dataの表示
        Serial.print(Register_Address[i],HEX);
        Serial.print(" = ");
        Serial.println(Register_Data[i],BIN);
    }
    delay(5000);

}

単純にレジストリを読み込んで、バイナリを出力するだけのプログラムです。レジストリの意味については、これ(ミラー)を参考にしてください。

こんな感じに表示されるとい思います。使用中のプロトコルや、電流が読めると思います。

Arduinoのプログラム(ライブラリの使用)

ここから、みやすいようにするプログラムを書いていたんですが、調べたらArduino向けライブラリがあったので使ってみます。

GitHub-SW35xx Library for Arduino

この後色々エラーが出るので、エラーが出ない改変バージョンのzipを置いておきます。

h1_SW35xx-custom.zip

zipファイルで落としてきて、スケッチ→ライブラリのインクルード→.ZIP形式のライブラリをインストール…で読み込みします。

以下のエラーはh1_SW35xx-custom.zipでは出ないはずです…

SimpleTestっていうサンプルがありますが、コンパイルしてみるとprintfが使えないよっていうエラーが大量に出て、コンパイルできないと思います。もしくは、cstdintがないよか、BITがじゃなくてBINじゃない?みたいなエラーが出ると思います。

とりあえずprintf対策で作り直しました。ディフォルトの設定だと、入力電圧が読み取れないためレジスタの13アドレスを2に変更して読めるようにします。

#include <Arduino.h>
#include <h1_SW35xx.h>
#include <Wire.h>
using namespace h1_SW35xx;

SW35xx sw(Wire);

void setup() {
  Serial.begin(9600);
  Wire.begin(); 

  //13アドレスを読む
  Wire.beginTransmission(0x3C);
  Wire.write(0x13);
  Wire.endTransmission(false);
  Wire.requestFrom(0x3C, 1,true);
  Serial.println(Wire.read(),BIN);

  //13アドレスに2を書き込み(入力電圧測定の有効化)
  Wire.beginTransmission(0x3C);
  Wire.write(0x13);
  Wire.write(0x2);
  Wire.endTransmission(false);

  //13アドレスを読む(書き換わったか確認)
  Wire.beginTransmission(0x3C);
  Wire.write(0x13);
  Wire.endTransmission(false);
  Wire.requestFrom(0x3C, 1,true);
  Serial.println(Wire.read(),BIN);
  
  sw.setMaxCurrent5A(); //5Aの出力をできるようにする
  
}

const char *fastChargeType2String(SW35xx::fastChargeType_t fastChargeType) {
  switch (fastChargeType) {
  case SW35xx::NOT_FAST_CHARGE:
    return "Not fast charge";
    break;
  case SW35xx::QC2:
    return "QC2.0";
    break;
  case SW35xx::QC3:
    return "QC3.0";
    break;
  case SW35xx::FCP:
    return "FCP";
    break;
  case SW35xx::SCP:
    return "SCP";
    break;
  case SW35xx::PD_FIX:
    return "PD Fix";
    break;
  case SW35xx::PD_PPS:
    return "PD PPS";
    break;
  case SW35xx::MTKPE1:
    return "MTK PE1.1";
    break;
  case SW35xx::MTKPE2:
    return "MTK PE2.0";
    break;
  case SW35xx::LVDC:
    return "LVDC";
    break;
  case SW35xx::SFCP:
    return "SFCP";
    break;
  case SW35xx::AFC:
    return "AFC";
    break;
  default:
    return "unknown";
    break;
  }
}

void loop() {
  sw.readStatus();
  Serial.print("Current input voltage:");
  Serial.print(sw.vin_mV);
  Serial.println("mV");

  Serial.print("Current output voltage:");
  Serial.print(sw.vout_mV);
  Serial.println("mV");

  Serial.print("Current USB-C output cuurent:");
  Serial.print(sw.iout_usbc_mA);
  Serial.println("mA");

  Serial.print("Current USB-A output cuurent:");
  Serial.print(sw.iout_usba_mA);
  Serial.println("mA");

  Serial.print("ChageType:");
  Serial.println(fastChargeType2String(sw.fastChargeType));
  if (sw.fastChargeType == SW35xx::PD_FIX || sw.fastChargeType == SW35xx::PD_PPS){
    Serial.print("PDversion:");
    Serial.println(sw.PDVersion);
  }
  
  
  delay(2000);
}

これで、コンパイルできればいいんですが、自分はあと、cstdintが見つからないってエラーが出たので他のライブラリからcstdintをコピーしました。詳しくはこの記事を参考にしてください。

Arduinoのライブラリ.hにcstdintが見つからないって言われる時の対処法

これで、このエラーは出なくなったんですが、次は、

In file included from /Users/unagidojyou/MEGA/Arduino/Arduino_SW3516_Library_test/Arduino_SW3516_Library_test.ino:2:0:
/Users/unagidojyou/Documents/Arduino/libraries/h1_SW35xx-master/src/h1_SW35xx.h:30:21: error: 'BIT' was not declared in this scope
     QC_CONF_PE    = BIT(0),
                     ^~~
/Users/unagidojyou/Documents/Arduino/libraries/h1_SW35xx-master/src/h1_SW35xx.h:30:21: note: suggested alternative: 'BIN'
     QC_CONF_PE    = BIT(0),
                     ^~~
                     BIN

みたいな感じで大量のエラーが出るっぽいです。どうやらBITっていう関数が見つからないらしいです。Wikiで調べてみた感じBITではなくbitが正しいっぽいので、/Users/”ユーザー名”/Documents/Arduino/libraries/h1_SW35xx-master/src/h1_SW35xx.hのBITをbitに変えました。

これでやっとコンパイルが通るようになります。こうゆう場合ってGitHubにissueを立てた方がいいのかなぁ

実行結果はこんな感じになります。

PD3で9V出力されているのが確認できます。

終わりに

ライブラリがちょっと曲者でしたが、なかなか面白いですね
LCDや昇圧コンバータと組み合わせて各種電圧、電流を計測できるやつを作ってみます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)