M5Stack Core2 Review

Intro

MakerFocus was kind of enough to send me a M5Stack Core2 to review. This is the latest ESP32 based 'core' product in their ever growing lineup. I'm not a big fan of unboxing videos, so I'm not going to spend time on this subject except to say that the packaging of the Core2 is well made.

After cutting a small piece of adhesive, you can slide the plastic sleeve off of the box. Inside is the Core2 along with a short USB-A to USB-C cable. The box you'll want to keep because it's perfect to protect the Core2 when not in use. 

For those not familiar with Espressif System's ESP32, it's a line of highly capable MCUs based on a pair of Tensilica LX6 CPUs along with various amount of RAM, optional PSRAM and FLASH memory. The ESP32 has found its way into a large number of products mainly due to its WiFi and Bluetooth support. Many products use it as a subordinate processor just for its wireless support, but with 2 240Mhz CPUs, and 520K of RAM it's very capable to do many jobs on its own.

M5Stack is a prolific creator of fun and useful 'maker' products which revolve around the ESP32. Their main product for the last couple of years has been their 'core' module along with various accessories which stack on top of it. The target audience are hobby and professional IoT makers who program the devices using C++ in the Arduino environment or higher level languages like Python. The latest version of their core module, the Core2, is packed with sensors and useful components which provide a compelling starting point or a complete solution depending on your needs. Here's what's inside:

Processor:    ESP32, FLASH: 16MB, PSRAM: 8MB, RAM: 520KB
microSD slot
Display: 320x240 ILI9342 SPI IPS LCD, capacitive touch input
IMU: MPU6886 6-DOF accelerometer + gyroscope
RTC: BM8563 plus backup battery
Power: USB-C, 390mAh LiPo battery, AXP192 Power management chip
Audio: NS4168 I2S decoder + 1W Amp + speaker, SPM1423 Microphone
Misc: Vibration motor,  Green LED
Expansion: I2C GROVE connector, 30-pin expansion bus

This collection of components comes wrapped in an attractive plastic case with smooth edges. It's sold as an IoT 'kit', but it's really a finished product that can do quite a bit with the right software. In fact, I'm evaluating it for use in a medical office.

Power On

When you power up the device for the first time, you'll be greeted by its "Factory Test" Arduino sketch. The program demonstrates its various capabilities with an attractive touch GUI. You can find the source code here: FactoryTest 

I'm not going to dwell on this code because it's just a demo, but I definitely appreciate that powering up the device for the first time shows you clearly that all is working.


My Project

I used to write game emulators for my day job, so I find it fun to port my code to run on different platforms. I decided to try getting my GameBoy Color code to run well on the Core2. There were a few things I needed to figure out first:

  • How to get the pixels onto the display as fast as possible
  • How to output audio
  • How to connect gaming controls

Fast Pixels

The majority of LCD displays connected to MCUs make use of the SPI (Serial Peripheral Interface) bus. This is convenient due to its standard interface and simple connections, but presents a bottleneck for gaming. That's the case here. The ESP32 can send data to the SPI bus at up to 80 Mbs (mega bits per second). One limitation is that the LCD display might not support that speed. In the case of the Core2, the LCD display can only handle a top speed of 40Mbs. At that speed, doing full screen gaming at 60fps is not possible. The best possible frame rate for full screen graphics is:
40,000,000 / (320 x 240 x 16bpp) = 32.55 FPS

Here's where I made a compromise. I didn't want to reduce my frame rate goal, so instead of filling the display, I decided to run my Gameboy emulator (160x144 pixels) at 1:1 so that it doesn't fill the display. The next problem is that in order to run at that speed, the SPI bus is busy nearly 100% of the time. If the CPU is busy writing the pixels, then that doesn't leave time to run the game code or generate audio. Luckily there's a way around this...

DMA is an acronym for Direct Memory Access. This is a MCU feature which allows it to send memory contents to another part of memory or a peripheral in the background while the CPU does other work. In this case, my program calculates each line of the game's graphics at the same time the previous line is being sent to the LCD. The ESP32 API for using DMA is relatively easy to configure so this worked without much experimentation.

Audio

This project was helpful to introduce me to I2S (Inter-IC Sound). This is a serial bus similar to SPI which is used to generate high quality audio. The Core2 has an internal I2S decoder and amplifier. To generate sound, the ESP32 must send I2S data to the NS4168. Luckily Espressif wrote a very simple API for managing I2S audio. The audio API provides a simple mechanism to deliver audio buffers asynchronously and it will manage a steady flow of data using DMA. This is perfect for games since there can be variable latency between each frame depending on the complexity of the game at that instant. By keeping track of a round-robin collection of audio buffers, your code can write audio on an unpredictable schedule and it will sound good as long as you don't allow all of the buffers to become empty.

Gaming Controls

The Core2 does have capacitive touch input, but that's not always the best choice for gaming; I wanted to use controls with a traditional feel. I don't have much on hand, but I do have an old SteelSeries:Free that I wrote an Arduino library for. This controller is small, but comfortable to use and makes use of a simple RFCOMM bluetooth protocol which is compatible with the ESP32 default BT support.

Here's the finished project - it's able to read games off of the microSD card, store them in PSRAM and use the faster RAM to hold the game emulator data.


One of the challenges I encountered was that reading the game cartridge into PSRAM would cause the ESP32 to crash with a "LoadProhibited" exception. It didn't make any sense to me because I was accessing the memory correctly. On a hunch, I tried accessing the PSRAM starting at the 1MB mark (there are 4MB of PSRAM). That ended up working. It may be a defective PSRAM chip or some other issue, but at least I got it working. The code is not ready to share because I'm in the middle of rewriting my bb_spi_lcd display library which it depends on. This project is based on my open source Gameboy emulator SmartGear Free.

Conclusion

The Core2 offers a ton of functionality in a slick package for a fair price. It has enough built-in sensors and components that it should satisfy quite a lot of project needs without having to add anything. I give this device a hearty thumbs-up. M5Stack has created an ever growing collection of innovative kits and it looks like they're not slowing down any time soon.

Comments

  1. Nice work! I'm looking forward to your finished emulator code :)

    ReplyDelete
  2. Brilliant, thanks for the write up!

    ReplyDelete

Post a Comment

Popular posts from this blog

Building the Pocket CO2 Project

How much current do OLED displays use?

Fast SSD1306 OLED drawing with I2C bit banging