Using the ESP32 MCU
Switching power supplies are a key piece of gear for many projects. But cost-effective units benefit from some kind of outside means of stepping output voltage up or down. To address that issue, Anuj built a power supply monitoring and control system using an ESP32-based development board.
Power supplies are essential for various electrical or electronic experiments. Switching mode power supplies (SMPS) act as a very good source of DC electrical power with high efficiency for various applications. The regular cost-effective ones have a minimalist design and constant output voltage. Such units often need to have their output voltage stepped down or stepped up depending on the devices that the supply is powering. I bought one such SMPS but wanted more control over the power output—like voltage control and configurable over current protection—while also being able to monitor the state of the output power. With all that in mind, I built a power monitoring and control system with a TTGO-T-Display ESP32 Wi-Fi/Bluetooth module development board from LILYGO . The system has an onboard display and an Espressif Systems’ ESP32-D0WDQ6 microcontroller (MCU) chip  as its processing unit. The block diagram of the system is shown in Figure 1.
The prototype uses ESP-IDF (Espressif’s IoT Development Framework) , which is the official software development environment supported by Espressif for hardware based on the ESP32. It has native support for developing firmware with FreeRTOS. The entire code for the system was written in “C” using the libraries and APIs provided by the development environment. For me, this was an adventurous, but well-guided experience because it involved using a real-time operating system (RTOS) that requires particular coding standards. The system is designed to give a guaranteed response in case of overload, which greatly improves the reliability of the entire system.
It’s essential to start with a constant output voltage DC power supply. That serves as the primary source of power for both the onboard electronics and the devices powered through the prototype. The input power from this power supply to the rest of the system can be disconnected by repositioning the jumper cap (JP1). The entire schematic diagram of the circuit used for building the system is shown in Figure 2. The list of components can be found in Table 1.
The step-down voltage regulator circuit was developed using Texas instruments’ (TI’s) voltage regulator LM338T in ‘“regulator and protection diode mode.” This mode is detailed in section 220.127.116.11.3 of TI’s “LM138 and LM338 5A Adjustable Regulators” datasheet . The mode has input, adjustment and output terminal bypassed to ground with capacitors to achieve ripple rejection close to 75dB. The variable resistor connecting the adjustment terminal of LM338T to ground for varying the output voltage from this regulator is achieved by using two of the three terminals available in a typical 1kΩ-rated rotary potentiometer. Heat dissipation is facilitated using a heatsink with thermal pad in between to further improve thermal conductivity while electrically isolating the heatsink from the case of LM338T. This prevents accidental and undesired contact with the output of the regulator.
The power sense unit consists of an INA219B power monitor sensor  from TI in a breakout board. It is used to measure the voltage and current values of the output electrical power and communicate them to the processing unit using I2C protocol. The output power switch unit consists of a mechanical electromagnetic relay with flyback diode, whose inductive coils are driven by a 2N3904—an NPN transistor controlled by the processing unit. This relay is used to disconnect the output electrical power when needed.
The momentary switch (from here on called the trigger), display and the processing unit are used for interfacing with the user through the custom graphical HMI developed in ESP-IDF. This interface is nicknamed a “one button interface.” This graphical HMI has multiple menus with options to freeze the display, set maximum voltage limit and much more. It can be accessed as described in Table 2, with selection done using only the trigger. The processing unit is the primary brain of this entire system. It is responsible for interacting with the user, collecting the measured value from the sensor using I2C protocol, controlling the output power switch and driving the display with a Sitronix ST7789V driver through a serial interface.
The entire prototype can be seen in Figure 3. It’s designed on a single perfboard with the ESP32 development board and INA229B power monitor sensor connected to the board through header pins. Meanwhile the rest of the components are directly connected to the traces of the board through soldering. Some additional components such as resistors, capacitors, diodes, wires, jumper caps, jumper links, screw terminals and Dupont connectors were used in the project. The onboard electronics are powered by a L7805CV fixed voltage regulator from STMicroelectronics (ST) with the input and output terminals bypassed using capacitors, and connected with a diode to protect the regulator from transient voltages.
OPERATING THE PROTOTYPE
The user interacts with the graphical interface of the prototype using the trigger (SW1) and controls the output voltage from the step-down voltage regulator using the rotary potentiometer (RV1). The prototype is first connected to the DC power supply using wires with butt crimp terminal connectors. Note: You could instead just use a wire between the terminals of the DC power supply and the prototype. The reason for the connectors is to make an easy switch between multiple power sources or to quickly disconnect the power source from the prototype in times of failure. The jumper cap (JP1) is placed to allow the flow of input power. The reset button on the ESP32 development board is pressed to start executing the firmware.
The display then shows the current status of electrical output such as voltage, current and power as numerical values and in a graph format, which is updated every subsecond. The display also shows the current status of the output power switch as “ON” or “OFF.” When OFF the display shows as “POWER OFF” in the middle right of the screen. But when ON, the display shows the maximum values of voltage, current and power that can be measured in the present settings, as shown in Figure 4. Operating beyond these maximum values will cause the output power switch to automatically turn OFF with an error message that will be displayed on the screen as shown in Figure 5.
The required output voltage is set by rotating the shaft attached to the wiper of the rotary potentiometer (RV1), whose values can be confirmed on the display. Once confirmed, the device that needs power can be powered by connecting its power input terminals to the output power screw terminal (J2) using wires. In my case, I used a female butt crimp terminal to terminate the wires connected to the J2, so that it can be either connected to a device with male butt connector or can be used to power other devices with a male banana connector to a crocodile clip wire with silicone insulation—not perfect, but works great. Now the prototype can be summoned to power the connected device using the trigger as shown in Table 2.
The graph contains all three quantities of the electrical output: voltage, current and power. These are plotted in the same area (roughly the bottom half of the screen), only separated by color as shown in Figure 6, with the hex triplet #ff3300 for voltage, #808000 for current, #990033 for power, #BFD980 when voltage and current covers same number of pixels along the Y-axis and #CC1999 when voltage and power covers the same number of pixels along the Y-axis. It shows #8CC019 when current and power covers the same number of pixels along the Y-axis and #AC6CD9 when voltage, current and power cover the same number of pixels along the Y-axis.
The X-axis represents time with a common scale of 1 pixel = 250ms, while the Y-axis has a different scale for each quantity, dictated by the maximum value setting for that particular quantity such that this maximum value coincides with the maximum number of pixels displayable along the Y-axis. Currently, the X-axis (time) scale has no options in the graphical HMI to adjust it. However, this maximum value (hence the Y-axis scale) is individually adjustable through the graphical HMI as shown in Table 2 for all the three quantities.
The firmware executed by the processing unit is responsible for displaying graphical information on the IPS display driven by ST7789V, collect electrical power measurements from INA219B power monitor sensor, receiving and responding to user input from the trigger and controlling the output power switch to turn the output power ON or OFF.
The overall flow of the firmware is shown in Figure 7. The firmware initiates the serial peripheral interface of the processing unit responsible for communicating with the ST7789V display driver and the driver itself, followed by the initiation of I2C interface for initiating and communicating with the INA219B power monitor sensor. Next, the corresponding GPIOs are initialized for receiving user input from the trigger and controlling the output power switch through 2N3904, an NPN transistor. Once the initialization is completed, four tasks are created using the
xTaskCreate() function for managing the initialized interfaces, namely the
st7789v_routine for managing display,
hmi_routine for managing the trigger,
ina219_routine for managing the INA219B power monitor sensor, and
power_control_routine for managing the output power switch. The tasks communicate with each other through the
xTaskNotify() function. Some of the important system configuration settings are defined in
st7789v_routine task initiates the local variables holding the display settings and enters the superloop waiting for incoming notification from the tasks
hmi_routine. If no notification is received from any routine within 300ms, a notification is sent to the
ina219_routine to notify that no data has been received yet. Although the display receives data from the
ina219_routine task every 250ms under normal operating conditions, it only updates the numerical values in the display every 0.75 seconds for readability. The graph is updated as the data is received—in other words, every 250 ms. If any notification is received from either of the tasks, the display is updated followed by an acknowledgment notification, which is sent to the corresponding task. The flowchart for this task is shown in Figure 8.
e hmi_routine task initiates the local variables and enters the superloop which scans the input from the trigger for every 100ms. When an input is received, the task assesses the input based on the trigger press, hold and release timings as shown in Table 2. It then sends the appropriate notification to the
st7789v_routine task and/or the
power_control_routine task and repeats sending it for every 100ms until it receives an acknowledgment notification from the corresponding tasks. The flowchart for this task is shown in Figure 9.
ina219_routine task reads data from the INA219B power monitor sensor once every 250ms and assesses if the current user settings for maximum voltage, current and power values are met. If the output electrical measurements from the sensor exceeds the user set threshold, then protection mechanisms kick in by notifying the
power_control_routine task to turn OFF the output and repeat the notification every 100ms if an acknowledgment for the same notification is not received, followed by a notification to the display for the same event. If the output electrical measurements from the sensor are within limits, a notification is sent to the
st7789v_routine task stating that new data is available for the display.
When a user tries to update the maximum value through the graphical HMI, the
hmi_routine task sends a notification to the
st7789v_routine task. The
st7789v_routine calculates the new maximum values, updates the display and relays it to the
ina219_routine task, which then collects and updates the maximum values used for internal comparison as discussed earlier. If, for some reason, the
ina219_routine task could not communicate with the INA219B power monitor sensor, it notifies
st7789v_routine task and tries to re-establish communication once every 100ms until it establishes communication with INA219B power monitor sensor. The flowchart for this task is shown in Figure 10.
power_control_routine task receives notification from both the
hmi_routine task and
ina219_routine task with regards to turning ON or OFF the output power switch and acknowledges the notification received by sending an acknowledgment notification to the corresponding task. It turns OFF the output power in case the
ina219_routine task kicks in the protection mechanisms (logical) or if the user intends to turn it off. The output is only turned ON if the user intends to turn it ON (logical) and the protection mechanism from the
ina219_routine task deems it to be safe to do so. The flowchart for this task is shown in Figure 11.
FIRMWARE AND TESTING
The firmware for this prototype was developed in C with FreeRTOS support provided by the ESP-IDF. Head to the get started information at , which has information on setting up the ESP-IDF environment for Linux, Windows and MacOS users in a few simple steps. Once the environment is set up, connect the processing unit to the computer using a USB type A male to USB type C male cable and download the code for this prototype.
Open the command prompt and enter the parent directory containing the code using the cd command. Now execute idf.py build to compile the code for ESP32. Once compiled, execute idf.py -p PORT flash, where “PORT” is the name of the serial port to which the ESP32 development board is attached. Voila! The processing unit is now ready to execute the target firmware for our prototype.
Caution: While the processing unit on the prototype is connected to the USB, the power from the USB port routed through the 5V pin of ESP32 development board followed by the diode D1 is enough to operate the entire prototype for pilot testing the firmware. But be careful not overload the output power from the prototype because the power from USB is limited and might cause damage to both the ,ESP32 development board and the USB port or the motherboard of the PC. Personally, I was able to light a single LED from the output power of the prototype using a USB2.0 port’s power as input, but the closed-circuit voltage which is displayed on the screen hardly rose above 3.2V.
One of the interesting features of the prototype is the over-current protection. I personally like to optimize the input voltage required for powering an LED to achieve the required brightness at as low power as possible. During these experiments, I often tend to unintentionally overshoot the input voltage and find the LED burning out due to over current. With this prototype, such incidents have reduced to zero. And it is very easy to estimate and monitor the power consumed in real-time. It also helps to identify the resistance of the load resistor using the voltage and electric current data displayed on the screen.
The prototype is designed in such a way that it can operate only with the step-down voltage regulator using the additional onboard options to bypass the output power switch driver, thus giving the prototype a failsafe design. But when operating with the processing unit under normal conditions, the output power switch is turned ON only if the inductive coils of the relay switch are powered, thus making sure the output is not turned ON unintentionally when the firmware is not operating or if the ESP32 development board is removed from the socket.
Adding a fuse to the design can act as a redundant safety mechanism because there already exists short circuit safety mechanisms built into the voltage regulator ICs. The system can handle a maximum output voltage of 26V limited by the INA219B power monitor sensor and maximum input voltage of 35V limited by the L7805CV.
The maximum current output is limited by the traces and the shunt resistors on the breakout board on the INA219B power monitor sensor, which, in my case, is 3.2A. However, if the breakout board allows, the system can be pushed to the maximum of 5A limited only by LM338T adjustable voltage regulator. I tested the system on an approximately 14V constant voltage output AC to DC SMPS as input power and with a maximum open circuit output voltage of around 12.5V. Also, make sure if the cross-sectional area of the wires, jumpers, traces and other conductors are large enough to carry the required amount of electric current over the required length of the electric current’s path.
Note from Rajappa: My thanks to my co-author Dr. Vairamani Kanagavel for investing his time and effort in reviewing and formatting this article before submission.
 ESP32 development board description, Link
ESP32 development board schematic diagram, Link
 ESP32 Series datasheet, Link
 ESP-IDF Programming guide, Link
 LM338T datasheet, Link
 INA219B power monitor sensor datasheet, Link
INA219 DC Current Sensor Breakout board schematics, Link
 Sitronix ST7789V driver https://www.sitronix.com.tw/en/products/display-driver-ic
 L7805CV datasheet, Link
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • OCTOBER 2021 #375 – Get a PDF of the issueSponsor this Article
Anuj Justus Rajappa (firstname.lastname@example.org) has received his B.Sc. Physics from Loyola college (Autonomous), Chennai.He received his M.Sc. Electronics from St. Joseph's college (Autonomous), Trichy. His interests include embedded system design, AI, automotive electronics and robotics.
Vairamani Kanagavel (email@example.com) received his B.Sc. and M.Sc. Electronics from St. Joseph's college (Autonomous), Trichy. He received his Ph.D. in Instrumentation from Madurai Kamaraj University, Madurai. His research interests include embedded systems, wireless sensor networks and sensor instrumentation.