Programming M5Paper and SCD40 as a CO₂ meter
I needed a CO₂ meter. I asked around for what to buy, and a friend said I should buy [a specific product with open hardware/software]. I tried to buy it, but the store’s checkout page stuck for me. If I am not allowed to buy a pre-programmed CO₂ meter, I thought, I should buy a CO₂ meter and program it myself. This thought is noted down for later.
A few days later, I stumbled upon https://m5stack.com/. Their modular hardware does not require soldering - a good fit for someone who doesn’t want to spend time thinking like me.
After navigating through their website (I feel mentally challenged during this process), I ordered:
- 1x M5Paper
- 1x prepackaged SDC40
Yesterday, the package finally arrived.
Day 1 - The Prototype
I followed the official Arduino development guide with arduino-cli. Then, it became obvious to me that the arduino-cli
rebuilds everything every time I issue a build command, so I ported the build system to Ninja.
At this point, I realized that I have no idea how to make I²C work myself, so I imitated code from an example working with SCD4X from SparkFun.
The result come out ok.
Here’s the “Arduino” code for this project: https://git.envs.net/iacore/m5stack-co2
I found a thin slice of laminated wood in a scrap bin. The “stick” is 1/5 of that (I broke it apart by hand).
The fridge is not in use.
Only the regions where the numbers are refreshed.
Still, one question remains: How do I make ESP32 sleep and be woken up by an I²C message?
Day 2 - Optimizing For Power Consumption
A day has passed. After at most 12 hours (I was sleeping) of running on battery, the battery has died with a charge of 2980mV (last frame displayed).
I don’t think I am using this industrial device correctly. It should sleep more.
One solution would be to plug the device into a power bank, or on wall power. I don’t want to do that just yet.
Here is the M5Paper Schematic. On the first page, it has a TOUCH_INT
pin on GPIO36. On the last page, near component J11, TOUCH_INT
is shown as indeed a pull up interrupt.
So, here’s the plan. We put the touch controller into sleep mode, and ESP32 into deep sleep mode (only wake up on interrupt). When the screen is touched, ESP32 wakes up and communicates with SCD40 to get a reading, then sleeps again. SCD40 seems to rely on periodic reading to calibrate itself, and I’m not sure if this mode of operation will make it less accurate. Well, I only need an output granularity of 100ppm.
Well, that was the idea until I realized that the M5EPD library comes with a method to switch the ESP32 off and turn it back on with RTC - that’s deeper sleep than hibernation; no interrupts available here. So I quickly set the device to wake up every 5 minutes, measure CO₂ density once, display the info, then sleep.
The simple solution worked out ok. I also made the font bigger in the meantime.
There is slight ghosting (background not entirely white), since I skipped initializing the E-ink display.
I have a CO₂ meter now! Yay! Yay?
Musings
Unexpected benefit for sleep-only software: pressing the power button gives me an immediate (not immediate, it takes a few seconds) reading.
The touch controller and the E-ink display are two separate devices. This is a bit surprising to me.
The M5EPD library is of higher quality than the Arduino core library provided by Espressif.
The Arduino implementation provided by Espressif runs on FreeRTOS. There is one place in the project where I could have used a callback and semaphore instead of a busy wait. Maybe I should learn FreeRTOS.
My homebrew CO₂ meter is cheaper than the open hardware one that I failed to buy.
Acoustic cryptanalysis is real. The M5paper whines when being powered on (sounds like voltage regulator). I have to put my ear to it to hear the sound, and there is difference in sound emitted. When the E-ink display refreshes, it gives another sound.
The xtensa ISA has sliding registers. With that said, this project is coded in C++, so it probably does not benefit from the architecture-specific fun™.
Day 4 - a more legible font
Staring at pixelated text hurts my object recognition, so I changed the font to a saner one.
It’s still not immediately legible. I could have used a better overall design.
Day 8 (2024-07-25)
The battery has died after 4 days of use without recharging.
Side note. Because how M5Paper’s circuit is designed, it can’t turn itself off while on external power.
Day 14 (2424-07-31)
I had the following Ideas to increase battery life.
- Use FreeRTOS properly. No busy loop.
- Use a larger battery. The stock battery is 1150mAh@4.35V.
This teardown video shows that a battery with a larger form-factor may not be possible. - I see people on the M5stack forum complains about battery usage too.
So I had the idea of only powering the EPD when it need to be refreshed. It worked! Now the display is only powered for 700ms instead of ~3s every time the device wakes up. The 3s is for the SCD40 to initialize and produce a reading.