M5StickVとM5StackをつなげてWiFi通信する - I2C編

# はじめに

[M5StickVとM5StackをつなげてWiFi通信する](https://qiita.com/fukuebiz/items/cc4fe4734e9eac6ae2bc) で、M5StickVとM5Stackを接続してシリアル通信でWiFi通信してみました。シリアル通信は汎用性が高いものの、通信速度が上げられない、M5StickVに１つしかないGroveポートを占有してしまう、などの問題がありました。そこでI2Cで通信できないか試してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/85872015-955c-8f2e-1fca-f280b519b7ed.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/5c1be89b-437c-dfbe-fd00-021a68bf487b.png)


# 準備

M5StackにはI2Cで通信するためのファームウェアを書き込みます。ソースは [こちら](https://github.com/fukuen/m5stack-i2c-wifi)。

Sipeed社から提供されているMaixduinoのSPI用のファームウェア [Maixduino_esp32_fimware](https://github.com/sipeed/Maixduino_esp32_fimware) を参考にさせて頂きました。また、M5StackをI2CのSlaveで通信させるところは、こちらの [ESP32_I2C_Slave](https://github.com/gutierrezps/ESP32_I2C_Slave) を参考にさせて頂きました。ありがとうございます。

# M5StickV側

WiFi通信用のライブラリーはこちらの [Maixduino_WiFiEspI2C](https://github.com/fukuen/Maixduino_WiFiEspI2C) 。

PubSubClientと組み合わせて、AWS IoTに接続するサンプルはこんな感じになります。

[ESP32でAWS IoTに繋いでThing Shadowを弄る](https://blog.maripo.org/2017/07/esp32-aws-iot/) を参考にさせて頂きました。ありがとうございます。

```cpp:main.cpp
/*--------------------------------------------------------------------
Copyright 2021 fukuen

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This software is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with The Arduino WiFiEsp library.  If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------*/

#include <Arduino.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include <WiFiEspI2C.h>
#include <PubSubClient.h>
#include "esp32_i2c.h"

TFT_eSPI lcd;

#define AXP192_ADDR 0x34
#ifdef M5STICKV
#define PIN_SDA 29
#define PIN_SCL 28
#define WIDTH 280
#define HEIGHT 240
#define XOFFSET 40
#define YOFFSET 60
#define I2C_SDA_PIN 34
#define I2C_SCL_PIN 35
#define I2C_SLAVE_ADDR 0x04
#endif

#define AXP173_ADDR 0x34
#ifdef MAIXAMIGO
#define PIN_SDA 27
#define PIN_SCL 24
#define WIDTH 480
#define HEIGHT 320
#define XOFFSET 0
#define YOFFSET 0
#define I2C_SDA_PIN 7 //27
#define I2C_SCL_PIN 9 //24
#define I2C_SLAVE_ADDR 0x04
#endif


char SSID[] = "<your ssid>";      // your network SSID (name)
char PASS[] = "<your pass>";      // your network password
int status = WL_IDLE_STATUS;

const char *endpoint = "<AWS_IOT_ENDPOINT>";
// Example: xxxxxxxxxxxxxx.iot.ap-northeast-1.amazonaws.com
const int port = 8883;
char *pubTopic = "/sample123";
char *subTopic = "/sample123";

const char* rootCA = "-----BEGIN CERTIFICATE-----\n" \
"......\n" \
"-----END CERTIFICATE-----\n";

const char* certificate = "-----BEGIN CERTIFICATE-----\n" \
"......\n" \
"-----END CERTIFICATE-----\n";


const char* privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" \
"......\n" \
"-----END RSA PRIVATE KEY-----\n";

// Initialize the Ethernet client object
WiFiEspSSLClient httpsClient;
PubSubClient mqttClient(httpsClient);

long messageSentAt = 0;
int dummyValue = 0;
char pubMessage[128];

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

char buf[1024];

bool axp192_init() {
  Serial.printf("AXP192 init.\n");
  sysctl_set_power_mode(SYSCTL_POWER_BANK3,SYSCTL_POWER_V33);

  Wire.begin((uint8_t) PIN_SDA, (uint8_t) PIN_SCL, 400000);
  Wire.beginTransmission(AXP192_ADDR);
  int err = Wire.endTransmission();
  if (err) {
    Serial.printf("Power management ic not found.\n");
    return false;
  }
  Serial.printf("AXP192 found.\n");

  // Clear the interrupts
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x46);
  Wire.write(0xFF);
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x23);
  Wire.write(0x08); //K210_VCore(DCDC2) set to 0.9V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x33);
  Wire.write(0xC1); //190mA Charging Current
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x36);
  Wire.write(0x6C); //4s shutdown
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x91);
  Wire.write(0xF0); //LCD Backlight: GPIO0 3.3V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x90);
  Wire.write(0x02); //GPIO LDO mode
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x28);
  Wire.write(0xF0); //VDD2.8V net: LDO2 3.3V,  VDD 1.5V net: LDO3 1.8V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x27);
  Wire.write(0x2C); //VDD1.8V net:  DC-DC3 1.8V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x12);
  Wire.write(0xFF); //open all power and EXTEN
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x23);
  Wire.write(0x08); //VDD 0.9v net: DC-DC2 0.9V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x31);
  Wire.write(0x03); //Cutoff voltage 3.2V
  Wire.endTransmission();
  Wire.beginTransmission(AXP192_ADDR);
  Wire.write(0x39);
  Wire.write(0xFC); //Turnoff Temp Protect (Sensor not exist!)
  Wire.endTransmission();

  fpioa_set_function(23, (fpioa_function_t)(FUNC_GPIOHS0 + 26));
  gpiohs_set_drive_mode(26, GPIO_DM_OUTPUT);
  gpiohs_set_pin(26, GPIO_PV_HIGH); //Disable VBUS As Input, BAT->5V Boost->VBUS->Charing Cycle

  msleep(20);
  return true;
}

void axp173_init() {
    Wire.begin((uint8_t) PIN_SDA, (uint8_t) PIN_SCL, 400000);
    Wire.beginTransmission(AXP173_ADDR);
    int err = Wire.endTransmission();
    if (err) {
        Serial.printf("Power management ic not found.\n");
        return;
    }
    Serial.printf("AXP173 found.\n");
#ifdef MAIXAMIGO
    //LDO4 - 0.8V (default 0x48 1.8V)
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x27);
    Wire.write(0x20);
    Wire.endTransmission();
    //LDO2/3 - LDO2 1.8V / LDO3 3.0V
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x28);
    Wire.write(0x0C);
    Wire.endTransmission();
#else
    // Clear the interrupts
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x46);
    Wire.write(0xFF);
    Wire.endTransmission();
    // set target voltage and current of battery(axp173 datasheet PG.)
    // charge current (default)780mA -> 190mA
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x33);
    Wire.write(0xC1);
    Wire.endTransmission();
    // REG 10H: EXTEN & DC-DC2 control
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x10);
    Wire.endTransmission();
    Wire.requestFrom(AXP173_ADDR, 1, 1);
    int reg = Wire.read();
    Wire.beginTransmission(AXP173_ADDR);
    Wire.write(0x10);
    Wire.write(reg & 0xFC);
    Wire.endTransmission();
#endif
}

void printWifiStatus() {
  // print the SSID of the network you're attached to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void connectAWSIoT() {
  while (!mqttClient.connected()) {
    if (mqttClient.connect("maixamigo")) {
      Serial.println("Connected.");
      int qos = 0;
      mqttClient.subscribe(subTopic, qos);
      Serial.println("Subscribed.");
    } else {
      Serial.print("Failed. Error state=");
      Serial.print(mqttClient.state());
      // Wait 5 seconds before retrying
      delay(5000);
      httpsClient.setCertificate(certificate);
      httpsClient.setPrivateKey(privateKey);
    }
  }
}

void setup() {
  Serial.begin(115200);
#ifdef M5STICKV
  axp192_init();
#else
  axp173_init();
#endif

  /* LCD init */
  lcd.begin();
  lcd.setRotation(1);

  lcd.fillRect(0, 0, WIDTH, HEIGHT, TFT_BLACK);
  lcd.setTextFont(0);
  lcd.setTextColor(TFT_WHITE);
  lcd.setCursor(0 + XOFFSET, 0 + YOFFSET);
  lcd.printf("running.");

  Wire1.begin((uint8_t)I2C_SDA_PIN, (uint8_t)I2C_SCL_PIN, (uint32_t)400000);
  WiFi.init(Wire1, I2C_SLAVE_ADDR);    // initialize ESP WiFi module

  Serial.println("## status");
  // check for the presence of the shield
//  if (WiFi.status() == WL_NO_SHIELD) {
  if (WiFi.status() == -2) {
      Serial.println("WiFi shield not present");
      // don't continue
      while (true);
  }

  // attempt to connect to WiFi network
  status = WiFi.begin(SSID, PASS);
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(SSID);
    // Connect to WPA/WPA2 network
    sleep(1);
    status = WiFi.status();
  }

  printWifiStatus();

  // Configure MQTT Client
//  httpsClient.setCACertificate(rootCA);
  httpsClient.setCertificate(certificate);
  httpsClient.setPrivateKey(privateKey);
  mqttClient.setServer(endpoint, port);
  mqttClient.setCallback(mqttCallback);

  Serial.println("connectAWSIoT");

  connectAWSIoT();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!mqttClient.connected()) {
    connectAWSIoT();
  }
  mqttClient.loop();

  long now = millis();
  if (now - messageSentAt > 5000) {
    messageSentAt = now;
    sprintf(pubMessage, "{\"message\": \"%d\"}", dummyValue++);
    Serial.print("Publishing message to topic ");
    Serial.println(pubTopic);
    Serial.println(pubMessage);
    mqttClient.publish(pubTopic, pubMessage);
    Serial.println("Published.");
  }
}

```

# さいごに

これでGroveポートに複数のI2Cデバイスをつなげられるようになるといいと思っています。

まだまだ実験中で、I2C通信周りなどまだ改善が必要だと思っています。