はじめに
M5StickVとM5StackをつなげてWiFi通信する で、M5StickVとM5Stackを接続してシリアル通信でWiFi通信してみました。シリアル通信は汎用性が高いものの、通信速度が上げられない、M5StickVに1つしかないGroveポートを占有してしまう、などの問題がありました。そこでI2Cで通信できないか試してみました。
準備
M5StackにはI2Cで通信するためのファームウェアを書き込みます。ソースは こちら。
Sipeed社から提供されているMaixduinoのSPI用のファームウェア Maixduino_esp32_fimware を参考にさせて頂きました。また、M5StackをI2CのSlaveで通信させるところは、こちらの ESP32_I2C_Slave を参考にさせて頂きました。ありがとうございます。
M5StickV側
WiFi通信用のライブラリーはこちらの Maixduino_WiFiEspI2C 。
PubSubClientと組み合わせて、AWS IoTに接続するサンプルはこんな感じになります。
ESP32でAWS IoTに繋いでThing Shadowを弄る を参考にさせて頂きました。ありがとうございます。
/*--------------------------------------------------------------------
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通信周りなどまだ改善が必要だと思っています。