The M5Stack is a modular open-source toolkit for developing IoT applications. It is based on an ESP32, which is the core module and there are a lot of stackable modules that you can use for different projects. This enables to do rapid and high-quality prototyping!
You can program the core device using the ESP-IDF framework, the Arduino-IDE, Blockly or MicroPython. Unfortunately, the BLE is still not available using the official M5Stack MicroPython firmware (forked from LoBo). However, flashing the ESP32 with the official MicroPython version built with the ESP-IDF v4.x enables the BLE module and it is possible to send and receive data to/from the M5Stack.
This article is a quick tutorial for flashing the MicroPython official version on the M5Stack. Additionally, I've included a project example that uses the BLE module to send the data of the IMU and the buttons' states and to receive a variable value in order to switch on/off the display.This tutorial focuses on the M5Stack-Fire. However, it can be used with every ESP32 boards that are available on the market. With some modification (sensors' or buttons' pins), the example application can run on different ESP32 boards. However, you should use boards that have pSRAM. Otherwise, the boards only have 512kB RAM, which will be a problem for the BLE Stack and you'll get an "out of memory" error. Some boards are listed here.
Hardware and Software
In this article, the following hardware and software are used or recommended:Note (*): You need the M5Stack Fire! There are cheaper versions (for example, Basic, Gray, M5Stick), but the RAM is only 512kB on those models, and therefore they will not work well with MicroPython. The following figure shows a summary of the differences between the M5Stack CORE models:
As I mentioned, you need to download the official version of MicroPython. You can compile it yourself, or you can download a pre-compiled firmware and flash it on your M5Stack-Fire.
Flashing a pre-compiled Firmware
This is the easy way to get the official version of MicroPython on the M5Stack. However, you get only what you download. So you cannot extend the version or freeze any new module.
If you are not familiar with Linux, this is your best option:
- Go to the MicroPython download website
- Download the firmware built with ESP-IDF v4.x (GENERIC-SPIRAM for the M5Stack Fire). There are two versions: a stable one, and a nightly release. You can choose one of them.
- Flash the M5Stack-Fire using the esptool.py tool and the following lines:
esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32spiram-idf4-20191220-v1.12.bin
If you are flashing this version of MicroPython on the M5Stack for the first time then you should first erase the entire flash. In that case, you need the first line of the code above.
- Use VSCode and the PyMakr extension to upload and run code on the M5Stack.
If you want to compile your MicroPython version from scratch, follow these instruccions:
- Install pre-requirements:
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache libffi-dev libssl-dev
Download the ESP-IDF framework:
mkdir ~/esp/ cd ~/esp/ git clone https://github.com/espressif/esp-idf.git cd esp-idf git checkout 310beae373446ceb9a4ad9b36b5428d7fdf2705f ## the above hash is defined by the variable ESPIDF_SUPHASH_V4 in the file: # https://github.com/micropython/micropython/blob/master/ports/esp32/Makefile git submodule update --init --recursive ## if you don't clone the submodules (recursive) # you'll get the following error while compiling MicroPython: # xtensa-esp32-elf/bin/ld: cannot find -lrtc
- Download and install the toolchain:
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz cd ~/esp/ tar -xzf ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH" export IDF_PATH="$HOME/esp/esp-idf" ## Don't use the install.sh option, it didn't work for me and # I got a lot of errors while compiling MicroPython
Clone MicroPython and compile the cross-compiler:
git clone https://github.com/micropython/micropython.git cd micropython/mpy-cross make cd ../ports/esp32
Modify the setup to include support for BLE on the SPIRAM board version (with pSRAM):
nano boards/GENERIC_SPIRAM/mpconfigboard.mk ## boards/GENERIC_SPIRAM/mpconfigboard.mk # add the following line at the end SDKCONFIG += boards/sdkconfig.ble
- Select the board version with SPIRAM:
- Compile the submodules and MicroPython:
make submodules make
- Flash MicroPython on the M5Stack, which should be already connected to a USB port:
Freeze modules on MicroPython
As I mentioned, you can freeze modules and include them in the firmware. This reduces the memory use on MicroPython and makes your code faster. To do that, copy the module files that you want to freeze into
micropython/ports/esp32/modules. Then, repeat step 7 and 8. You should see something like this:
Use make V=1 or set BUILD_VERBOSE in your environment to increase build verbosity. Building with ESP IDF v4 MPY ili934xnew.py GEN build-GENERIC_SPIRAM/frozen_content.c CC build-GENERIC_SPIRAM/frozen_content.c LINK build-GENERIC_SPIRAM/application.elf text data bss dec hex filename 1151395 269960 46244 1467599 1664cf build-GENERIC_SPIRAM/application.elf Create build-GENERIC_SPIRAM/application.bin esptool.py v2.8-dev Create build-GENERIC_SPIRAM/firmware.bin bootloader 22528 partitions 3072 application 1421488 total 1487024
In this case, the display driver (
ili934xnew.py) was included. The module is compiled (MPY) and added to the MicroPython firmware as a frozen module. Then, you don't need to upload it using the PyMakr extension and you can import/use it as usual. In the example case:
from ili934xnew import ILI9341, color565
Fonts files and drivers are good candidates for this procedure.
I've published an application example on GitHub, clone it using the following:
git clone --recursive https://github.com/lemariva/uPyM5BLE.git
The uPyM5BLE application reads the data from the IMU (accelerometer, gyrometer, magnetometer, and temperature sensors) and the buttons' states. The application then publishes them as different BLE characteristics (GATT) (see Fig. 1). Additionally, it offers a writeable variable to switch on/off the M5Stack display (see Fig. 2). Thus, to summarize, the following data is available:
- 3-axis accelerometer - 3 shorts & accuracy 0.01g,
- 3-axis magnetometer - 3 ints & accuracy 0.01uT,
- 3-axis gyroscope - 3 ints & accuracy 0.01°/s,
- Temperature sensor - 1 short & accuracy 0.01°C,
- Button A, B and C states.
To see the BLE device, read and write data, you can use the BLE Scanner application.
Fig. 1: BLE Scanner Application - Reading data from the M5Stack Fig. 2: BLE Scanner Application - Writing a variable value
Additional information about the
ubluetoothmodule can be found here. And, as it is mentioned in the documentation, on the ESP32, the MAC address is random and will be generated when the BLE interface is activated. So you can use the BLE Scanner application to find the device MAC address as shown in Fig. 3.
Fig. 3: BLE Scanner Application - Getting Device MAC address
This tutorial helps you enable the Bluetooth module on an M5Stack-FIRE running MicroPython. The M5Stack official version still doesn't include that option. If you want to send data over Bluetooth, you need to flash the MicroPython official version built with ESP-IDF v4.x. The article explains two ways to achieve this and includes an explanation to freeze modules in order to reduce RAM use on ESP32. Furthermore, an example is included, in which readable and writeable variables are listed. The IMU data and the buttons' states are sent over BLE and the display can be controlled writing a variable. The BLE Scanner application is used to see the device and interact with the data.