4 USB-Channel 5V Power supply module EP-0249 from 52pi

 

The EP-0249 is a 4 USB-Channel 5V Poser supply module for DeskPi's Rackmate T0 and Rackmate T1 1U rack mounts. The unit allows to power up 4 Raspberry Pi from on central point. Additionally the EP-0249 monitors the voltage and current on each USB outlet.

The Hardware

The 4 USB-Channel Power Supply basically consists of

  • a step down power supply with an input range from 6V to 24V,
  • a Raspberry Pi Pico,
  • a I2C 0.91" OLED (128x32)
  • two I2C INA3221 ICs to measure voltages and currents

It fits well to their line of rack mounts. What I found out from their schematic so far is, that the first 3 USB channels are measured by the INA3221 with address 0x40. The second INA3221 at 0x41 measures USB 4 on channel 0 and the input voltage on channel 2. Channel 1 on the second IC is not connected to anything.

4 USB-Channel 5V Poser supply module

The OEM Software in Python

The module I had to program came with an empty Rasperry Pi Pico. 52pi provides an installation description for Thonny and how to flash MircoPython on the Pico. Further more 52pi has published two library files - one for the OLED and one for the INA3221 ICs and a Phyton Script.

After flashing the three files on the Pico the OLED will display the voltages and currents of all 4 USB channels, the input voltage and the total current.
Screen 1:
4 USB-Channel 5V Poser supply module

Screen 2:
4 USB-Channel 5V Poser supply module

Unfortunately the font on the OLED is very small hence barely readable. As far as I found out, there is no easy solution to make the OLED font larger with MicroPython and the given OLED library. Furthermore the numbering of the channels in the second screen doesn't make so much sense for me.

The current of the first USB channel is printed to Serial.

A C++ Program with Larger Font for the Supply Module EP-0249 from 52pi

When it is so hard to change the font size in MicroPython, why not use something else. I opted for C++ and the Arduino Framework.

First I had to install the Platform Package "Arduino Mbed OS RP2040 Boards" with the Boards Manager in the Arduino IDE.

Arduino IDE for Raspberry PI Pico

Afterwards I installed two libraries from Adafruit: Adafruit_INA3221.h and Adafruit_SSD1306.h. Both libraries might require the installation of additional libraries but the Arduino IDE will do that during the installation anyway.

Based on the examples from the libraries a test sketch was straight forward:

/* 
   4 USB-Channel 5V Power supply module  EP-0249 
   Base Idea is on the 52pi Programm  
   https://wiki.52pi.com/index.php?title=EP-0249
   https://wiki.52pi.com/images/a/a3/EP-0249-7.jpg
   https://www.youtube.com/watch?v=uHrA0ky3zVA

   This sketch uses a larger screen/font resolution to make the values better readable.
   The screen displays two lines with Voltage & Amperage for each channel.
   Additionally the actual values are printed to Serial.

   Remark: set the correct value for the shunt Resistance in the constant expression!

   2026-04-05 noiasca: tested with real 52pi hardware  109441/43696
   2026-03-06 noiasca: tests with prototype board      109441/43696
*/
#include "Adafruit_INA3221.h"          // install via Library Manager (last tested 1.0.3)
#include "Adafruit_GFX.h"              // install via Library Manager (last tested 1.12.4)
#include "Adafruit_SSD1306.h"          // install via Library Manager (last tested 2.5.16)
#include "Wire.h"               

constexpr int screenWidth {128};                 // OLED display width, in pixels
constexpr int screenHight {32};                  // OLED display height, in pixels
constexpr int screenReset { -1};                 // Reset pin # (or -1 if sharing Arduino reset pin)
constexpr uint8_t screenAddress {0x3C};          // See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
constexpr uint32_t interval {5000};              // display time of one screen
Adafruit_SSD1306 display(screenWidth, screenHight, &Wire, screenReset);

Adafruit_INA3221 ina[2];                         // Create array of INA3221 objects
constexpr uint8_t addr[2] {0x40, 0x41};          // the two I2C addresses for the INA ICs
constexpr float shuntResistance {0.006};         // 0.006 for the 52pi board, 0.1 for breakout boards with R100 shunts 

constexpr uint8_t ledPin{25};          // there is a green LED on the Raspberry Pico

// helper function to display one line on the OLED and print the values to serial
void outputChannel(Adafruit_INA3221 &ina, uint8_t channel, String id, uint8_t posY) {
  // measure:
  float voltage = ina.getBusVoltage(channel);
  float current = ina.getCurrentAmps(channel);
  // output to OLED
  display.setCursor(0, posY);
  display.print(id);
  display.print(":");
  display.print(voltage, 1);
  display.print(" ");
  display.print(current, 1);
  display.print("A");
  display.display();
  // output to Serial
  Serial.print("ch");                  // start characters
  Serial.print(id);                    // readable identifier (i.e. The channel numbers 1 2 3 4)
  Serial.print(";");
  Serial.print(voltage, 1);            // voltage with one decimal
  Serial.print(";");
  Serial.print(current, 2);            // current with two decimals
  Serial.println();                    // line feed as end of data set
}

void setup() {
  Serial.begin(115200);
  delay(500);                          // Wait for serial port to connect on some boards, continue anyway
  Serial.println("INA3221 & SSD1306");

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);          // optional: just to see the program has started

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, screenAddress)) {
    Serial.println(F("SSD1306 allocation failed"));
  }
  display.clearDisplay();
  display.setTextSize(2);              // default font slightly larger
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);             // Start at top-left corner
  //display.cp437(true);               // Use full 256 char 'Code Page 437' font
  display.print("INA3221");
  display.setCursor(0, 16);
  display.print("SSD1306");
  display.display();

  // we have two INA3221 ICs
  for (uint8_t ic = 0; ic < 2; ic++) {
    // Initialize the INA3221
    if (!ina[ic].begin(addr[ic], &Wire)) {
      Serial.print("Failed to find INA3221 chip ");
      Serial.println(addr[ic], HEX);
      while (1)    // don't proceed if the IC is not responding
        delay(10); 
    }
    Serial.print("INA3221 Found on ");
    Serial.println(addr[ic], HEX);

    ina[ic].setAveragingMode(INA3221_AVG_16_SAMPLES);
    // Set shunt resistances for all channels
    for (uint8_t i = 0; i < 3; i++) {
      ina[ic].setShuntResistance(i, shuntResistance);      // 0.1 for breakout boards with R100, 0.006 for the 52pi board
    }
    // Set a power valid alert to tell us if ALL channels are between the two
    // limits:
    // ina[ic].setPowerValidLimits(3.0 /* lower limit */, 15.0 /* upper limit */);
  }
}

void loop() {
  display.clearDisplay();              // clear screen
  outputChannel(ina[0], 0, "1", 0);    // hand over IC, channel, readable name, line to print
  outputChannel(ina[0], 1, "2", 16);
  delay(interval);                     // wait some time 

  display.clearDisplay();
  outputChannel(ina[0], 2, "3", 0);
  outputChannel(ina[1], 0, "4", 16);   // the "4th" USB is on IC1 channel 0
  delay(interval);

  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Total");
  display.setCursor(0, 16);
  outputChannel(ina[1], 2, "T", 16);   // the "3rd" channel on IC1 is connected to the input VCC
  delay(interval);
}
//

To avoid code duplicates I'm using a helper function outputChannel which gets the INA IC object as reference, the channel on that IC, a cleartext name (ID) for that channel and the information on which line it should be printed on the OLED. The function reads the values from the respective INA3221 channel and provides the information to the OLED and Serial. In loop() I just call two lines for each screen. The double sized font makes the OLED so much easier to read.

4 USB-Channel 5V Poser supply module large font

4 USB-Channel 5V Poser supply module larger font

Furthermore, all values are also printed out to Serial and could be transmitted to any other Raspberry in the rack.

Don't forget that you must press and hold the boot button on the Raspberry PI Pico during power on to bring the Pico in flash mode. Then press "Upload" in the Arduino IDE.

The sketch is nothing special and you can improve it on your own.

A Test Rig with INA3221 Breakout Boards

During reverse engineering and programming I decided that I would need a test rig. I bought a Raspberry PI Pico, two breakout boards with INA3221 and found a OLED display in the right dimension. To set the I2C adress on the second INA3221 to 0x41 I have connected the solder bridge VS.

Raspberry PI Pico with INA3221

Remark: The INA3221 breakout boards are using 100 Ohm resistors as shunt which is different to the 52Pi USB power board. Hence you must modify the value for the shunt resistor from 0.006 (for the 52pi) to 0.1 (for the breakout boards). When you have done this modification, the provided sketch will also work with the breakout boards.

Summary

The EP-0249 4 USB-Channel 5V Power Supply with the Raspberry Pi Pico is a nice module and the firmware can be adopted to your needs. If you want to use C++ it can be done with the Arduino IDE.

(*) Disclosure: Some of the links above are affiliate links, meaning, at no additional cost to you I will earn a (little) comission if you click through and make a purchase. I only recommend products I own myself and I'm convinced they are useful for other makers.

History

First upload: 2026-04-0 | Version: 2026-04-06