I optimize software for a living. This blog is to share some personal projects which others may find interesting.
M5Stack Core2 Review
Get link
Facebook
X
Pinterest
Email
Other Apps
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.
Intro Espressif Systems released their ESP32-S3 SoC a few years ago, but only recently have they released more documentation and support of its full capabilities. Without any changes to your code, the S3 runs about 15% faster than older ESP32 CPUs at the same clock speed. It has a 'hidden' capability that's more difficult to use, but can be worth the effort if you need more speed. This article is aimed at programmers who are already familiar with SIMD instructions on other platforms. I've been optimizing code with SIMD for more than 15 years on Intel, Arm and DSPs (even Cadence's), so when I heard that the S3 had SIMD instructions, I immediately went searching for documentation. When the S3 became available to buy, there was only a promise of documentation and support. In the 2+ years since then, not much has changed. At the end of 2023, Espressif released a document describing the new instructions: S3 Technical Reference Manual The document has a decent level of d...
Those little OLED displays are everywhere, and there's a good reason. They're inexpensive, easy to program and they look good. I wanted to explore how much current they draw so that I can plan better for battery powered projects. Questions I want answered: How much idle current is drawn when the controller is off versus on (blank display)? What's the minimum current to see text indoors? What's the maximum current when all pixels are on at their brightest? How does display size affect current draw? How does active data writing affect current draw? It's obvious they use more, but how much current do grayscale and color OLEDs use? How practical are OLED displays compared to common LCDs for battery powered projects? Materials: Cheap multimeter (manual scale, assumed accuracy +/-10% at worst) Various OLED displays (72x40, 96x16, 128x32, 64x32, 128x64-0.96", 128x64-1.3") Arduino compatible microcontroller ( Adafruit nRF52840 Feather Express ) ...
What The SSD1306 OLED displays are very popular with hobbyists due to their low cost and easy interfacing. The majority of the ones sold expose a two wire interface (TWI) aka I2C. The default speed for I2C is 100Khz and the "fast" mode is 400Khz. These are the 2 standard speeds supported by most AVR Arduinos. An I2C clock rate of around 800Khz is also possible on AVR MCUs, but not supported directly by the Wire library. The I2C standard recently added some higher speeds (1Mhz and 3.4Mhz). The 3.4Mhz version uses a slightly different protocol. At 400Khz, using the I2C hardware and the Wire library, I was able to refresh the display around 23.5 frames per second (FPS) with my code. Why I have already written a SSD1306 library for both Linux and Arduino, but I wanted to drive the display from an ATtiny85 and learn about the I2C protocol in the process. The ATtiny85 doesn't have I2C hardware built in, so it needs to be emulated in software using GPIO pins. There ...
Nice work! I'm looking forward to your finished emulator code :)
ReplyDeleteBrilliant, thanks for the write up!
ReplyDelete