Portenta H7 bricked

After running some simple test code using the Arduino IDE on my Portenta H7 Lite successfully I switched to the STM32 Eclipse based IDE. I rigged up the ST-Link v2 and stepped through the downloaded code of a project generated by the STM32 IDE. It looked like everything worked fine. The last successful debugger step that I can recall was stepping over the HAL_Init() function. After that I was unable to connect with the STM32 IDE and CubeProgrammer.

I found other posts on this forum with similar problems, Portenta H7 DL2 on - nothing works anymore - Hardware / Portenta - Arduino Forum and Missing 3V3 on JTAG/SWD connector on Portenta breakout board? - Hardware / Portenta - Arduino Forum . The symptoms are that the 3V3 disappears and indeed on my board it was gone too.

I followed their instructions and was able to program the PMIC chip using I2C from an Arduino Uno. After that I got my 3V3 back as 3.3V using the memory contents of tjaekel, or 3.0V after using the direction from user michelesponchiado. Still, I am unable to connect with the ST-Link v2. The orange/red light turns off so I'm doing all the steps the recommended but the STM32 CubeProgrammer still refuses to connect.

I am running out of ideas. Any thoughts about how I can bring my Portenta H7 Lite back to life?

FYI I am using it with the Portenta breakout board to be able to use the ST-Link v2. I will be happy to share my Arduino I2C code once my first post (this one) is approved.

Good news! My Portenta H7 Lite is alive again. This happened after I connected the RESET wire as described by tjaekel in Portenta H7: debug messages via SWO Viewer - Hardware / Portenta - Arduino Forum . After that I was able to connect though ST-Link v2 using the hardware reset option. Thank you tjaekel for describing all your efforts in detail! I am now debugging in the STM32 Eclipse IDE and can proceed with my work.

It is a bit nebulous to me how all this fixed it - I think setting the PMIC registers helped. Here is the code that can run on an Arduino Uno using its I2C (Wire) implementation. Maybe it helps someone else.

#include <Wire.h>

const int nMichele = 12;//13;
uint16_t regAddrMichele[nMichele] = {0x4f, 0x50, 0x4c, 0x4d, 0x52, 0x53, 0x9c, 0x9e, 0x42, 0x94, 0x3b, 0x35};//, 0x42};
byte     regValMichele[nMichele]  = {0x00, 0x0f, 0x05, 0x03, 0x09, 0x0f, 0x80, 0x20, 0x02, 0xa0, 0x0f, 0x0f};//, 0x01};

const int nTJaekel = 160;
byte regValTJaekel[nTJaekel] = 
 {0x7c ,0x00 ,0x11 ,0x00 ,0x00 ,0x00 ,0x88 ,0x00 ,0x00 ,0x07 ,0x00 ,0x04 ,0x07 ,0x04 ,0x00 ,0x03
 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x07 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00
 ,0x00 ,0x05 ,0x00 ,0x00 ,0x00 ,0x3f ,0x00 ,0x00 ,0x08 ,0x1f ,0x04 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00
 ,0x00 ,0x00 ,0x06 ,0x06 ,0x06 ,0x0f ,0x00 ,0x00 ,0x0a ,0x0a ,0x0a ,0x0f ,0x00 ,0x00 ,0x0d ,0x0d
 ,0x0d ,0x03 ,0x01 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x05 ,0x03 ,0x00 ,0x00
 ,0x0f ,0x00 ,0x09 ,0x0f ,0x00 ,0x00 ,0x00 ,0x00 ,0x21 ,0x80 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x01
 ,0x02 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x0c ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00
 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00
 ,0x68 ,0x00 ,0xff ,0x00 ,0xac ,0x00 ,0x20 ,0x03 ,0x04 ,0x02 ,0x00 ,0x00 ,0x00 ,0x40 ,0x05 ,0x6b
 ,0x00 ,0x00 ,0x00 ,0x00 ,0xa0 ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x80 ,0x00 ,0x20 ,0x00};

uint16_t regAddrTJaekel[nTJaekel] = {
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  10,11,12,13,14,15,16,17,18,19,
  20,21,22,23,24,25,26,27,28,29,
  30,31,32,33,34,35,36,37,38,39,
  40,41,42,43,44,45,46,47,48,49,
  50,51,52,53,54,55,56,57,58,59,
  60,61,62,63,64,65,66,67,68,69,
  70,71,72,73,74,75,76,77,78,79,
  80,81,82,83,84,85,86,87,88,89,
  90,91,92,93,94,95,96,97,98,99,
  100,101,102,103,104,105,106,107,108,109,
  110,111,112,113,114,115,116,117,118,119,
  120,121,122,123,124,125,126,127,128,129,
  130,131,132,133,134,135,136,137,138,139,
  140,141,142,143,144,145,146,147,148,149,
  150,151,152,153,154,155,156,157,158,159
};

const byte one = 0x01;
const byte zero = 0x00;
const byte sendRestart = false;

void readI2C(byte devAddr, int m, int n)
{
  Serial.println();
  for (int i = 0; i < m; i++)
  {
    Serial.print(byte(i*16), HEX);
    Serial.print(" | ");
    for (int j = 0; j < n; j++)
    {
      Wire.beginTransmission(devAddr);
      int nWritten = 0;
      nWritten += Wire.write(uint16_t(i*16+j));
      int error = Wire.endTransmission(sendRestart);
      if (error != 0)
      {
        Serial.print("Transmission error, code = ");
        Serial.println(error);
      }
      int nRead = Wire.requestFrom(devAddr, one);
      if (nRead == 1)
      {
        byte valRead = Wire.read();
        Serial.print(valRead, HEX);
        Serial.print(" ");
      }
    }
    Serial.println();
  }
}

void writeI2C(byte devAddr, uint16_t regAddr[], byte regVal[], int n)
{
  Serial.println();
  for (int i = 0; i < n; i++)
  {
    Wire.beginTransmission(devAddr);
    int nWritten = 0;
    nWritten += Wire.write(regAddr[i]);
    nWritten += Wire.write(regVal[i]);
    int error = Wire.endTransmission();
    if (error != 0)
    {
      Serial.print("Transmission error, code = ");
      Serial.println(error);
    } else {
      Serial.print("Wrote ");
      Serial.print(nWritten);
    }
    Wire.beginTransmission(devAddr);
    nWritten = 0;
    nWritten += Wire.write(regAddr[i]);
    error = Wire.endTransmission(sendRestart);
    int nRead = Wire.requestFrom(devAddr, one);
    if (nRead == 1)
    {
      byte valRead = Wire.read();
      Serial.print(" bytes to register ");
      Serial.print(regAddr[i], HEX);
      Serial.print(": wrote ");
      Serial.print(regVal[i], HEX);
      Serial.print(", read ");
      if (valRead != regVal[i]) {
        Serial.print(valRead, HEX);
        Serial.println(" *** ERROR ***");
      } else {
        Serial.println(valRead, HEX);
      }
    } else {
      Serial.print("Error in reception, bytes received = ");
      Serial.println(nRead);
    }
  }
  
}

void scanI2C() {
  byte error, address;
  int Devices;
  Serial.println();
  Serial.println("I2C Scanner");
  Serial.println("Scanning...");
  Devices = 0;
  for(address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
      Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
      Devices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
      Serial.print("0");
      Serial.println(address,HEX);
    }
  }
  if (Devices == 0)
    Serial.println("No I2C devices found");
  else
    Serial.println("done");
}

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

  scanI2C();
  Wire.begin();
  Wire.setTimeout(1000);
  byte devAddr = 0x08;
  readI2C(devAddr, 16, 16);
  //writeI2C(devAddr, regAddrMichele, regValMichele, nMichele);
  writeI2C(devAddr, regAddrTJaekel, regValTJaekel, nTJaekel);
  readI2C(devAddr, 16, 16);
}

void loop()
{
  scanI2C();
  delay(5000);          
}

Cool!
Do you know, Arduino has published the source code for the MCU Boot (bootloader)?
You can find now the I2C PMIC config in this bootloader source code.
Arduino bootloader published
Github with bootloader source code

BTW:
What are you doing? It sounds like - you use STMCubeIDE to generate and flash FW for Portenta H7. COOL - I want to do as well - Please, can you share some approaches, how? Thank you.

Do you overwrite the bootloader? Do you flash your own FW code from start of flash ROM, 0x08000000?

I am so keen on a setup to use STMCubeIDE, all as full source code and also to use the space allocated by the bootloader (I am running out of space).

Please, share some details how to use STMCubeIDE, in particular how to setup all the Include Paths (-I) and Macro-Definitions? This sounds the most complicated part to me, to find all the files in Arduino, mbed library installed.

This might help as well related to the PMIC:
Portenta H7 PMIC configuration

BTW: you do not need to write all these registers. And eventually, you have to write registers in a different order.
What the bootloader is doing - find here:
bootloader PMIC configuration

Hello tjaekel first of all thanks again for your posts, without them I would have been nowhere.

The STM32CubeIDE worked out of the box for me. I created a project for my target. It lets you select the target first. Based on that it creates a .ioc file with a graphical representation of the MCU where you can configure your project. When saving the file, it asks you if you want to generate code (yes). Then you can select either the M7 or the M4 core, click Debug as... et voila you are on the target. I did not have to do anything out of the ordinary. I did not run out of space and did not have to configure include paths. It sounds to me like you have an installation problem of your IDE.

I haven't yet flashed a new bootloader (that I think has disappeared on my system). That implies an odd procedure for now when I restart: I have to set both boot dip switches away from the Arduino PRO label, plug the USB cable in, run the above code on the Uno to activate the 3V3, then double-click the reset switch on the breakout board. Then SM32CubeProgrammer lets me connect with the hardware reset selected. However, when I download a project from the STM32CubeIDE, it gets stuck in some power management code called from the clock configuration. Until I moved both dip switches to the other side and re-flashed the project, it won't get past that point.

It worked 4x so far. Next stop, get a bootloader working.

I read that post and tried those settings first (also copied in Missing 3V3 on JTAG/SWD connector on Portenta breakout board? - Hardware / Portenta - Arduino Forum ). That got me 3.0V on the 3V3. Only after I tried your settings, I got 3.3V on the 3V3, which I liked better.

My understanding: Portenta H7 VDD is not 3.3V, instead it is only 3.1V. It seems to come from the PMIC config and PMIC generating the VDD (maybe an LDO voltage drop on PMIC).
3.1V is still OK.
The only "issue" : if you drive input signal into Portenta H7, e.g. I2C, and they are pulled-up to 3.3V - the input signal level is higher as MCU VDD. OK, most of GPIOs are 5V tolerant. But not nice to provide signals with levels higher as MCU core itself.

In that case, in loop() of the code I posted, uncomment the first writeI2C() call and comment the next one. That gave 3.1V when I tried it. Thanks for the info, I don't know if that 0.2V difference would kill it sooner than any other things I might try playing around with it.

Regarding the other problem of how to use the STM32CubeIDE for Portenta H7 development: Whenever downloading an image from the STM32 IDE, the Arduino bootloader does not work anymore. To get the Arduino functionality back you have to burn the bootloader from the Arduino IDE through the ST-Link v2. It works, thankfully! Also, the IDE is written for MCUs and has no board support package for the Portenta H7. The Arduino IDE does.

I can see 2 ways of developing code with the STM32 IDE: One way is as described above using an Uno to configure the PMIC then flipping the dip switches twice to get started (crazy workflow of course but it's how I got it back to life). The other is to burn the bootloader from the Arduino when you are done for the day so you can boot it and connect next time without a problem.

Eventually you will want to do the final "production" build and download from the Arduino IDE because it provides a bootable image stored in flash. I don't see how you could do that easily from the STM32 IDE without first writing a board support package for the Portenta H7 with a boot loader that stores/loads the image to/from flash. That's to the best of my knowledge.

I am very happy that my system works again and that I know how to fix it when I accidentally ruin it.

"ahhhh, I see": it looks like, you build a FW in STM32CubeIDE which links all to ROM flash starting address 0x08000000.
This overwrites the bootloader and you CANNOT, never, go back to use Arduinio IDE and bootloader. You had to re-reflash the bootloader with your debugger again (you have overwritten it).

Using STM32CubeIDE
I see two approaches to develop code for Portenta H7 with other IDEs (not Arduino, instead STM32CubeIDE or even IAR):

  1. write still a "sketch" where the code still starts "after" the bootloader. Assume all is built, but the debugger should not write your own code starting from 0x08000000 - instead the start address is 0x08040000. So, you do not overwrite the bootloader, you just overwrite the "user code".
    But "my" problem is this: a "sketch" has just entry points, functions to be provided as "setup()" and "loop()". How does the bootlader find the entry points for these functions?
    I think: the main(), which sits in bootloader, jumps to setup() and to loop() afterwards. But how? When the address is not fix - how does the bootloader know where these functions are?
    So, possible just to generate the "sketch" code and debugger flashes just my user code, the bootloader not needed to be used in order to flash, but after a reset the bootloader jumps to my sketch, the entry functions in my sketch. But how does it know where they are?

  2. You write ALL code, really ALL, yourself: You do not need the bootloader but your code has to do ALL what the bootloader does, e.g. configure the PMIC.
    So, you could let flash your code at start address 0x08000000 (and you overwrite bootloader), but your entire FW code has to do all what is needed to do.
    And also all the "Startup.S" code is needed, the vector table, the INT handlers (as the bootloader has).

I thought also to use STM32CubeIDE as IDE, but it ends up in these questions:

  • What is done in the bootloader? And now I have to do the same system initialization, startup, such as:
    configure the PMIC, setup the USB-C for UART, configure the clocks for MCU and mandatory
    peripherals needed during startup (e.g. I2C to PMIC), Vector table, INT handlers ... - HEAVY to know what and how...

  • OK, let's assume I go with all as source code (Open Source), with the STM HAL drivers etc. But some stuff can be tricky: example: configure SD-RAM? What is the pin setting? What is the configuration of Memory Controller etc.? I had to do all again myself, test all again myself ... And Arduino does NOT provide Open Source so that I can copy and paste, at least I can have a look how it works on Portenta HW.

It should be possible to program ALL on Portenta H7, with STM32CubeIDE. But for all the features provided by the board, e.g. how to use SPI flash on board, SD-RAM on board, USB-C for UART or even other devices via USB, SD Card ... it is so much work to start from scratch and bring-up all with a real Open Source system (meaning: all pieces of Source Code in my hands and under my control).

Still my intention to do, to have a full Open Source environment, even a faster IDE - but not so much time left to work on it.

Yes, we had to write a BSP (Board Support Package) for using native STM HAL driver code and to use STM32CubeIDE as an IDE (with really FULL Source Code and Open Source).

Technically not so difficult - just time consuming:
Even I know meanwhile how to configure the PMIC - how to bring-up the USB-C UART (at least)? It is not really "easy": there are chips on board providing the USB-C connectivity. So, it ends up in deep understanding of schematics, the datasheets of the other chips onboard ...

Let's say my simple goal is this:

  • get rid of the bootloader: instead, I write my own startup, flashing my code from 0x08000000, and my own code has the proper "Startup.S", vector table and mandatory INT handlers defined

  • but at least I want to see the UART alive again, as USB-C to host: and here I am struggling already: it does not seem so easy to understand the USB-C bridge (chips) on Portenta H7 board. You might need to configure and use other chips on board. And for these chips - there are not examples (not provided by STM, not part of STM HAL drivers). And Arduino does not provide Open Source code so that you cannot have a look.

Even possible - I am sure - but so much time needed! And is it worth all this effort when you would trap at the end into "legal issues"? (assuming Arduino does not want to have all really as Open Source, they do not like an alternative IDE, they do not want to deal with support for platforms and environments they do not have provided ... reasonable from their perspective).
So, at the end more a "personal fun project" (which I think is "necessary" to do, esp., due to this crazy turnaround compile time on Arduino IDE, missing features such as a real debugger).
But you would not be able to promote, to "sell" your - for sure BETTER - solution. You might step into a "legal issue trap".

I am sorry to abuse this thread for brainstorming myself (for the intention to use another IDE, e.g. STM32CubeIDE).

Here is another "tiny" problem:
Let's assume you want to build just a "sketch" with another IDE: OK, you can create a similar linker script file as "linker_script.ld": where you have those definitions:

MEMORY
{
  FLASH (rx)     : ORIGIN = 0x08040000, LENGTH = 0x8040000 - CM4_BINARY_START
  DTCMRAM (rwx)  : ORIGIN = 0x20000000 + (((166 * 4) + 7) & 0xFFFFFFF8), LENGTH = 128K - (((166 * 4) + 7) & 0xFFFFFFF8)
  RAM (xrw)      : ORIGIN = 0x24000000, LENGTH = 0x80000
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (rwx)  : ORIGIN = 0x00000000, LENGTH = 64K
  SDRAM (rwx)    : ORIGIN = 0x60000000, LENGTH = 8M
}

So, you could make sure that the code you generate starts at 0x08040000 (for your "sketch").
All fine (let's also assume that we manage properly the entry to our "sketch").

But:
If you connect via ST-LINK debugger and you want to flash just the code starting at 0x08040000 - ok, but the setting in Debugger GUI (ST-LINK-Utility, STM32CubeProgrammer, or the debug settings in your project) is as : "erase entire flash before programming" - You would still "kill" and delete the bootloader (which would be still needed to have on ROM flash!)

So, question is: "could I configure debugger, STM flash tools ..., in a why NOT to erase ALL, instead just part of ROM flash, to let 0x08000000 ... 0x0803FFFF untouched and never erased?" Potentially NOT!

The original bootloader seems to do this:

  • it erases just the sectors in ROM flash used by the user code, "sketch" code
    (the bootloader is code running after reset which will erase sectors and flash sectors on ROM where it is running from itself - other not used sectors touched)

  • it never erases itself (0x08000000 ... 0x0803FFFF), the bootloader code, which is executed during "boot loading" - it is never killed, just the "user space in ROM" (never "entire flash ROM erased as a real debugger would potentially do)

  • and bootloader seems to relocate the INT vector table: It is on DTCMRAM, 0x020000000 ... I guess, it is the vector table which comes with your user "sketch" code: another vector table generated, coming with your code, and bootloader "moves" it to DTCMRAM.

If bootloader sets the MCU internal register to use now the vector table coming with your "sketch code" - any wrong setting of INT handler entry addresses in it will fail. It means to me: even you generate just your own "sketch" with another GUI: you had to make sure that the "expectations by the bootloader" are still correct (entry addresses for functions called in "sketch", such as "setup()" and "loop()") as well as the system vector table is correct).

Also: even you would build your "sketch" with other IDE, even you would provide the INT vector table again in your "sketch" - make sure never to use DTCMRAM from start: the first part is reserved for the new vector table. bootloader would still copy vector table and make it active there. So, it must be correct. So, your "linker_script.ld" must be aligned with the expectations of the bootloader.

The "devil sits in the details". And reverse engineering "so much" does not make any sense, in the ages of Open Source (and STM is well known to provide such one, but Arduino does not).

I have no intention of writing my own BSP that includes serial over USB support and use of the external flash and SDRAM, for instance. There are a few options some of which you mentioned:

  • Redefine flash starting at 0x00804000 and have a debug config starting from there. That way you won't overwrite the boot loader. But you won't have the other benefits from the BSP. It would be useful to write MCU test code and export the generated code to the Arduino project. That's how I got my first program working. So we don't have to worry too much about main() vs setup() and loop() - which is not much of a problem anyway because the generated main() also has a while (1) loop - very similar.

  • Write your own BSP - takes a tremendous amount of time, out of the question for me. I have seen source code with message queues, DMA and SPI-based flash - I will be very happy using someone else's binaries. Arduino seems to have some nice tutorial examples.

  • I would probably be fine with using the ST-Link v2 with the Arduino debugger, but I don't know if this is available. I see a topic "Debugging with the Ardiuono v2.0 IDE" but it appears to be for a limited set of targets and for JLink. I'm seeing others were successful with Visual Micro and VSCode so maybe I'm missing something. Otherwise see below.

  • From the generated Arduino compilation and link commands echoed in the Arduino GUI, create an Eclipse makefile project that does the same. For that you need to set up include paths, link paths, makefile fragments, makefile build targets, all pretty straightforward. You would be linking in Arduino binaries for the parts you don't have source code for. I've done something like this for a Wemos Arduino for my telescope mount project once I found the Arduino GUI too limiting. You can browse the source code in Eclipse. Though I have not tried it, I presume it should be possible to use the ST-Link v2 for debugging with this Makefile project just like with an STM32 project (I see some hints in the Debug configuration, check also the generated STM32 commands for this in the IDE). You could copy the STM32 project parts that you need or maybe you can add targets and makefile fragments that take over that part as well, if you are ambitious. That should let you allow access to all the BSP features. A bit of work and not super elegant.

For now, I think I will simply use the STM32 IDE for MCU development and copy the results into my Arduino project. If I need to do a lot of debugging for instance for message protocols over the serial-over-USB port, I might go to the last option mentioned.

I tried to recover my portenta with my own code, but it didn't work. i could read registers, but writing them and then reading was not a success. I used a mkr1000 and a ESP32.

If i try your code i get quite a lot errors:

2C Scanner
Scanning...
I2C device found at address 0x08  !
I2C device found at address 0x60  !
done

0 | 7C 0 11 0 0 0 88 0 0 7 0 4 7 0 0 3 
10 | 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 
20 | 0 5 0 0 0 3F 0 0 D 1F 4 0 0 0 0 0 
30 | 0 0 6 6 6 0 0 0 6 6 6 0 0 0 D D 
40 | D 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
50 | 0 0 0 0 0 0 0 0 1 80 0 0 0 0 0 0 
60 | 0 0 0 0 0 0 0 C 0 0 0 0 0 0 0 0 
70 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
80 | 68 0 FF 0 AC 0 20 3 4 2 0 0 0 40 2 AB 
90 | 0 0 0 0 A0 0 0 0 0 0 0 0 0 0 0 0 
A0 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
B0 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
C0 | 0 0 0 0 0 0 0 3F 28 4 0 2B 0 3B 0 0 
D0 | 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 
E0 | 0 0 A 20 0 0 0 0 0 0 0 0 0 0 0 0 
F0 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

Wrote 2 bytes to register 0: wrote 7C, read 7C
Wrote 2 bytes to register 1: wrote 0, read 0
Wrote 2 bytes to register 2: wrote 11, read 11
Wrote 2 bytes to register 3: wrote 0, read 0
Wrote 2 bytes to register 4: wrote 0, read 0
Wrote 2 bytes to register 5: wrote 0, read 0
Wrote 2 bytes to register 6: wrote 88, read 88
Wrote 2 bytes to register 7: wrote 0, read 0
Wrote 2 bytes to register 8: wrote 0, read 0
Wrote 2 bytes to register 9: wrote 7, read 7
Wrote 2 bytes to register A: wrote 0, read 0
Wrote 2 bytes to register B: wrote 4, read 0 *** ERROR ***
Wrote 2 bytes to register C: wrote 7, read 7
Wrote 2 bytes to register D: wrote 4, read 0 *** ERROR ***
Wrote 2 bytes to register E: wrote 0, read 0
Wrote 2 bytes to register F: wrote 3, read 3
Wrote 2 bytes to register 10: wrote 0, read 0
Wrote 2 bytes to register 11: wrote 0, read 0
Wrote 2 bytes to register 12: wrote 0, read 0
Wrote 2 bytes to register 13: wrote 0, read 0
Wrote 2 bytes to register 14: wrote 0, read 0
Wrote 2 bytes to register 15: wrote 0, read 0
Wrote 2 bytes to register 16: wrote 0, read 0
Wrote 2 bytes to register 17: wrote 0, read 0
Wrote 2 bytes to register 18: wrote 0, read 0
Wrote 2 bytes to register 19: wrote 7, read 7
Wrote 2 bytes to register 1A: wrote 0, read 0
Wrote 2 bytes to register 1B: wrote 0, read 0
Wrote 2 bytes to register 1C: wrote 0, read 0
Wrote 2 bytes to register 1D: wrote 0, read 0
Wrote 2 bytes to register 1E: wrote 0, read 0
Wrote 2 bytes to register 1F: wrote 0, read 0
Wrote 2 bytes to register 20: wrote 0, read 0
Wrote 2 bytes to register 21: wrote 5, read 5
Wrote 2 bytes to register 22: wrote 0, read 0
Wrote 2 bytes to register 23: wrote 0, read 0
Wrote 2 bytes to register 24: wrote 0, read 0
Wrote 2 bytes to register 25: wrote 3F, read 3F
Wrote 2 bytes to register 26: wrote 0, read 0
Wrote 2 bytes to register 27: wrote 0, read 0
Wrote 2 bytes to register 28: wrote 8, read 5 *** ERROR ***
Wrote 2 bytes to register 29: wrote 1F, read 1F
Wrote 2 bytes to register 2A: wrote 4, read 4
Wrote 2 bytes to register 2B: wrote 0, read 0
Wrote 2 bytes to register 2C: wrote 0, read 0
Wrote 2 bytes to register 2D: wrote 0, read 0
Wrote 2 bytes to register 2E: wrote 0, read 0
Wrote 2 bytes to register 2F: wrote 0, read 0
Wrote 2 bytes to register 30: wrote 0, read 0
Wrote 2 bytes to register 31: wrote 0, read 0
Wrote 2 bytes to register 32: wrote 6, read 6
Wrote 2 bytes to register 33: wrote 6, read 6
Wrote 2 bytes to register 34: wrote 6, read 6
Wrote 2 bytes to register 35: wrote F, read F
Wrote 2 bytes to register 36: wrote 0, read 0
Wrote 2 bytes to register 37: wrote 0, read 0
Wrote 2 bytes to register 38: wrote A, read A
Wrote 2 bytes to register 39: wrote A, read A
Wrote 2 bytes to register 3A: wrote A, read A
Wrote 2 bytes to register 3B: wrote F, read F
Wrote 2 bytes to register 3C: wrote 0, read 0
Wrote 2 bytes to register 3D: wrote 0, read 0
Wrote 2 bytes to register 3E: wrote D, read D
Wrote 2 bytes to register 3F: wrote D, read D
Wrote 2 bytes to register 40: wrote D, read D
Wrote 2 bytes to register 41: wrote 3, read 3
Wrote 2 bytes to register 42: wrote 1, read 1
Wrote 2 bytes to register 43: wrote 0, read 0
Wrote 2 bytes to register 44: wrote 0, read 0
Wrote 2 bytes to register 45: wrote 0, read 0
Wrote 2 bytes to register 46: wrote 0, read 0
Wrote 2 bytes to register 47: wrote 0, read 0
Wrote 2 bytes to register 48: wrote 0, read 0
Wrote 2 bytes to register 49: wrote 0, read 0
Wrote 2 bytes to register 4A: wrote 0, read 0
Wrote 2 bytes to register 4B: wrote 0, read 0
Wrote 2 bytes to register 4C: wrote 5, read 5
Wrote 2 bytes to register 4D: wrote 3, read 3
Wrote 2 bytes to register 4E: wrote 0, read 0
Wrote 2 bytes to register 4F: wrote 0, read 0
Wrote 2Error in reception, bytes received = 0
Transmission error, code = 2
Error in reception, bytes received = 0
Transmission error, code = 2
....

On another bricked Portenta i got those error (different registers):

Wrote 2 bytes to register 6: wrote 88, read 80 *** ERROR ***
Wrote 2 bytes to register B: wrote 4, read 0 *** ERROR ***
Wrote 2 bytes to register D: wrote 4, read 0 *** ERROR ***
Wrote 2 bytes to register 28: wrote 8, read 1 *** ERROR ***

After writing the registers, the I2C scanner is not able to find the portenta again (probaly some fault mode in the state machine from the PMIC)
After disconnecting the portenta from the power supply and waiting a little bit it gets recognized again.

I bricked the board only using the visio shield and the stlink.

Do you know what could triggers those errors while writing the registers?

Leaving the program aside, what I found later on is a much simpler way to fix it that does not require programming. See this link. Try that first. Otherwise, (since I can't recollect exactly how I set up my program flashing), check if you applied 3.3V (at your own risk of course - I do it all the time when this trouble arises) and see if that makes a difference. Otherwise, the program has choice of Tjaekel's and Michele's settings. Comment the Tjaekel ones and uncomment Michele's. Those are fewer settings - the exact ones from the boot loader - that make it less likely to lead to a write conflict.

BTW: why do you try to write all registers, even the ChipID (a read-only register)?
And you had to write registers in a different order (do not write back "a register dump", it does not make sense).

It looks like, you see the PMIC chip.
Just write the minimal required registers to enable the power, e.g. as:

/* Portenta H7 PMIC I2C recovery */
int PMIC_Recover(void)
{
/* slave address PMIC */
#define PMIC_I2C_SLAVE_ADDR	(0x08 << 1)

	//check if we can read the PMIC ChipID (should be 0x7C)
	uint8_t data[2];
	int err;

	err = I2CUser_MemReadEx(PMIC_I2C_SLAVE_ADDR, 0, data, 1);
	if (err)
		return err;				//ERROR

	if (data[0] != 0x7C)
	{
		print_log(UART_OUT, "*E: external PMIC not found\r\n");
		return 0;				//ERROR - incorrect ChipID
	}

	//initialize the PMIC registers:
	// LDO2 to 1.8V
	  data[0]=0x4F;
	  data[1]=0x0;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  /* ATTENTION: if I write this register - the I2C is dead, read ChipID does not work anymore
	   * write this register as the last one!
	   */
#if 0
	  data[0]=0x50;
	  data[1]=0xF;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));
#endif

	  // LDO1 to 1.0V
	  data[0]=0x4c;
	  data[1]=0x5;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  data[0]=0x4d;
	  data[1]=0xF;		//was 0x3
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  // LDO3 to 1.2V
	  data[0]=0x52;
	  data[1]=0x9;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  data[0]=0x53;
	  data[1]=0xF;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  osDelay(10);

	  //charger LED off - duty cycle
	  data[0]=0x9C;
	  data[1]=(1 << 7);		//0x80
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  // Disable charger led
	  data[0]=0x9E;
	  data[1]=(1 << 5);		//0x20
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  osDelay(10);

	  // SW3: set 2A as current limit
	  // Helps keeping the rail up at wifi startup
	  data[0]=0x42;
	  data[1]=2;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  osDelay(10);

	  // Change VBUS INPUT CURRENT LIMIT to 1.5A
	  data[0]=0x94;
	  data[1]=(20 << 3);		//0xA0
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  // SW2 to 3.3V (SW2_VOLT)
	  data[0]=0x3B;
	  data[1]=0xF;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

	  // SW1 to 3.0V (SW1_VOLT)
	  data[0]=0x35;
	  data[1]=0xF;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));

#if 1
	  osDelay(10);
	  data[0]=0x50;
	  data[1]=0xF;
	  I2C1_Write(PMIC_I2C_SLAVE_ADDR, data, sizeof(data));
#endif

	  return 0;		//OK
}

1 Like

Thank you for your replies!
I wrote to all registers, because the script in this thread does.
In my own script i wrote only to a few registers.

Now I can write the register you mentioned and read those back with the right values. I can even measure 2.999V on the 3V3 pin. I tried to connect the STLink which didn't work. I connected an external 3.3 Voltage to the pin (maybe under 3 V still to low for the stlink), but it didn't make any difference. I switched the dip switches on the breakout board, but it still didn't do anything.

Something is still not right, but i can't imagine that something on the board got destroyed, because it got bricked while using the vision shield.

2.99V makes sense (set to 3.0V).
ATTENTION: do you mean 3.3V to the VCC pin on JTAG/Debug header?
NO!
It is not a pin to provide (input) 3.3V.
It is the pin where ST-LINK senses the target voltage. It is an output to the ST-LINK.
ST-LINK will measure voltage there: if missing (too low) - ST-LINK does not find target.
(I think it displays in log message what the target voltage is).
This JTAG/SWD VCC goes to the ST-LINK and must be connected.

When you change the BOOT DIP switch plus pressing Reset (or the blue ON button - not sure which one) - afterwards you should be able to use "dft-util.exe" and flash a firmware from CMD line.

1 Like

I was able to recover the board.
Playing with the dip switches and pressing the on button on did help (holding on while conneting the stlink).
After uploading the bootloader i need to switch the BT_SELC to the upper position, and then it worked.

Why did you set the 3V3 to 3.0V? In the Arduino datasheet the typical voltage is 3.1 V which is interesting.

Thank you for your help!

1 Like

Great, well done.
(BTW: it is just the BOOT DIP switch needed).
Yes, after flashing done: change it back and reset normally.

I want to have 3V3 for these reasons:
I want to run the board with (at least) nominal clock, 480 MHz. I need the full performance possible. With lower voltage I might need also larger FLASH_LATENCY.
I have realized, I can overclock a bit, e.g. 490 MHz, 500 MHz can be flaky, and reduce the flash latency needed.

I need SPI, I2C as interface to other external chips (testing those chips). This has to be as fast as possible (measuring the SPI, I2C performance).
There also ribbon cables involved, longer cables. If I lower the VCC - also the high level of signals is affected, the drive strength, the speed on GPIOs etc.
Lowering the VCC is good for heat dissipation but could degrade a bit the max. system performance (not just MCU, also internal logic, like bus fabric, memories, peripheral devices, signal integrity on external signals etc.).

3.0V is fine for most of the use cases, but not for my requirements: evaluating external chips and measuring their speeds on interfaces. I need nominal conditions on all parts, also on external chips (signal levels).

1 Like