Portenta H7: PMIC 3.0V to 3.3V config

If you wonder (like me): the board VCC voltage is 3.0V (when you measure).
OK, I want to change to 3.3V instead: meanwhile I found a solution - but just on a "bare-metal" project (all my source code, from startup, under my control, nothing from Arduino or Mbed).

Potentially, changing the PMIC config on a running Arduino system (with Arduino Bootloader used) will not work (even you try my code).

I have realized:
when you reprogram PMIC, e.g. some registers in PMIC, via I2C write, it is not effective: PMIC wants to get a power-cycle to make changes effective (not during run-time, at startup-time).
When PMIC has booted and started-up - no changes on several registers anymore effective.

So, the only chance to modify PMIC configuration would be:

  • initialize the PMIC before Arduino code will do. After, when Arduino has done - "too late" - no effects, PMIC is already in RUN state.
  • so it works only with a "bare-metal" project or you find a hook to let do your own PMIC config before the Arduino LIB code will do. (potentially not possible, therefore potentially not possible to change the PMIC config during runtime - I have not found a "PMIC soft-reset" function).

Details for curious people - what I have figured out meanwhile
The PMIC is programmed via I2C register writes. But if you see the (minimal) code - it relies on having the OTP programmed in PMIC: some register defaults come from a pre-configured PMIC chip (the OTP in it). Some registers are preloaded from OTP, sometimes you cannot overwrite these registers (e.g. all for SW2).

When I check my chip, the schematics - a bit confusing:
Datasheet says a PMIC chip as "MC34PF1550A4EP" is used. This 4 there means actually: a part with OTP variant 4 programmed (which is for NXP i.MX processors).
But when I read the PMIC registers - and register 0x01 tells me which OTP variant should be there - it tells me "OTP not programmed".

But when I read the OTP registers (details below): I see OTP values. And these values have a clear relation to what I see, e.g. 3.0V is the default.

OTP register values (OTP registers from address 0x1C ... 0x36):

00 06 1a d8
02 00 00 00 00 00 00 00 00 00 00 02 00 84 2b 00
14 00 00 00 00 00

When you decode the OTP register content - use this document for it:
PF1550 OTP programming and registers
you see clearly:

  • SW1 is set to 0x6 = 3.0V: it is used as VCAP, the MCU digital voltage supply (internal MCU voltage)

  • SW2 is also set to 0x6 = 3.0V: this is the other board VCC supply, everywhere you can measure 3.0V

  • SW3 is any other voltage, e.g. you can see it as I2C pull-up register voltage (measure SDA, SCL level in I2C and you see this voltage): it is set to 3.1V. And cannot never be changed, even not by me: it comes directly from fixed programmed OTP which sets it as 0xD = 3.1V.

So, I see 3.0V for board VCC voltage, 3.1 on I2C pull-up signals and 3.0V on VCAP (I can measure over L9) - for the MCU itself.

So, SW1 and SW2 can be programmed - first time after power-cycle and just once (no affect when changing after power cycle again). SW3 can never be changed because it comes from OTP (and 3.1V is fix programmed there).

I am able to change SW1 and SW2 setting and I see 3.3V now.
See in schematics:

  • SW1 from PMIC is VCAP: this is the MCU internal digital voltage (just to measure on L9).

  • SW2, even mentioned as 3.3V in schematics - it burned via OTP to 3.0V. I can change it with my own code and a new power cycle. It is the general board voltage.

  • SW3 is fix, hard-coded via OTP and remains always on 3.1V. It is the voltage you see on pull-up pins. Any write to PMIC registers do not have any effect (SW3 config comes only from OTP).

For the PMIC programming:
PF1550 datasheet

My I2C PMIC init code
Here the code I use on my "bare-metal" project. More as a reference, potentially not helpful to use on an Arduino project (it will not have any effect or does not change the voltage when this code is not called as the very first on startup - before Arduino will do PMIC config).
I2C_PMIC.h (903 Bytes)
I2C_PMIC.c (11.5 KB)

How to read OTP?
Reading and writing PMIC registers is just straight-forward with I2C transactions (see datasheet).
But for reading the OTP - find the other document and details in my code.
How to do?

OTP registers are used via indirect read: there is an OTP controller. You cannot see and read as regular register in PMIC, you had to go via the OTP controller in the chip and let them do.
It works this way:

  • You initialize the OTP Controller, via (keys and config):
    reg. 0x6F = 0x15
    reg. 0x9F = 0x50
    reg. 0xDF = 0xAB
    reg. 0x6B = 0x01

  • You write the OTP register address (as 0x1C...0x36) to FMRADDR register:
    reg. 0xC4 = OTPRegisterAddress

  • you wait a bit, give the OTP Controller time to read this OTP register and to place the result in another register (FRMDATA):
    osDelay(2)
    read reg. 0xC5

Now you have the OTP register value in this register 0xC5 (see my dump above for all OTP registers I have read on my system).

BTW: these OTP registers are not "really" programmable, no way to change:
OTP = One-Time Programmable: when done already once - not possible to do again.
It would need also a high voltage (7.7V) provided externally (not possible on Portenta H7 board). And even you would program OTP a second time: you can just burn fuses (e.g. set to 1), so changing a bit from 0 to 1 might be possible, but never to clear a bit from 1 to 0!
So, just burned once before shipment - no way to change the OTP (as defaults) again.
Potentially, Arduino team does already once for you.

Conclusions
It looks to me: even Arduino mentions an OTP variant 4 part on schematics - they got the PMIC chips as "not OTP programmed" (obvious, if not millions of chips, NXP will not do the favor).
So, they might have programmed the PMIC chips themselves. And they used OTP values for startup with 3.0V (and 3.1V). So, very obvious what I see (and measure) - it is the OTP!

Standby Mode and lower-power config
Have you realized that MCU can drive a pin called "PMIC_STDBY" (as STANDBY on PMIC chip)?
It is PJ0:
a low out on PJ0 is "RUN" mode, a high out on it is "STANDBY" mode: it should toggle the PMIC between these two modes, enter STANDBY ("lower power mode"), e.g. with lower voltages generated.

It works a bit (when I drive and toggle this pin). I see for sure the PMIC has entered STANDBY or RUN mode.

But I had to to modify the PMIC config:
The Arduino default PMIC config does not seem to distinguish between RUN and STANDBY and will potentially NOT support a low-power mode.

But I cannot find a fully reasonably working config:
I can toggle SW2 (the board VCC supply) between 3.3V and 3.0V, but I am not able to set SW1 properly and let it toggle between RUN and STANDBY: if I play with it - the SW2 and SW1 get too low (2.1 and 2.0V) and: even MCU is still running but my USB-C UART is dead (obvious with 2.0V only). Maybe it works to lower also MCU clock, to wait for a "wake up" signal and change back to RUN mode on PMIC.

So, I can just use STANDBY to toggle between 3.3V and 3.0V on SW2 (not SW1 for MCU).
SW3 as 3.1V would never toggle anyway (same SW3_VOLT used from OTP for all modes).

So, when you ask about "MCU lower power mode" - actually this PJ0 pin is your friend: it should toggle the PMIC between RUN and STANDBY mode, from high to lower voltage.
As long as your MCU is still alive - it can react on an event (INT) and change PJ0 pin again, in order to raise the voltage again coming out from PMIC (before MCU restores the system, esp. the clock).

You can read the PMIC status on register 0x67: I see clearly that driving this PJ0 pin changes the state (low = RUN, 1 = STANDBY, value 0xC vs. 0xD).
Just a problem to configure the SW1 voltage, SW2 is fine as long as between 3.3V and 3.0V (but using a lower STANDBY, e.g. 2.5V fails).

Never mind: for me it is fine (I do not want to use the "low power mode"). What it means: when it comes to real "low power modes": the PJ0 on MCU (and software) must be used and the external PMIC will toggle the state and modify the voltage.
No idea if Arduino has an API call which ends up in toggling this pin PJ0.

To get it working with default Arduino PMIC config - no idea. It looks more to me as:
Arduino does not differentiate between RUN and STANDBY state (all the same voltages) in PMIC. Arduino seems to program all the voltages (SW1_VOLT, SW2_VOLT) the same for RUN and STANDBY mode, so no difference in which mode the PMIC is (even possible to let it toggle with PJ0).

But it works a bit to have different RUN and STANDBY voltage settings in my "bare-metal" project.

When you want to have a real "low-power mode" - here my thoughts:

  • have a proper config of SW1_VOLT, SW2_VOLT for RUN and STANDBY mode in PMIC
    (different voltages)

  • Use PJ0 for toggling PMIC between RUN and STANDBY (low = RUN, 1 = STANDBY)

  • when SW enters low-power mode: shout all down, lower the clock (in SW, MCU) and at the end set PJ0 high to toggle PMIC power

  • Potentially, some peripherals might be dead, e.g. USB-C UART due to low voltage, never mind as long as MCU is still running and can see the "wake up" signal

  • MCU will wait for a "wake-up" signal: which one? depends on your system. Be aware of: MCU has some dedicated pins to change internal MCU mode, from low-power to regular, some pins are used for this mode transition

  • if MCU gets this "wake up call": go first to PMIC STANDBY signal - PJ0, set to RUN, than increase the clock again and keep going in RUN mode

It means: a real "low power" mode is only possible with keeping the (external) PMIC in to your focus. Just toggling inside MCU might not lower the power, just in combination with PMIC you can do a real "system low power" mode.

BTW: why just 3.0V for MCU and board?
I could imagine, that Arduino has chosen to program PMIC in a way to provide just 3.0V always in order to make it possible to run from a 3.0V coin cell battery. If system would be set to 3.3V - powered from a coin cell it will drain immediately the battery and the voltage is unreliable.
So, it looks like: the 3.0V config correlates with users using 3.0V coin cell, even it compromises the use with 3.3V for people running the board with USB only (I do not care the charger and battery option - I need the highest performance and reliability... - I want to see 3.3V).

I am fine meanwhile (and understand the board much better and my "bare-metal" project can make use of any features, under my own FULL control). The PMIC is ok, and I understand much better now how to use...

6 Likes

Super helpful, thanks!

Here's a link to a sketch that reads all of the PMIC's I2C registers: Portenta H7 PMIC PF1550 Read I2C Registers - #3 by Disco

Very Helpful! thank you.