---
title: "W55RP20-EVB-PICO PSE KIT!"
url: "https://maker.wiznet.io/jaden/projects/w55rp20-evb-pico-pse-kit/"
markdown_url: "https://maker.wiznet.io/jaden/projects/w55rp20-evb-pico-pse-kit/md"
type: "WCC: WIZnet Created Content"
author: "jaden kim"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "jaden kim"
published: "2024-11-29"
language: "en"
hardware: ["WIZnet W55RP20-EVB-Pico"]
likes: 0
views: 4300
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# W55RP20-EVB-PICO PSE KIT!

> W55RP20-EVB-PICO PSE KIT

Original author: jaden kim

## Components

- **WIZnet W55RP20-EVB-Pico** x 1 ([docs](https://wiznet.io/products/powered-by-raspberry-pi/w55rp20-evb-pico))

## Documents and links

- [W55RP20-EVB-PICO_PSE_KIT](https://maker.wiznet.io/_lib/download.asp?path=project/6943&downfile=W55RP20%2DEVB%2DPICO%5FPSE%5FKIT%2Epdf) (schematics)

## Article

## Power over Ethernet (PoE) PSE-KIT Project

PoE (Power over Ethernet) is a convenient feature that allows devices to receive power through Ethernet UTP cables.

That's why countless devices support PoE, and many makers have also created projects using PoE. However, most PoE-related projects made by makers are limited to **Powered Devices (PDs)**.

Why is that...? Because PoE-PDs, which receive power, are simpler and have fewer considerations than **Power Sourcing Equipment (PSEs)** that supply power!

I thought that if we could monitor and control the voltage, current, temperature, and status of each port on a PSE—including the ability to turn them on/off—it would enable more efficient power management in smart systems. So, I decided to create a **PSE-KIT**.

### System Block Diagram

*The overall system block diagram is as follows.*

![](https://maker.wiznet.io/upload/ckeditor5/879226896%5F1732812745%2Epng)

Initially, I considered converting **220 VAC to 54 VDC**, but after learning that PoE-specific 54 V adapters are widely available on the market, I changed the power input to **54 VDC**. (The fact that I lack AC to DC design skills also played a part.)

![](https://maker.wiznet.io/upload/ckeditor5/879226896%5F1732812589%2Epng)

***DC 54V 2.6A SMPS,140W***

### Component Selection

#### Voltage Conversion

For converting **54 V to 3.3 V** and **54 V to 5 V**, I used Torex's **XC9702A75CDR-G**.

![](https://maker.wiznet.io/upload/ckeditor5/879226896%5F1732812794%2Epng)

**Reason for Selection**: It has a maximum input voltage of **60 V**, providing an input voltage margin, and I had previous experience using it in other projects.

#### Input Protection

- **Reverse Voltage Protection**: An **FET** is used on the 54 V input.

- **Transient Voltage Suppression**: A **TVS diode** is employed to maintain circuit stability against voltage transients.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732869509%2Epng)

*Power protection circuitry*

### PSE Implementation

#### IP804AR - PSE IC

I used the **IP804AR** from ICplus as the PSE IC.

**Features**:

- Supports **4 ports**, each capable of supplying up to **30 W**.

- Uses **internal FETs** for switching PoE power, eliminating the need for additional external FETs.

- Can directly use the **54 VDC** from the PoE adapter as the IC supply voltage.

**Limitation**: The IP804AR only supports PoE-related operations and does not handle Ethernet data communication.

![](https://maker.wiznet.io/upload/ckeditor5/879226896%5F1732813071%2Epng)

*Internal FET*

![](https://maker.wiznet.io/upload/ckeditor5/879226896%5F1732813119%2Epng)

*44~57V Power input*

#### IP175G - Ethernet Switch IC

To enable Ethernet data communication, I also used the **IP175G**, a **5-port Ethernet switch IC** from ICplus.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732868611%2Epng)

*IP175G schematic image*

### PoE Configuration

- **Mode B Operation**: Since I'm using PoE in Mode B, I used PoE-specific transformers and RJ45 connectors.

- **PoE+ Support**: Aimed to support up to **PoE+**, so I selected components with higher specifications.

- **Cost Consideration**: Cost was not a major concern as there are no plans for mass production.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732868780%2Epng)

*RJ45*

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732868950%2Epng)

*PoE Transformer*

### Integration with W55RP20-EVB-PICO

The key feature of the **W55RP20-EVB-PICO PSE_KIT** is that it can be used by connecting the **W55RP20-EVB-PICO**, as suggested by its name.

- **Port Allocation**:
  - Out of the 5 ports on the IP175G, **4 ports** are connected via RJ45 connectors for UTP cable connections.
  - The remaining **1 port** is connected to the Ethernet interface of the **W55RP20-EVB-PICO**.

#### Connection Method

Initially, to connect the Ethernet port of the W55RP20-EVB-PICO to the IP175G, I considered using the method from the impressive project **"Wiznet Rudge PoE Pico PLC"** by **Manuel Alejandro Iglesias Abbatemarco**.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872029%2Epng)

*Wiznet Rudge PoE Pico PLC*

- **Issue**: This method required removing the RJ45 connector from the W55RP20-EVB-PICO, and once manually soldered, replacing the board would be difficult.

- **Solution**: I opted to use **pogo pins** to connect the IP175G to the W55RP20-EVB-PICO.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872151%2Epng)

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872173%2Epng)

#### Pogo Pin Details

- **Type Used**: Cupped Head pogo pins from **Adafruit.**

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872286%2Epng)

- **Pin Arrangement**: Positioned to contact pins **1**, **2**, **3**, and **6** of the RJ45 connector on the W55RP20-EVB-PICO.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872406%2Epng)

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872430%2Epng)

- **Outcome**: When mounting the W55RP20-EVB-PICO, the pogo pins accurately made contact without needing precise alignment.

#### PHY Connection

By connecting directly to the pins of the RJ45 connector (instead of through the RJ45 jack), the connection bypasses the internal LAN transformer.

- **Direct PHY-to-PHY Connection**: To connect the PHYs without transformers, I used **DC blocking capacitors** between the IP175G and the W55RP20-EVB-PICO.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732872828%2Epng)

*left side is IP175G and right side is POGO PIN(connected to W55RP20-EVB-PICO RJ45 pin)*

### Testing and Results

- **Power-Up and Link Confirmation**: After supplying power and mounting the W55RP20-EVB-PICO, I confirmed that the **LINK** was established properly.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732873024%2Epng)

- **Port Verification**: All **4 additional ports** showed active links, confirmed by the **LINK LEDs**.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732873118%2Epng)

- **PoE Detection and Power Supply**: Connected PoE PD devices to verify power delivery, confirmed by the **PoE LEDs** on each port.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732873200%2Epng)

### Accessing IP804AR Registers via I2C

Referring to the IP804AR datasheet, I used the I2C interface of the W55RP20-EVB-PICO to read and analyze various registers of the IP804AR, outputting the data to the terminal.

#### Connection Setup

- **I2C Connection**: Connected the I2C ports (previously brought out via header pins) to the I2C pins on the W55RP20-EVB-PICO using jumpers.

- **I2C Configuration**:
  - The IP804AR divides the data line into **SDAO** and **SDAI**.
  - For standard 2-wire I2C communication, connected **SDAO** and **SDAI** together.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732873593%2Epng)

#### Pin Assignments

- **UART Output**: Used **GP0** and **GP1** on the W55RP20-EVB-PICO for UART communication to the terminal.

- **I2C Interface**: Assigned to **GP4** and **GP5**.

#### Code Implementation

The code is as follows:

```c
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"

#define IP804AR_I2C_ADDR 0x74  // Default I2C address for IP804AR
#define PICO_DEFAULT_I2C_SDA_PIN 4
#define PICO_DEFAULT_I2C_SCL_PIN 5

// Register definitions
#define REG_SYSTEM_CONFIG 0x01  // System Configuration Register
#define REG_PORT_POWER_CONTROL(port) (0x98 + (port))  // Power Control Register per port
#define REG_SUPPLY_VOLTAGE_MSB 0xE0
#define REG_PORT_VOLTAGE_MSB(port) (0xB0 + (port * 2))  // Port Voltage MSB
#define REG_PORT_CURRENT_MSB(port) (0xA0 + (port * 2))  // Port Current MSB
#define REG_PORT_TEMP_MSB(port) (0xC0 + (port * 2))     // Port Temperature MSB

#define REG_IVT_POLL 0xE3    // IVT Poll Register address
#define REG_DETECTED_PD_CLASS 0x88  // Detected PD Class Register address

void print_binary(uint8_t value) {
    for (int i = 7; i >= 0; i--) {
        printf("%c", (value & (1 << i)) ? '1' : '0');
    }
    printf("\n");
}

void switch_to_page(uint8_t page) {
    uint8_t device_register = 0x00;
    uint8_t value;

    // Read current page
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &device_register, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &value, 1, false) != 1) {
        printf("Failed to read current page.\n");
        return;
    }

    // Set page
    uint8_t new_value = (value & 0x3F) | (page << 6);  // Set page in the upper 2 bits
    uint8_t write_data[2] = {device_register, new_value};
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data, 2, false) != 2) {
        printf("Failed to switch to Page %d.\n", page);
        return;
    }
    printf("Page switched to %d.\n", page);
}



void enable_port_manual_mode(uint8_t port) {
    if (port > 3) {
        printf("Invalid port number. Must be 0-3.\n");
        return;
    }

    switch_to_page(1);  // Switch to page 1

    // Set Power Control register
    uint8_t power_control_register = REG_PORT_POWER_CONTROL(port);
    uint8_t power_control_data[2] = {power_control_register, 0x01};  // Activate Manual mode
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, power_control_data, 2, false) != 2) {
        printf("Failed to enable manual mode for Port %d.\n", port);
        return;
    }
    printf("Port %d enabled in Manual Mode.\n", port);
}

void read_ivt(uint8_t port) {
    uint8_t msb, lsb;

    // **Switch to page 0**
    switch_to_page(0);

    // **Read supply voltage (Supply Voltage)**
    uint8_t supply_voltage_reg = REG_SUPPLY_VOLTAGE_MSB;
    uint8_t supply_voltage_data[2];
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &supply_voltage_reg, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, supply_voltage_data, 2, false) != 2) {
        printf("Failed to read supply voltage.\n");
        return;
    }
    uint8_t supply_voltage_integer = ((supply_voltage_data[0] & 0x0F) << 4) | (supply_voltage_data[1] >> 4);
    uint8_t supply_voltage_fractional = supply_voltage_data[1] & 0x0F;
    float supply_voltage = supply_voltage_integer + (supply_voltage_fractional * 0.0625);

    printf("Supply Voltage: %.2f V\n", supply_voltage);

    // **Read port voltage (Port Voltage)**
    uint8_t voltage_reg = REG_PORT_VOLTAGE_MSB(port);
    uint8_t voltage_data[2];
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &voltage_reg, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, voltage_data, 2, false) != 2) {
        printf("Failed to read voltage for Port %d.\n", port);
        return;
    }

    // **Print port voltage MSB and LSB**
    printf("Port %d Voltage MSB (Binary): ", port);
    print_binary(voltage_data[0]);  // Print MSB
    printf("Port %d Voltage LSB (Binary): ", port);
    print_binary(voltage_data[1]);  // Print LSB

    // **Calculate port voltage**
    uint8_t port_voltage_integer = ((voltage_data[0] & 0x0F) << 4) | (voltage_data[1] >> 4);  // MSB lower 4 bits + LSB upper 4 bits
    uint8_t port_voltage_fractional = voltage_data[1] & 0x0F;  // LSB lower 4 bits
    float port_voltage = port_voltage_integer + (port_voltage_fractional * 0.0625);

    // **Calculate true voltage: Supply Voltage - Port Voltage**
    float true_port_voltage = supply_voltage - port_voltage;

    printf("Port %d Voltage: %.2f V (True Port Voltage: %.2f V)\n", port, port_voltage, true_port_voltage);

    // **Read current**
    uint8_t current_reg = REG_PORT_CURRENT_MSB(port);
    uint8_t current_data[2];
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &current_reg, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, current_data, 2, false) != 2) {
        printf("Failed to read current for Port %d.\n", port);
        return;
    }

    // **Print current MSB and LSB**
    printf("Port %d Current MSB (Binary): ", port);
    print_binary(current_data[0]);  // Print MSB
    printf("Port %d Current LSB (Binary): ", port);
    print_binary(current_data[1]);  // Print LSB

    // **Calculate current**
    uint8_t current_integer = ((current_data[0] & 0x0F) << 6) | (current_data[1] >> 2);  // MSB lower 4 bits + LSB upper 6 bits
    uint8_t current_fractional = current_data[1] & 0x03;  // LSB lower 2 bits
    float current = current_integer + (current_fractional * 0.25);  // Calculate fractional part (2 bits = * 0.25)

    printf("Port %d Current: %.2f mA\n", port, current);

    // **Read temperature**
    uint8_t temp_reg = REG_PORT_TEMP_MSB(port);
    uint8_t temp_data[2];
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &temp_reg, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, temp_data, 2, false) != 2) {
        printf("Failed to read temperature for Port %d.\n", port);
        return;
    }

    // **Print temperature MSB and LSB**
    printf("Port %d Temperature MSB (Binary): ", port);
    print_binary(temp_data[0]);  // Print MSB
    printf("Port %d Temperature LSB (Binary): ", port);
    print_binary(temp_data[1]);  // Print LSB

    // **Calculate temperature**
    uint8_t integer_part = ((temp_data[0] & 0x1F) << 4) | (temp_data[1] >> 4);  // MSB lower 5 bits + LSB upper 4 bits
    uint8_t fractional_raw = temp_data[1] & 0x0F;  // LSB lower 4 bits
    float fractional_part = fractional_raw * 0.0625;  // Calculate fractional part
    float temperature = integer_part + fractional_part;

    printf("Port %d Temperature: %.2f °C\n", port, temperature);
}

void read_and_print_voltage_binary(uint8_t reg) {
    uint8_t device_register = 0x00;  // I2C Device Address Register
    uint8_t value;

    // **Set page to 0**
    i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &device_register, 1, true);
    i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &value, 1, false);
    uint8_t new_value_page0 = value & 0x3F;  // Set upper 2 bits to 00
    uint8_t write_data_page0[2] = {device_register, new_value_page0};
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data_page0, 2, false) != 2) {
        printf("Failed to switch to Page 0\n");
        return;
    }
    printf("Page switched to 0 for register 0x%02X.\n", reg);

    uint8_t data[2];  // 2-byte array for Burst Read

    // **Perform Burst Read**
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &reg, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, data, 2, false) != 2) {
        printf("Failed to read from register 0x%02X\n", reg);
        return;
    }

    // **Print MSB and LSB in binary**
    printf("Register 0x%02X MSB (Binary): ", reg);
    print_binary(data[0]);
    printf("Register 0x%02X LSB (Binary): ", reg + 1);
    print_binary(data[1]);

    // **Calculate voltage value**
    uint16_t integer_raw = ((data[0] & 0x0F) << 4) | (data[1] >> 4);  // Combine lower 4 bits of MSB and upper 4 bits of LSB
    uint8_t fractional_raw = data[1] & 0x0F;  // Lower 4 bits of LSB (fractional part)
    float fractional_part = fractional_raw * 0.0625;  // Convert to decimal (4-bit value * 0.0625)
    float voltage = integer_raw + fractional_part;

    // **Print voltage value**
    printf("Voltage: %u.%02u V\n", integer_raw, (uint8_t)(fractional_part * 100));
}

void read_system_config() {
    uint8_t device_register = 0x00;  // I2C Device Address Register address
    uint8_t system_config;
    uint8_t system_config_register = REG_SYSTEM_CONFIG;

    // **Set page to 1**
    i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &device_register, 1, true);
    i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &system_config, 1, false);
    uint8_t new_value_page1 = (system_config & 0x3F) | (1 << 6);
    uint8_t write_data_page1[2] = {device_register, new_value_page1};
    i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data_page1, 2, false);
    printf("Page switched to 1\n");

    // **Read System Configuration Register**
    i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &system_config_register, 1, true);
    if (i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &system_config, 1, false) != 1) {
        printf("Failed to read System Configuration Register\n");
        return;
    }

    // **Print System Configuration status**
    printf("System Configuration Register (0x01): 0b");
    for (int i = 7; i >= 0; i--) {
        printf("%c", (system_config & (1 << i)) ? '1' : '0');
    }
    printf("\n");

    // **Check Operation Mode**
    uint8_t operation_mode = (system_config >> 6) & 0x03;
    printf("Operation Mode: ");
    switch (operation_mode) {
        case 0b00: printf("Auto Mode\n"); break;
        case 0b01: printf("Manual Mode\n"); break;
        case 0b10: printf("Diagnostic Mode\n"); break;
        case 0b11: printf("Scan Mode\n"); break;
        default: printf("Unknown Mode\n"); break;
    }

    // **Check Suspend Classification**
    if (system_config & (1 << 2)) {
        printf("Suspend Classification: Enabled\n");
    } else {
        printf("Suspend Classification: Disabled\n");
    }

    // **Check Suspend Power Up**
    if (system_config & (1 << 1)) {
        printf("Suspend Power Up: Enabled\n");
    } else {
        printf("Suspend Power Up: Disabled\n");
    }

    // **Check I2C Checksum**
    if (system_config & (1 << 0)) {
        printf("I2C Checksum: Enabled\n");
    } else {
        printf("I2C Checksum: Disabled\n");
    }
}

void enable_auto_polling() {
    uint8_t device_register = 0x00;  // I2C Device Address Register
    uint8_t value;

    // **Set page to 0**
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &device_register, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &value, 1, false) != 1) {
        printf("Failed to read current page from I2C Device Address Register\n");
        return;
    }

    uint8_t new_value_page0 = value & 0x3F;  // Set upper 2 bits to 00
    uint8_t write_data_page0[2] = {device_register, new_value_page0};
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data_page0, 2, false) != 2) {
        printf("Failed to switch to Page 0\n");
        return;
    }
    printf("Page switched to 0 for enabling Auto Polling.\n");

    uint8_t ivt_poll_register = REG_IVT_POLL;  // IVT Poll Register address
    uint8_t ivt_poll_status;

    // Read IVT Poll Register
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &ivt_poll_register, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &ivt_poll_status, 1, false) != 1) {
        printf("Failed to read IVT Poll Register (0xE3)\n");
        return;
    }

    // Enable Auto Polling (Set Bit 5)
    ivt_poll_status |= (1 << 5);  // Set Bit 5 to 1
    uint8_t write_data[2] = {ivt_poll_register, ivt_poll_status};
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data, 2, false) != 2) {
        printf("Failed to write to IVT Poll Register (0xE3)\n");
        return;
    }
    printf("Auto Polling enabled.\n");
}

void read_ivt_poll_register() {
    uint8_t device_register = 0x00;  // I2C Device Address Register
    uint8_t value;

    // **Set page to 0**
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &device_register, 1, true) != 1 ||
        i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &value, 1, false) != 1) {
        printf("Failed to read current page from I2C Device Address Register\n");
        return;
    }

    uint8_t new_value_page0 = value & 0x3F;  // Set upper 2 bits to 00
    uint8_t write_data_page0[2] = {device_register, new_value_page0};
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, write_data_page0, 2, false) != 2) {
        printf("Failed to switch to Page 0\n");
        return;
    }
    printf("Page switched to 0 for IVT Poll Register (0xE3).\n");

    uint8_t ivt_poll_register = REG_IVT_POLL;  // IVT Poll Register address
    uint8_t ivt_poll_status;

    // Read IVT Poll Register
    if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &ivt_poll_register, 1, true) != 1) {
        printf("Failed to write to IVT Poll Register (0xE3)\n");
        return;
    }

    if (i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, &ivt_poll_status, 1, false) != 1) {
        printf("Failed to read IVT Poll Register (0xE3)\n");
        return;
    }

    // Print IVT Poll Register status
    printf("IVT Poll Register (0xE3): 0b");
    for (int i = 7; i >= 0; i--) {
        printf("%c", (ivt_poll_status & (1 << i)) ? '1' : '0');
    }
    printf("\n");

    // Interpret status
    if (ivt_poll_status & (1 << 7)) {
        printf("Polling is currently in progress.\n");
    } else {
        printf("No polling is in progress.\n");
    }

    if (ivt_poll_status & (1 << 5)) {
        printf("Auto Polling is enabled.\n");
    } else {
        printf("Auto Polling is disabled.\n");
    }

    uint8_t poll_interval = ivt_poll_status & 0x0F;
    printf("Poll Interval: %d (units of 0.25ms)\n", poll_interval);
}

void read_ivt_all_ports() {
    for (uint8_t port = 0; port < 4; port++) {  // Repeat for ports 0 to 3
        printf("\nReading data for Port %d\n", port);

        uint8_t msb, lsb;

        // **Switch to page 0**
        switch_to_page(0);

        // **Read supply voltage (Supply Voltage)**
        uint8_t supply_voltage_reg = REG_SUPPLY_VOLTAGE_MSB;
        uint8_t supply_voltage_data[2];
        if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &supply_voltage_reg, 1, true) != 1 ||
            i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, supply_voltage_data, 2, false) != 2) {
            printf("Failed to read supply voltage.\n");
            return;
        }
        uint8_t supply_voltage_integer = ((supply_voltage_data[0] & 0x0F) << 4) | (supply_voltage_data[1] >> 4);
        uint8_t supply_voltage_fractional = supply_voltage_data[1] & 0x0F;
        float supply_voltage = supply_voltage_integer + (supply_voltage_fractional * 0.0625);

        printf("Supply Voltage: %.2f V\n", supply_voltage);

        // **Read port voltage (Port Voltage)**
        uint8_t voltage_reg = REG_PORT_VOLTAGE_MSB(port);
        uint8_t voltage_data[2];
        if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &voltage_reg, 1, true) != 1 ||
            i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, voltage_data, 2, false) != 2) {
            printf("Failed to read voltage for Port %d.\n", port);
            continue;  // Move to next port
        }

        // **Calculate port voltage**
        uint8_t port_voltage_integer = ((voltage_data[0] & 0x0F) << 4) | (voltage_data[1] >> 4);
        uint8_t port_voltage_fractional = voltage_data[1] & 0x0F;
        float port_voltage = port_voltage_integer + (port_voltage_fractional * 0.0625);
        float true_port_voltage = supply_voltage - port_voltage;

        printf("Port %d Voltage: %.2f V\n", port, true_port_voltage);

        // **Read current**
        uint8_t current_reg = REG_PORT_CURRENT_MSB(port);
        uint8_t current_data[2];
        if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &current_reg, 1, true) != 1 ||
            i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, current_data, 2, false) != 2) {
            printf("Failed to read current for Port %d.\n", port);
            continue;  // Move to next port
        }

        // **Calculate current**
        uint8_t current_integer = ((current_data[0] & 0x0F) << 6) | (current_data[1] >> 2);
        uint8_t current_fractional = current_data[1] & 0x03;
        float current = current_integer + (current_fractional * 0.25);

        printf("Port %d Current: %.2f mA\n", port, current);

        // **Read temperature**
        uint8_t temp_reg = REG_PORT_TEMP_MSB(port);
        uint8_t temp_data[2];
        if (i2c_write_blocking(i2c_default, IP804AR_I2C_ADDR, &temp_reg, 1, true) != 1 ||
            i2c_read_blocking(i2c_default, IP804AR_I2C_ADDR, temp_data, 2, false) != 2) {
            printf("Failed to read temperature for Port %d.\n", port);
            continue;  // Move to next port
        }

        // **Calculate temperature**
        uint8_t integer_part = ((temp_data[0] & 0x1F) << 4) | (temp_data[1] >> 4);
        uint8_t fractional_raw = temp_data[1] & 0x0F;
        float fractional_part = fractional_raw * 0.0625;
        float temperature = integer_part + fractional_part;

        printf("Port %d Temperature: %.2f °C\n", port, temperature);
    }
}


int main() {
    // Initialize UART
    stdio_init_all();

    // Initialize I2C
    i2c_init(i2c_default, 100 * 1000);
    gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
    gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);

//    printf("Reading IVT Poll Register\n");
//    read_ivt_poll_register();
//    printf("----------------------------------------\n");
//    printf("Enable Auto poll\n");
//    enable_auto_polling();
//    printf("----------------------------------------\n");
    printf("Reading IVT Poll Register\n");
    read_ivt_poll_register();
    printf("----------------------------------------\n");
    printf("Reading System Configuration Register\n");
    read_system_config();
    printf("----------------------------------------\n");
    // Activate Manual Mode on Port 0
    //enable_port_manual_mode(0);

    while (1) {
        read_and_print_voltage_binary(REG_SUPPLY_VOLTAGE_MSB);
        printf("\nMonitoring Port 0~3 IVT...\n");
        read_ivt_all_ports();
        printf("\n\n\n");
        sleep_ms(10000);  // Wait for 1 second
    }

    return 0;
}
```

Note: The code is a bit messy due to quick testing. Please excuse any inconsistencies.

The **CMakeLists.txt** was written as follows:

**set(TARGET_NAME pse)add_executable(${TARGET_NAME} ${TARGET_NAME}.c )target_link_libraries(${TARGET_NAME} pico_stdlib hardware_i2c )pico_enable_stdio_usb(${TARGET_NAME} 0)pico_enable_stdio_uart(${TARGET_NAME} 1)pico_add_extra_outputs(${TARGET_NAME})**

#### Terminal Output

Upon checking the terminal output, the data appeared as follows:

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732875772%2Epng)

**Observation**: Since I was testing with a PoE PD device connected to **Port 0**, its temperature was slightly higher compared to the other ports.

![](https://maker.wiznet.io/upload/ckeditor5/19233087%5F1732876968%2Epng)

"In the attached schematic, pin 13 of the IP175G is marked as NC (Not Connected), which was my mistake. I discovered this later and fixed it with a jumper wire. Please take note."

### Next Steps

In the next project, I plan to utilize this **W55RP20-EVB-PICO PSE_KIT** to add functionality that allows monitoring and controlling the PSE's status via a **web server**.

Thank you for your interest!

---

Source: https://maker.wiznet.io/jaden/projects/w55rp20-evb-pico-pse-kit/
