鳥なき里のマイコン屋(118) M5ATOM Lite、UART、I2C接続

Joseph Halfmoon

前回、M5Stack社の超小型無線マイコンボード ATOM Liteの拡張端子について、デジタル、アナログの入出力ピンとしての動作を確認しました。今回は、UARTおよびI2Cインタフェースが使用できることを確かめたいと思います。兄弟品種?のM5StickC よりも大分使いやすい気がいたします。

※「鳥なき里のマイコン屋」投稿順Indexはこちら

(末尾に今回作成した動作確認用のプログラム<Arduino環境向け>の全文を掲げました。)

IDEのボード選択メニューでATOM Liteは、M5StickC(plusではなくノーマル版)として設定するのが標準です(今のところ。)搭載しているESP32モジュールの型式などM5StickCと共通する部分が多いです。M5StickCのUART接続については以下の投稿でちょっと試行錯誤をしているのでATOM Liteはどうなんだろうとかなり気になっていました。

トホホな疑問(27) M5StickC、Uartを使う

大きさからするとM5StickCのサブセット的にも思えるATOM Liteなのですが、こと拡張端子やGroveコネクタに出ている端子名を見ると結構異なります。確かめてみると、

M5StickCよりもATOM Liteの拡張端子の方が「各段に」使いやすい

とおもいました。

拡張端子は全てUART接続可能だった

ATOM Liteの場合、裏面に6端子、Groveコネクタに2端子の合計8端子が外部接続可能です。この全てがUART(非同期式シリアルインタフェース)のTXあるいはRXとしてアサイン可能でした。動作テストしたのは以下の組み合わせです。

    • Groveポート G32=TX、G26=RX
    • 背面端子 G22=TX、G19=RX
    • 背面端子 G21=TX、G25=RX
    • 背面端子 G23=TX、G33=RX

まあ実際に動作確認したのは、ATOM LiteのTXから外部のRXへの通信の方向だけです。外部TXからATOM LiteのRXに向かう方法は実機テストしていないのでご注意を。

ソフトウエア的に見ると、Arduino環境で

Serial2

と呼ばれる「2番目の」UARTとしての使用です。2の付かない 「1番目の」”Serial” の方はお約束通り、USBシリアル(IDEのシリアルモニタなど printfデバッグ的に使う)に向いています。外部デバイスとの通信にはSerial2の方を使うと良いと思います。なお、M5StickCのUART動作を確認した時、「ESP32はAny端子にUART接続出せるようなことを書いてあるけど駄目じゃん」みたいなことを書いてしまいましたが、本ATOM LiteについてはAny端子OKって感じです。

末尾に掲げたサンプルソフトでは、4組のTX-RX組を列挙(コメントとして)してあります。このうちから1組を選んでコメントを外せばSerial2としてそこの端子が使用できます。

もう一組のI2Cバス利用可能

Groveポートに出ている2端子はI2CバスのSCLおよびSDAとして使用可能の筈です(Arduino環境下の「1番目の」I2CバスであるWireとして)背面拡張端子にもSCLおよびSDAとして使用可能な以下の信号が出ています。こちらはGroveポートのバスとは独立のバスなのでハード的には取り扱いがしやすいです。(前にも書いてますが、M5Stack社のデバイスのGroveポートの電源は5VなのにI2Cバスの信号レベルは3.3Vなので取り扱いが気になるところです。その点、背面端子には3.3V/5Vの両電源とも出ているので、3.3Vのままでも、5Vに変換するにしても回路的には安心して取り扱えると思います。)

G21=SCL、G25=SDA

なお、前回書きましたが兄弟品種のATOM Matrixでは内部でこのI2CバスはIMUに接続されています。ATOM Liteでは、未スキャンですが、多分他に接続されているデバイスは無い筈。使い放題。

Arduino環境でのソフトウエア上では、

Wire1

という名で呼ばれる「2番目の」I2Cバスとして使えました。なお初期化は以下のようにピン番号含めた方が良いようです。

 Wire1.begin(25,21);

Groveポートに出ている番号なしのWireに対して、「2番目」がWire1という名前の付け方、UARTと並べるとちょっと統一感がないですが、そこには何か事情があるのでしょう。

動作確認

動作確認は、「電子工作」業界定番?の以下のモジュールを接続して行いました。いずれも秋月電子製です。

    • FT232RL、ATOM LiteのUART出力を受信するのに使用。3.3V設定。
    • ARM1602XA-RN-GBW、ATOM LiteのI2C出力を受信するのに使用。3.3V接続。

まずはUART接続の様子を下に掲げます。COM14がATOM LiteのUSBシリアル(Serial)に接続している方で、COM6がSerial2側です。

Serial and Serial2I2C接続の方は、ちょっと見づらいですが、アイキャッチ画像を御覧ください。キャラクタLCDモジュールに Hello World! 書かれているのがI2C通信の結果です。3.3V電源で使っているので秋月電子殿の文書の設定値(5V電源用)のままだとコントラストが薄くなるのでちょっとキツメにしてあります。

これで ATOM Lite と外部デバイスを接続する「すべ」が確認できました。次はいよいよ無線機能の無いデバイスに ATOM Liteを接続して無線IoT化ですかね?

鳥なき里のマイコン屋(117) M5ATOM Lite、ブレッドボード接続のお供 へ戻る

鳥なき里のマイコン屋(119) M5Stack、FreeRTOS機能使って周波数カウンタ へ進む

ATOM Lite, Serial2(UART) と Wire1(I2C)の接続テスト
#include "M5Atom.h"
//OK
//#define TXPIN  (32)
//#define RXPIN  (26)
//#define TXPIN  (22)
//#define RXPIN  (19)
//#define TXPIN  (21)
//#define RXPIN  (25)
#define TXPIN  (23)
#define RXPIN  (33)

const bool LCDEnable = false;
const bool PowerEnable = false;
const bool SerialEnable = true;

int loopCounter;
bool ledOn;

int i2c1WriteByte(uint8_t busadr, uint8_t regadr, uint8_t dat) {
  Wire1.beginTransmission(busadr);
  Wire1.write(regadr);
  Wire1.write(dat);
  return (Wire1.endTransmission()); // 0:success >0:fail
}

void initAQM1602() {
  uint8_t adr1602 = 0x3E;
  uint8_t cmd = 0x00;
  uint8_t dat = 0x40;
  delay(100);
  i2c1WriteByte(adr1602, cmd, 0x38);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x39);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x14);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x77); //0x73 for 5V, 0x77 for 3.3V
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x56);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x6C);
  delay(200);
  i2c1WriteByte(adr1602, cmd, 0x38);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x01);
  delay(20);
  i2c1WriteByte(adr1602, cmd, 0x0C);
  delay(20);
}

int displaySTR(char Pos, char* message) {
  uint8_t adr1602 = 0x3E;
  uint8_t cmd = 0x00;
  uint8_t dat = 0x40;
  uint8_t cc;
  int idx = 0;
  int status = 0;
  delay(20);
  status = i2c1WriteByte(adr1602, cmd, Pos);
  while ((status == 0) && (idx < 16) && (*message != 0)) {
    cc = *message++;
    status = i2c1WriteByte(adr1602, dat, cc);
    idx++;
  }
  return status;
}

void setup() {
  M5.begin(LCDEnable, PowerEnable, SerialEnable); //M5StickC::begin
  Serial.begin(115200); 
  while(!Serial) {};
  Serial.println("1> Start Serial:");
  Serial2.begin(115200, SERIAL_8N1, RXPIN, TXPIN);
  while(!Serial2) {};
  Serial2.println("2> Start Serial2:");
  loopCounter = 0;
  ledOn = true;
  Wire1.begin(25,21);
  initAQM1602();
  if (displaySTR(0x80, "Hello World!")) {
    Serial.println("AQM1602 Write Fail");    
  } else {
    Serial.println("AQM1602 Write Success");
  }
}

void loop() {
  if (ledOn) {
    M5.dis.drawpix(0, 0x100000); //G=0x10
    ledOn = false;
  } else {
    M5.dis.drawpix(0, 0x001000); //R=0x10
    ledOn = true;    
  }
  Serial.print("1>");  
  Serial.println(loopCounter);  
  Serial2.print("2>");  
  Serial2.println(loopCounter++);
  delay(5000);
}