? >This document provides a brief overview of how to migrate from the individual M5Stack libraries for the Arduino IDE and ESP-IDF to M5Unified when changing to M5Unified.
* This document is based on information from M5Unified v0.0.7.
M5Unified is a library to handle hardware with different specifications of M5Stack products with a common API. Although it requires more configuration items, the same source code can be used for different devices, which is useful in the following cases.
Include files can be unified.
In the past, the Include header files were different for each device, such as #include <M5Stack.h>
for M5Stack Basic and #include <M5StickC.h>
for M5StickC, but with M5Unified, #include <M5Unified.h>
. The device type is automatically identified in the library.
The argument of M5.begin() is different.
In the conventional M5.begin(), the content and number of arguments are different for each device library. In order to unify them, a structure is used as the argument.
See
M5.begin()
for details.
M5Atom and other RGB LED controls are not supported.
At the time of M5Unified v0.0.7, LED control of M5Atom is not supported. Please include and implement
FastLED library
separately.
Automatic mounting (SD.begin()) of TFCard (SDCard) is not done.
In order to support ESP-IDF, SD.h cannot be used by default and SD.begin() is not executed internally, assuming that SDFat is also selected in the library of available TF cards.
Graphics library changed from TFT-eSPI to M5GFX
The existing library had TFT_eSPI internally, but M5Unified depends on M5GFX and has been changed to use M5GFX. Note that the API is different.
For more information about the M5GFX library, please refer to
Getting Started with M5GFX
for the M5GFX library.
Speaker function
Core1 has noise in the sound, but it is an improvement over the previous library. Also, models with piezoelectric buzzers can play audio files, etc. as well as buzzers.
* Please be careful not to play loud audio files or low frequencies continuously at high volume as it may damage the speaker.
Difference in Button name
To make it common, the name is BtnA instead of Btn even if the model has one button.
error: reference to 'jpeg_div_t' is ambiguous jpeg_div_t scale = JPEG_DIV_NONE);
error: conflicting declaration 'M5Stack M5' extern M5Stack M5;
Parameters of M5.begin() are set by structure, and should be executed at the beginning of setup() function.
? >If you are a beginner, please write the following at the beginning of the setup function even if you use the default settings.
auto cfg = M5.config(); // Assign a structure for setup.
// Set the items you want to configure. Omit the following two lines if you use the default settings.
cfg.serial_baudrate = 115200;
cfg.output_power = true;
M5.begin(cfg); // start the device with the value you set.
See the following link for details.
Conventional M5.begin() has different contents and number of arguments for each device as follows.
// M5Stack
M5.begin(bool LCDEnable = true, bool SDEnable = true, bool SerialEnable = true, bool I2CEnable = false);
// M5Core2
M5.begin(bool LCDEnable = true, bool SDEnable = true, bool SerialEnable = true, bool I2CEnable = false, mbus_mode_t mode = KMBusModeOutput);
// M5StickC
M5.begin(bool LCDEnable = true, bool PowerEnable = true, bool SerialEnable = true);
// M5StickCPlus
M5.begin(bool LCDEnable = true, bool PowerEnable = true, bool SerialEnable = true);
// M5Atom
M5.begin(bool SerialEnable = true, bool I2CEnable = true, bool DisplayEnable = false);
The buttons available differ depending on the M5Stack product.
While button A is pressed, the message "BtnA isPressed." is displayed; when released, the message "BtnA isReleased" is displayed.
#include <M5Unified.h>
void setup() {
auto cfg = M5.config();
cfg.clear_display = true;
M5.begin(cfg);
M5.Lcd.setTextSize(2);
M5.Lcd.println("Press BtnA");
}
void loop() {
// update the button state.
M5.update();
if (M5.BtnA.isPressed()) {
M5.Display.setCursor(0, 16);
M5.Display.println("BtnA isPressed ");
} else {
M5.Display.setCursor(0, 16);
M5.Display.println("BtnA isReleased");
}
}
M5.update() must be executed to update the button state. Note that if there are more loops, M5.update() is needed for those loops as well.
#include <M5Unified.h>
uint32_t loop_count = 0;
void setup() {
auto cfg = M5.config();
cfg.clear_display = true;
M5.begin(cfg);
M5.Lcd.setTextSize(2);
M5.Lcd.println("Press BtnA");
}
void loop() {
M5.update(); // update the button state.
if (M5.BtnA.wasPressed()) {
M5.Display.fillScreen(TFT_BLACK);
M5.Display.setCursor(0, 0);
M5.Display.println("BtnA wasPressed");
M5.Display.println("Press BtnA Stop Count");
while (true) {
M5.update(); // update the button state within the subloop.
M5.Display.setCursor(0, 32);
M5.Display.printf("count: %10d\n", loop_count);
if (M5.BtnA.wasPressed()) {
M5.Display.println("Count Stop");
loop_count = 0;
break;
}
loop_count++;
}
}
}
The state of a button can be obtained with the following functions. Beginners should try using wasPressed() or wasClicked() first.
was
Detects if the state occurred before M5.update() was executed.
is
Detects if the state happened when M5.update() was executed.
Click
Detects if a click has been made.
longPressed
Detects a long press or release of a button with a specified time.
The number of times a button is clicked consecutively is added. The number of times can be obtained with M5.Btn.getClickCount()
.
M5Unified depends on M5GFX library and should be installed together if not already installed. (ArduinoIDE displays a dialog message when installing M5Unified; PlatformIO installs it automatically.)
For devices with a screen, the M5GFX API can be used with M5.Display. No definition is required.
To do HelloWorld on M5Unified, write the following code, which is the same source for both LCD and e-Ink Display devices. The same source code can be used for both LCD and e-Ink Display models, and can be used for M5Atom models as well, although the screen does not move.
#include <M5Unified.h>
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setTextSize(3);
M5.Display.println("HelloWorld!");
}
void loop() {
}
There are some differences in the API as well, but I have omitted the details.
Change from product-specific library headers to M5Unified.h
, and add SD.h
when accessing SD.
- #include <M5Stack.h>
+ #include <SD.h>
+ #include <M5Unified.h>
Change M5.begin() by executing M5.config() as follows
- M5.begin(true, true, true, true);
+ auto cfg = M5.config();
+ cfg.internal_imu = true;
+
+ M5.begin(cfg);
Change IMU processing to be accessed by M5.Imu.
Add SD.begin()
+ while (false == SD.begin(GPIO_NUM_4, SPI, 25000000))
+ {
+ delay(500);
+ }
If you want to use Port.A of M5Stack Basic/Gray/Fire etc. other than I2C, you need to run M5.In_I2C.release().
auto cfg = M5.config();
.
.
.
M5.begin(cfg);
M5.In_I2C.release();
If you change FactoryTest.ino, an Example of M5Stack, to M5Unified, it will be as follows.
diff --git a/src/main.cpp b/src/main.cpp
index b735e30..dae9b99 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,10 +1,10 @@
#include <Arduino.h>
-#include <M5Stack.h>
+#include <SD.h>
+#include <M5Unified.h>
#include <stdlib.h>
//#include "FastLED.h"
#include "WiFi.h"
-#include "utility/MPU9250.h"
extern const unsigned char gImage_logoM5[];
extern const unsigned char m5stack_startup_music[];
@@ -13,7 +13,8 @@ extern const unsigned char m5stack_startup_music[];
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
-MPU9250 IMU;
+
+#define SPEAKER_PIN 25
// #define LEDS_PIN 15
// #define LEDS_NUM 10
@@ -127,15 +128,15 @@ void writeFile(fs::FS &fs, const char *path, const char *message) {
}
void buttons_test() {
- if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) {
+ if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000)) {
M5.Lcd.printf("A");
Serial.printf("A");
}
- if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000, 200)) {
+ if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000)) {
M5.Lcd.printf("B");
Serial.printf("B");
}
- if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000, 200)) {
+ if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000)) {
M5.Lcd.printf("C");
Serial.printf("C");
}
@@ -475,8 +476,11 @@ void setup() {
// GPIO_test();
// }
+ auto cfg = M5.config();
+ cfg.internal_imu = true;
+
// initialize the M5Stack object
- M5.begin();
+ M5.begin(cfg);
/*
Power chip connected to gpio21, gpio22, I2C device
@@ -484,6 +488,10 @@ void setup() {
If used battery, please call this function in your project
*/
M5.Power.begin();
+ while (false == SD.begin(GPIO_NUM_4, SPI, 25000000))
+ {
+ delay(500);
+ }
// dac test
// if (gpio_test_flg)
@@ -492,7 +500,6 @@ void setup() {
// }
startupLogo();
// ledBar();
- Wire.begin();
// Lcd display
M5.Lcd.setBrightness(100);
@@ -609,54 +616,33 @@ void setup() {
M5.Lcd.setBrightness(i);
delay(2);
}
-
- byte c = IMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
- Serial.print("MPU9250 ");
- Serial.print("I AM ");
- Serial.print(c, HEX);
- Serial.print(" I should be ");
- Serial.println(0x71, HEX);
- Serial.println("");
- M5.Lcd.setCursor(20, 0);
- M5.Lcd.print("MPU9250");
- M5.Lcd.setCursor(0, 10);
- M5.Lcd.print("I AM");
- M5.Lcd.setCursor(0, 20);
- M5.Lcd.print(c, HEX);
- M5.Lcd.setCursor(0, 30);
- M5.Lcd.print("I Should Be");
- M5.Lcd.setCursor(0, 40);
- M5.Lcd.println(0x71, HEX);
- M5.Lcd.println();
- delay(100);
-
- IMU.initMPU9250();
- // Initialize device for active mode read of acclerometer, gyroscope, and
- // temperature
- Serial.println("MPU9250 initialized for active data mode....");
-
- // Read the WHO_AM_I register of the magnetometer, this is a good test of
- // communication
- byte d = IMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
- Serial.print("AK8963 ");
- Serial.print("I AM ");
- Serial.print(d, HEX);
- Serial.print(" I should be ");
- Serial.println(0x48, HEX);
-
- // M5.Lcd.fillScreen(BLACK);
- M5.Lcd.setCursor(20, 100);
- M5.Lcd.print("AK8963");
- M5.Lcd.setCursor(0, 110);
- M5.Lcd.print("I AM");
- M5.Lcd.setCursor(0, 120);
- M5.Lcd.print(d, HEX);
- M5.Lcd.setCursor(0, 130);
- M5.Lcd.print("I Should Be");
- M5.Lcd.setCursor(0, 140);
- M5.Lcd.print(0x48, HEX);
+ const char* name;
+ // run-time branch : imu model check
+ switch (M5.Imu.getType())
+ {
+ case m5::imu_t::imu_mpu6050:
+ name = "MPU6050";
+ break;
+ case m5::imu_t::imu_mpu6886:
+ name = "MPU6886";
+ break;
+ case m5::imu_t::imu_mpu9250:
+ name = "MPU9250";
+ break;
+ case m5::imu_t::imu_sh200q:
+ name = "SH200Q";
+ break;
+ default:
+ name = "none";
+ break;
+ }
+ M5.Display.print("IMU:");
+ M5.Display.println(name);
+ M5.Display.endWrite();
+ ESP_LOGI("setup", "imu:%s", name);
delay(1000);
+
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("wifi test:");
M5.Lcd.fillScreen(BLACK);