How to modify output voltage of a buck converter using PMBus?

Hello Everyone,

I am trying to modify the output voltage of a buck converter that is as a slave device via Arduino MEGA2560 as a Master device and using PMBus protocol.
I have written a code to write and read the output voltage, but I received garbage value (C0).
I would be grateful if someone can help me to solve the problem.
Here is the entire code.

#include <Wire.h>

void setup() {

  Wire.begin();                // join i2c bus (address optional for master)

  Serial.begin(9600);          // start serial communication at 9600bps
}

byte msb = 0;
byte lsb = 0;
byte V_out = 0;


void loop() {

  // step 1: Unlock PMBUS write protection

  Wire.beginTransmission(0x38);  // transmit to device(0x38)

  Wire.write(0x10);             // sets register pointer to the command register (0x10)

  Wire.write((byte)0x00);      // sends Data:0x00

  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(70);

  // step 2: VOUT setpoint
  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x21);      // sets register pointer to the command register(0x21)

  Wire.write((byte)0x00);      //sends  Byte#0:0x66 to the command register (0x21)

  Wire.write((byte)0xC6);       //sends  Byte#1:0xC6 to the command register (0x21)

  Wire.write(0x17);            // PEC

  Wire.endTransmission();      // stop transmitting

  delay(70);                   // datasheet suggests at least 65 milliseconds


  // step 3: Set VOUT_OV_WARN

  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x42);      // sets register pointer to to the command register(0x42)

  Wire.write((byte)0x33);      //sends  Byte#0:0x33 to the command register (0x42)

  Wire.write((byte)0xD3);       //sends  Byte#1:0xD3 to the command register (0x42)

  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(70);

  // step 4: Command 0xEC should be send to unlock the MCU which save the data.

  Wire.beginTransmission(0x38);     // transmit to device(0x38)

  Wire.write(0xEC);                 //sets register pointer to to the command register(0xEC)

  Wire.write(0x04);                 //sends  Byt count:N:4(0x04) to the command register (0xEC)

  Wire.write((byte)0x7E);           //sends  Byte#0:0x7E to the command register (0xEC)

  Wire.write((byte)0x15);           //sends  Byte#1:0x15 to the command register (0xEC)

  Wire.write((byte)0xDC);           //sends  Byte#2:0xDC to the command register (0xEC)

  Wire.write((byte)0x42);          //sends  Byte#3:0x42 to the command register (0xEC)

  Wire.write(0x45);                // PEC

  Wire.endTransmission();         // stop transmitting

  delay(70);

  //step 5: Command 0x11 should be send to save the Vout setpoint in the MCU


  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x11);            //sets register pointer to to the command register(0x11)


  Wire.endTransmission();      // stop transmitting


  delay(70);


  // step 6: request reading Vout setpoint  from the Buck Converter

  Wire.beginTransmission(0x38);       // transmit to device(0x38)

  Wire.write(0x21);                  //sets register pointer to to the command register(0x21)

  Wire.endTransmission(false);       // stop transmitting


  Wire.requestFrom((uint8_t) 0x38, (uint8_t) 2, (uint8_t) true);    //  Wire.requestFrom(38, 2);    // request 2 bytes from peripheral device #0x38


  // step 7: receive reading from the Buck Converter

  if (2 <= Wire.available()) {   // if two bytes were received

    msb = Wire.read();        // receive high byte (overwrites previous reading)
    
    msb =  msb << 8;       // shift high byte to be high 8 bits
    
    lsb= Wire.read();     // receive low byte as lower 8 bits

     V_out = msb | lsb;
     
    Serial.print("  V_out = ");
    Serial.print(V_out, HEX);   // print the reading
    Serial.println(" V");
  }

  delay(250);                  // wait a bit since people have to read the output :)
}

Could you show a datasheet or at least a link to the buck converter?

by the way...
Your msb defined as a byte, so this line is non-sense:

Result of shifting byte left by 8 bits always will be zero.

...

This will always result in the MSB being ignored. A byte can only hold 8 bits. If you move these 8 bits by 8 bits you have no value left in the variable.

Hi
Thank you very much for reply.
Yes, I have datasheet.
DS_Q48SC12042 (3).pdf (1012.5 KB)

Do you fix the error?
Is the problem solved?

Not yet. My major is not digital electronic, so it is difficult for me to understand the concept of these kinds of codes. I need to change the code, but should study more, and it is time-consuming for me.

I tried to tell you that you have to use a variable type for "msb" that is able to hold the result. Try uint16_t.

1 Like

Thank you very much for helping me.
Sure, I will use it.

You should also test return codes (where available) from the Wire library functions you are using to help with troubleshooting, especially Wire.endTransmission(). See Wire - Arduino Reference

As well as msb, which you have already been told about, V_out must also be defined as uint16_t.

If you are getting "garbage values" that is already quite good since it shows that I2C is delivering "something" so, for example, the I2C address must be correct.

Great! Thanks.
Yes, it could be a good way to find the problem.

Hi
I did all suggestions, but it still returns C0.

Standard answer - show your actual code.

Hi,
My code is below.


#include <Wire.h>

void setup() {

  Wire.begin();                // join i2c bus (address optional for master)

  Serial.begin(9600);          // start serial communication at 9600bps
}

uint16_t msb = 0;
uint8_t lsb = 0;
byte V_out = 0;


void loop() {


  // step 1: Unlock PMBUS write protection


  Wire.beginTransmission(0x38);  // transmit to device(0x38)

  Wire.write(0x10);             // sets register pointer to the command register (0x10)

  Wire.write((byte)0x00);      // sends Data:0x00

  //  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);


  // step 2: VOUT setpoint
  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x21);      // sets register pointer to the command register(0x21)

  Wire.write((byte)0x00);      //sends  Byte#0:0x66 to the command register (0x21)

  Wire.write((byte)0xC6);       //sends  Byte#1:0xC6 to the command register (0x21)

  //  Wire.write(0x17);            // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);                   // datasheet suggests at least 65 milliseconds


  // step 3: Set VOUT_OV_WARN

  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x42);      // sets register pointer to to the command register(0x42)

  Wire.write((byte)0x33);      //sends  Byte#0:0x33 to the command register (0x42)

  Wire.write((byte)0xD3);       //sends  Byte#1:0xD3 to the command register (0x42)

  //  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);

  // step 4: Command 0xEC should be send to unlock the MCU which save the data.

  Wire.beginTransmission(0x38);     // transmit to device(0x38)

  Wire.write(0xEC);                 //sets register pointer to to the command register(0xEC)

  Wire.write(0x04);                 //sends  Byt count:N:4(0x04) to the command register (0xEC)

  Wire.write((byte)0x7E);           //sends  Byte#0:0x7E to the command register (0xEC)

  Wire.write((byte)0x15);           //sends  Byte#1:0x15 to the command register (0xEC)

  Wire.write((byte)0xDC);           //sends  Byte#2:0xDC to the command register (0xEC)

  Wire.write((byte)0x42);          //sends  Byte#3:0x42 to the command register (0xEC)

  //  Wire.write(0x45);                // PEC

  Wire.endTransmission();         // stop transmitting

  delay(50);

  //step 5: Command 0x11 should be send to save the Vout setpoint in the MCU


  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x11);            //sets register pointer to to the command register(0x11)

  Wire.endTransmission();      // stop transmitting


  delay(50);


  // step 6: request reading Vout setpoint  from the Buck Converter

  Wire.beginTransmission(0x38);       // transmit to device(0x38)

  Wire.write(0x21);                  //sets register pointer to to the command register(0x21)

  Wire.endTransmission(false);       // stop transmitting


  //  Wire.requestFrom((uint8_t) 0x38, (uint8_t) 2, (uint8_t) true);    //  Wire.requestFrom(38, 2);    // request 2 bytes from peripheral device #0x38


  // step 7: receive reading from the Buck Converter


  if (Wire.requestFrom(0x38, 2) >= 2) {  // if two bytes were received

    uint16_t msb = Wire.read();        // receive high byte (overwrites previous reading)

    msb =  msb << 8;       // shift high byte to be high 8 bits

    uint8_t lsb = Wire.read();    // receive low byte as lower 8 bits

    V_out = msb | lsb;
    Serial.print("  msb = ");
    Serial.println(msb, HEX);   // print the reading
  
    Serial.println(" lsb = ");
    Serial.print(lsb, HEX);   // print the reading

    Serial.print("  V_out = ");
    Serial.print(V_out, HEX);   // print the reading
    Serial.println(" V");
 
  }

  delay(250);                  // wait a bit since people have to read the output :)
}

Note: Data return from MCU is in Vout Mode format : (Byte #1<<8) + (Byte #0)

Please read post #10 carefully. You have to change V_out type too.

Thank you very much for your help.
Sure, I will do it.

EDIT: I changed int V_out to uint16_t V_out, but the result does not change.

So insert your new code.
Every time you change something in the code and ask why it doesn't work - post the code again

State what output you got here an what you were expecting:

Note here in step #2 there is a mismatch between the comment and command:

Hi,
I put the last version code in below.

#include <Wire.h>

void setup() {

  Wire.begin();                // join i2c bus (address optional for master)

  Serial.begin(9600);          // start serial communication at 9600bps
}

 uint16_t msb = 0;
 uint8_t lsb = 0;
 uint16_t V_out = 0;


void loop() {


  // step 1: Unlock PMBUS write protection


  Wire.beginTransmission(0x38);  // transmit to device(0x38)

  Wire.write(0x10);             // sets register pointer to the command register (0x10)

  Wire.write((byte)0x00);      // sends Data:0x00

  //  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);


  // step 2: VOUT setpoint
  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x21);      // sets register pointer to the command register(0x21)

  Wire.write((byte)0x66);      //sends  Byte#0:0x66 to the command register (0x21)

  Wire.write((byte)0xC6);       //sends  Byte#1:0xC6 to the command register (0x21)

  //  Wire.write(0x17);            // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);                   // datasheet suggests at least 65 milliseconds


  // step 3: Set VOUT_OV_WARN

  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x42);      // sets register pointer to to the command register(0x42)

  Wire.write((byte)0x33);      //sends  Byte#0:0x33 to the command register (0x42)

  Wire.write((byte)0xD3);       //sends  Byte#1:0xD3 to the command register (0x42)

  //  Wire.write(0x17);             // PEC

  Wire.endTransmission();      // stop transmitting

  delay(50);

  // step 4: Command 0xEC should be send to unlock the MCU which save the data.

  Wire.beginTransmission(0x38);     // transmit to device(0x38)

  Wire.write(0xEC);                 //sets register pointer to to the command register(0xEC)

  Wire.write(0x04);                 //sends  Byt count:N:4(0x04) to the command register (0xEC)

  Wire.write((byte)0x7E);           //sends  Byte#0:0x7E to the command register (0xEC)

  Wire.write((byte)0x15);           //sends  Byte#1:0x15 to the command register (0xEC)

  Wire.write((byte)0xDC);           //sends  Byte#2:0xDC to the command register (0xEC)

  Wire.write((byte)0x42);          //sends  Byte#3:0x42 to the command register (0xEC)

  //  Wire.write(0x45);                // PEC

  Wire.endTransmission();         // stop transmitting

  delay(50);

  //step 5: Command 0x11 should be send to save the Vout setpoint in the MCU


  Wire.beginTransmission(0x38); // transmit to device(0x38)

  Wire.write(0x11);            //sets register pointer to to the command register(0x11)

  Wire.endTransmission();      // stop transmitting


  delay(50);


  // step 6: request reading Vout setpoint  from the Buck Converter

  Wire.beginTransmission(0x38);       // transmit to device(0x38)

  Wire.write(0x21);                  //sets register pointer to to the command register(0x21)

  Wire.endTransmission(false);       // stop transmitting


  //  Wire.requestFrom((uint8_t) 0x38, (uint8_t) 2, (uint8_t) true);    //  Wire.requestFrom(38, 2);    // request 2 bytes from peripheral device #0x38


  // step 7: receive reading from the Buck Converter


  if (Wire.requestFrom(0x38, 2) >= 2) {  // if two bytes were received

    uint16_t msb = Wire.read();        // receive high byte (overwrites previous reading)

     msb =  msb << 8;       // shift high byte to be high 8 bits

    uint8_t lsb = Wire.read();    // receive low byte as lower 8 bits

    uint16_t V_out = msb | lsb;
    Serial.print("  msb = ");
    Serial.println(msb, HEX);   // print the reading
  
    Serial.println(" lsb = ");
    Serial.print(lsb, HEX);   // print the reading

    Serial.print("  V_out = ");
    Serial.print(V_out, HEX);   // print the reading
    Serial.println(" V");
 
  }

  delay(250);                  // wait a bit since people have to read the output :)
}