Has anyone done PMBus communication using the STM32 HAL library, with one STM32 as master and another as slave?

I configured SMBus using CubeMX and added the X_CUBE_SMBUS package. I see stm32_PMBUS_stack and stm32_SMBUS_stack in the Middlewares folder, but I don’t know what to do next. I don’t know how to use them.

Don’t bother slogging through the low-level source code in the Middleware; it’s too easy to get lost. ST always follows the same pattern. Since you’ve already downloaded the X_CUBE_SMBUS package, just go straight to its installation directory (usually under STM32Cube\Repository) and find the Projects folder. You’ll definitely find ready-made Examples in there for specific dev boards (like NUCLEO or EVAL). Find the PMBus-related project and just open its main.c and stm32_xx_it.c. Focus on two things: first, the Stack Process function called in the main loop; and second, how the callback is written after the slave receives a command. Copy over its application-layer code, tweak it a bit, and you’re good to go.

Bro, don’t rush it. The documentation for this package really is a bit scattered; I was completely lost the first time I used it too.

Your current situation is: the hardware layer (CubeMX) is configured, but you don’t know how to connect the protocol layer (stack) to your application code.

Let me lay out the main workflow based on my understanding. Just follow along:

Step 1: Make sure you generated the correct project structure When adding X-CUBE-SMBUS in CubeMX’s Software Packs, there are two checkboxes in the Mode window: SMBus stack and PMBus extension. Make sure to check both. After generating the code, your project should contain:

  • Middlewares/ST/STM32_SMBus_Stack/ — This is the core protocol stack
  • Drivers/BSP/ — Board support package (if you selected it)

Step 2: Understand how the stack works This stack isn’t meant for you to call HAL_I2C_xxx directly; it wraps a state machine. Your code will mainly interact with three functions:

  • STACK_SMBUS_Init() — Initialization, binds the I2C handle
  • STACK_SMBUS_HostCommand()For the host, initiates a communication
  • STACK_SMBUS_ExecuteCommand()For the slave, callback upon receiving a command

Step 3: How to write the slave code The most crucial part for the slave is CMD_Table. This is an array that tells the stack: “When I receive command code 0x01, which register should I read; when I receive 0x02, which register should I write.”

const tSMBUS_CMD_Table MyCmdTable[] = {
    {0x01, MyReadHandler, MyWriteHandler, 1},  // Command code, read callback, write callback, data length
    {0x02, MyReadHandler2, NULL, 2},
};

Then, inside STACK_SMBUS_ExecuteCommand(), you dispatch based on stackhandle.CurrentCommand.

Step 4: How to write the host code The host side is much simpler. Just construct the command struct and call STACK_SMBUS_HostCommand(&stackhandle, &cmd). Note that this function is non-blocking; you check the result in the interrupt callback via stackhandle.State.

Special reminders:

  • The official examples are in the Projects directory. Find the one closest to your board, like the NUCLEO-G431RB or the F072 Discovery.
  • Make sure to read AN4502. It’s the official application note. It’s thick, but Chapter 8 “Configuration” and Chapter 9 “Project example” are absolute lifesavers.
  • When wiring between two STM32s, both SDA and SCL need pull-up resistors. Even if the boards have internal pull-ups, adding an external 4.7k resistor makes it much more stable. PMBus is more sensitive to signal integrity than I2C.

If you run into issues, post the specific error messages, and we’ll help you take a look.

You are probably looking at the folders from the wrong angle. stm32_SMBUS_stack is the lower communication layer, while stm32_PMBUS_stack sits on top for PMBus command handling.
What you need next is usually: enable the HAL SMBus peripheral, include the middleware source files in the project, initialize the stack in main(), and implement the callback functions required by the library. Without the callbacks, the stack has nowhere to send received frames.

Thanks for the answers, everyone. I’ll go try it out first.

How did the attempt turn out?

I tossed this part to my teammate, I don’t have enough energy :sweat_smile: