Building an IoT sensor
I've always been interested in not only software, but hardware too. Learning has been very slow, because I don't put much time into it. Some years ago I started to play with self build IoT sensors and I'm finally at the point where I like the result.
In the beginning I mostly used platforms where you could buy a micro-controller and extensions boards (shields) manufactured by the same vendor. This makes it really easy to start, because it requires no soldering, the design is known to work, and there are many code examples.
My first attempt at building temperature and humidity sensors that run on battery was made with Wesmos D1 minis. Originally, they were using ESP8266 micro-controllers. They have the benefit of being very cheap, integrating WiFi and you can program them using the Arduino IDE. They also had ready made shields with DHT22 temperature sensors and shields that allowed you to power them using LiPo batteries, even including a charging circuit for the batteries. I quickly discovered that they would only run on battery for some days though, even if the ESP was in deep sleep most of the time. I tried to understand the circuit schema and discovered that it was probably converting the battery voltage to 5V first and then back down to 3.3V which I guessed was wildly inefficient.
So I decided, that in order to have an ESP run on battery for a year or more, I would need to build my own board. My first attempts were still done using ESP8266, since I already had them and ESP32 were not more power efficient. I prototyped on bread boards, using a MCP1700 low dropout (LDO) voltage regulator with a very low quiescent current, which means two things that are important to me:
- Low dropout means the input voltage does not need to be much higher than the output voltage. Since the voltage of a LiPo battery is continuously dropping from ~4.2V to ~3.6V while it's discharging, even if the battery is becoming empty and its voltage is low, it will still be sufficient for the LDO to produce the desired output voltage of 3.3V
- Low quiescent current means that the LDO itself doesn't use much power by itself. Even when the micro-controller is in deep sleep and drawing less than 10µA of current, the LDO itself will also draw some current. I want this to also be in the range of a few µA, otherwise its power usage would dominate and putting the micro-controller to sleep would not help in prolonging the battery life.
It generally worked fine using a power supply like USB, but I couldn't measure my power consumption well and as soon as I tried to power it using a battery, it stopped working. I assumed that the connection between the components on the breadboard wasn't great and that having everything on a PCB might make it work. This was a mistake, as we will see ...
So I set out to learn how to design PCBs using KiCad. It's not terribly difficult, but it takes a bit getting used to the short cuts. My biggest confusions were around were and when to use which resistor and which capacitor. If you really learned electrical engineering and circuit design, you probably know, can calculate and have an intuition regarding this question, but they way I got through it is mostly by looking at existing schemas that were similar enough to what I wanted to do, looking at the specification sheets of components (like the LDO) and asking a friend.
Two years ago I had my first design I could get manufactured. I ordered it on Aisler since they are cheap enough, you can just upload a KiCad project (no messing around with Gerber files) and shipping in Germany is quick. Last year I soldered it using the reflow soldering oven in our maker space. I had two slightly different ESP32866 boards I used and I think only one of them ended up actually working. Also, I remember having forgotten to connect the reset PIN to the signal PIN of the built in real time clock, so the wake up from sleep wasn't working until I added a messy fix with a pice of wire.
At that point I realized that by continuing to use the ESP8266 I might make my life a bit harder than necessary, so I switched to ESP32, specifically C6 variants. They have built in USB support and if you add it to you board you can even program the ESP using USB. They don't need extra connections to make wake up from deep sleep work, and best of all, I could program them in Rust 😄 Furthermore, I was hoping to eventually use Zigbee (or Bluetooth) as a wireless communication protocol, which might use less power than WiFi and is not supported by ESP8266 chips.
The principal design of the board remained the same, but I went through some iterations, adding and removing connections for the UART TX/RX pins, exposing USB as a pin header only, vs adding a proper socket, and fixing some design issues. The two biggest mistakes I made were
- Using the through-hole variant of the MCP1700 in the circuit schema and then assigning the SMD footprint. Unfortunately, the numbering of the pins is slightly different between the through-hole variant and the SMD variant. It cost me quite a while to realize the mistake, because surprisingly, the board still worked! Instead of regulating the USB 5V to 3.3V, the LDO probably worked like a really expensive resistor and dropped the voltage to 4.6V, which the ESP32 happily accepted, and even the BME280 sensor seemed to work fine. This is very much out of spec! 🤯
- I forgot one connection completely. Whenever I was happy with the design, I would run the design rule check to verify that I didn't make any mistake. I realized too late, that a missing connection is shown in a separate tab, that I never bothered to check ... So the BME280 sensor wasn't working in one design, and I had to redo it ...
After fixing these issues, I arrived and the current iteration of the board, which almost works. I was able to program it using Rust, the code is on GitHub. Both the variant using only the main core and using the low power core seem to work. Unfortunately, if I try to sent the measurements via MQTT (WiFi) the ESP reboots 😭
I immediately suspected that the power supply wasn't sufficient. This time, instead of just guessing, I pulled out the cool gear we have and started testing. From reading about similar problems online, it probably was a so called brownout, which as far as I know just means that the voltage of the power supply drops until it's too low for your micro-controller. Some micro-controllers can actually detect that, reset themselves and report it during the next boot, but if I remember correctly, my ESP32 didn't.
So first I used an oscilloscope, to see what's happening to the voltage during the reset. Someone from the FabLab was kind enough to help me configure it correctly. Most important was to configure the trigger, which is the condition the oscilloscope will use to detect the start of the "signal". For me that meant a sharp drop in voltage, because that's what I expected to see. Et voilá, I was able to exactly detect that, a sharp drop in voltage, followed by a rise to the 3.3V I want.
The most plausible reason for the power to drop would be that the ESP suddenly draws much more power (or current at a fixed voltage) than the power source can supply. For me that probably meant more than the voltage regular can supply, since my power source should be able to supply enough but the LDO had a rating of up to 250mA. To verify this, I used the Nordic Power Profiler we have at the lab. As I expected, you can see the current rising, which correlated with the logs is the time when WiFi transmission starts. Then there is a sudden spike before it breaks down, which is when the ESP resets.
My first conclusion was that the ESP32 really just consumes more power for WiFi than what is stated in the specification, and that using the MCP1700 would have never worked, even on a PCB. I set out to find a better LDO, but quiescent current of <10µA, drop out of <0.2V and current of >400mA is really not possible it seems (except if the quiescent current is measured when the LDO is "off", but then, how would I turn it on again?). I read about the antenna overlapping the the PCB causing higher power consumption which made me realize, that I could do the same test with the ESP32-C6-DevKit before I try another LDO. So I did just that, and what do you know, while it has the same current spikes, they only reach to roughly 300mA. Looking at the schema of the DevKit again, they use two 10µF capacitors with the input and output of their LDO, which is more than what I had so far. Maybe bigger capacitors and an antenna that does stick out of the PCB helps?
Back to the drawing board for another round of schema and PCB design! I will report again when I made some progress 🙂
More blog posts
Building an IoT sensor
I've always been interested in not only software, but hardware too. Learning has been very slow, because I don't put much time into it. Some years ago I started to play with self build IoT sensors and I'm finally at the point where I like the result.
Building a smart speaker
Some years ago I built a small speaker together with a friend. It is set up as a speaker for Spotify and still in use.
Weekend in Paris
A week ago we've been to Paris. We only where there for the weekend and on Monday, but we still saw a lot.
Crete Vacation
This summer we were on Crete for vacation. I've been learning a bit about photography and my Sony Alpha 6000 lately, and took the opportunity to practice while on holidays.
Hiking the first part of the Eifelsteig
Some days ago we went hiking and started with the first stages of the Eifelsteig. There is a bus that drops you of right at the start in Kornelimünster, which is very convenient.