Portenta H7 PMIC PF1550 Read I2C Registers

Hello, I'm trying to read the I2C registers of the power management IC in the Portenta H7, but despite all the effort it looks like the PF1550 has some protection or operation mode that prevent to read the registers. Anyone had the same issue?

At first I tried to scan the I2C1 of the Portenta looking for devices and I got as expected 2 response on address 0x08 (the PMIC PF1550) and 0x60 (Encryption ICs)

Then I tried to read all the registers of both, but only the Encryption ICs gives back data.

If I try to write a register of the PF1550 (without bricking the Portenta....) it acknowledge it, but if I read any registers it simply refuse to respond.

Below you can see the few line of code I used to read the DEVICE_ID register, but also this one doesn't work.

I tried also some arduino library for the PF1550 that initialize it but it doesn't change anything.
Also this library only write registers but the read doesn't work.

With a logic analyzer (Saleae Logic) I checked the registers that the bootloader of the Portenta write at the boot, but it never read any registers.

I tried the write se same registers in the same order, reading each registers right after the write, but it doesn't respond.

Any obvious things I'm missing?

//Portenta H7 Read 
#include <Wire.h>

const int pf1550Address = 0x08; // PF1550 I2C slave address (0x08 for read operations)

void setup() {
  Wire1.begin();
  Serial.begin(9600);
}

void loop() {
  Wire1.beginTransmission(pf1550Address);
  Wire1.write(0x00); // Address of register to read
  Wire1.endTransmission(false); // Send repeated start condition
  Wire1.requestFrom(pf1550Address, 1); // Request 1 byte from PF1550
  if (Wire.available()) {
    byte value = Wire1.read();
    Serial.print("Register 0x00 value: ");
    Serial.println(value, HEX);
  }
  delay(1000);
}

Yep you just have to change it from Wire to Wire1 on this line.

Here's a full sketch that reads all of the PMIC chip's I2C registers on the H7:

#include <Wire.h>

// Define an array of each register address (There's gaps in the readable register adresses so just define the ones that are meaningful/used)
const uint8_t REGISTER_ADDRESSES_PMIC[] = { 0x00, 0x01, 0x02, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x18, 0x19, 0x1A, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2A, 0x30, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x48, 0x4A, 0x4C, 0x4D, 0x4F, 0x50, 0x52, 0x53, 0x58, 0x59, 0x5A, 0x5B, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6F };
const uint8_t REGISTER_ADDRESSES_CHARGER[] = { 0x00, 0x02, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
const uint8_t REGISTER_ADDRESSES_OTP[] = { 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 };

void setup() {

  Wire1.begin();       // Initialize I2C communication on Wire1 (Doesn't work on "Wire")
  Serial.begin(9600);  // Initialize Serial communication

  while (!Serial) {   // Wait for serial port to connect
    delay(100);
  }

}

void loop() {

  // Read the PMIC registers
  Serial.println("--- PMIC Registers --- ");
  int check = sizeof(REGISTER_ADDRESSES_PMIC);
  Serial.print("PMIC array size: ");
  Serial.println(check);  // Should be 66
  for (uint8_t i = 0; i < sizeof(REGISTER_ADDRESSES_PMIC); i++) {
    byte data = readFromRegister(0x08, REGISTER_ADDRESSES_PMIC[i]);
    Serial.print("Register:,0x");
    Serial.print(REGISTER_ADDRESSES_PMIC[i], HEX);
    Serial.print(",Value:,");
    Serial.print(data, HEX);
    Serial.print(",Binary:,");
    printBinary(data);  // Print binary representation of the byte
    Serial.println("");
  }

  Serial.println("------------------");

  delay(100);

  // Read the Charger registers
  Serial.println("--- Charger Registers --- ");
  check = sizeof(REGISTER_ADDRESSES_CHARGER);
  Serial.print("Charger array size: ");
  Serial.println(check);  // Should be 24
  for (uint8_t i = 0; i < sizeof(REGISTER_ADDRESSES_CHARGER); i++) {
    byte data = readFromRegister(0x08, REGISTER_ADDRESSES_CHARGER[i] + 0x80);  // Charger registers ave an "offset" of 0x80
    Serial.print("Register:,0x");
    Serial.print(REGISTER_ADDRESSES_CHARGER[i], HEX);
    Serial.print(",Value:,");
    Serial.print(data, HEX);
    Serial.print(",Binary:,");
    printBinary(data);  // Print binary representation of the byte
    Serial.println("");
  }
  Serial.println("------------------");

  // Read the OTP registers
  Serial.println("--- OTP Registers --- ");
  check = sizeof(REGISTER_ADDRESSES_OTP);
  Serial.print("OTP array size: ");
  Serial.println(check);  // Should be 28

  //Enable OTP reading
  //KEY1
  uint8_t OTPCmd = 0x15;
  writeToRegister(0x08, 0x6F, OTPCmd);  // Device address, register address, data

  //KEY2
  OTPCmd = 0x50;
  writeToRegister(0x08, 0x9F, OTPCmd);  // Device address, register address, data

  //TEST_REG_KEY3
  OTPCmd = 0xAB;
  writeToRegister(0x08, 0xDF, OTPCmd);  // Device address, register address, data, data

  //RC REQ 16MHz
  OTPCmd = 0x01;
  writeToRegister(0x08, 0x6B, OTPCmd);  // Device address, register address, data

  //OTP is indirect read, via register 0xC4 = FMRADDR and 0xC5 = FRMDATA
  for (uint8_t i = 0; i < sizeof(REGISTER_ADDRESSES_OTP); i++) {

    writeToRegister(0x08, 0xC4, REGISTER_ADDRESSES_OTP[i]);  // Device address, register address, data
    delay(2);
    byte data = readFromRegister(0x08, 0xC5);  // Charger registers ave an "offset" of 0x80
    Serial.print("Register:,0x");
    Serial.print(REGISTER_ADDRESSES_OTP[i], HEX);
    Serial.print(",Value:,");
    Serial.print(data, HEX);
    Serial.print(",Binary:,");
    printBinary(data);  // Print binary representation of the byte
    Serial.println("");
  }
  Serial.println("------------------");

  while(1){}
}

void writeToRegister(uint8_t deviceAddress, uint8_t registerAddress, uint8_t data) {
  Wire1.beginTransmission(deviceAddress);  // Start communication with device on Wire1
  Wire1.write(registerAddress);            // Address of the register to write to
  Wire1.write(data);                       // Write the data
  Wire1.endTransmission();                 // End communication
}

byte readFromRegister(uint8_t deviceAddress, uint8_t registerAddress) {
  byte data;
  Wire1.beginTransmission(deviceAddress);  // Start communication with device on Wire1
  Wire1.write(registerAddress);            // Address of the register to read from
  Wire1.endTransmission(false);            // Send restart to keep connection alive

  // Request 1 byte from the device
  Wire1.requestFrom(deviceAddress, 1);
  if (Wire1.available()) {
    data = Wire1.read();  // Read the byte
  }
  return data;
}

void printBinary(byte b) {
  for (int i = 7; i >= 0; i--) {
    Serial.print((b >> i) & 1);
  }
}
1 Like