Nucleo Board Upload issue

I’m new to PlatformIO. I have a Nucleo-L476RG I’m trying to upload programs to.

I believe my ST-LINK is properly configured, as I can upload with both STM32CubeIde and Arduino IDE.

Here is the log:

Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, jlink, mbed, stlink
CURRENT: upload_protocol = stlink
Uploading .pio\build\nucleo_l476rg\firmware.elf
xPack OpenOCD, x86_64 Open On-Chip Debugger 0.11.0-00155-ge392e485e (2021-03-15-16:44)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
debug_level: 1

srst_only separate srst_nogate srst_open_drain connect_deassert_srst

target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x080034d4 msp: 0x20020000
** Programming Started **
Warn : Adding extra erase range, 0x08003b70 .. 0x08003fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked

I found several posts with similar issues, but none helped.

Any clue?

Okay so what exactly is the issue? The log says everything is fine.

1 Like

Thanks @maxgerhardt , that’s good to know. So the fact that my program doesn’t run (no led blinking, no println working) must come from somewhere else. I will investigate more.

As a side note, please let me express my astonishment to the fact that vivid colors+“target halted”+“Programming Finished”+“Resetting Target”+“shutdown command invoked” means “everything is fine” :slight_smile:

That’s the OpenOCD output that is colored that way by PlatformIO. The output makes sense – first it thas to stop the MCU from executing any further code from flash, then burn the new program into flash, verify it by reading ot out again, then resetting the MCU so that it starts running the new application, and finally shutting down OpenOCD.,

From experience the issue in these cases stems from either wrong code (though unlikely if not even a Serial.println works, or clock initialization issues. See the thread Nucleo F401RE fails to execute Clock init issue - #17 by vortex314. The gist is that there are older Nucleo board revision which do not have the solder bridge set so that a clock-out signal from the ST-Link reaches the main STM32 MCU, but the STM32Duino expects this clock to be there since it programs the MCU to use that clock signal as its own, and if it’s not there your MCU will hang up in an error loop in the clock init function.

You check extremely fast whether you are running into this issue by adding a piece of code at the bottom of your main.cpp file to use only the internal, always-available clock source (MSI + PLL) instead of an external one.

extern "C" void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 40;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
}

if you still have problems, please post the whole platformio.ini and code that you’re testing with.

Thanks a lot @maxgerhardt.

I tried your clock patch, without any success. I was anticipating this result as my Nucleo board is brand new.

Here is my platformio.ini:

[env:nucleo_l476rg]
platform = ststm32
board = nucleo_l476rg
framework = arduino
monitor_speed = 115200

and main.cpp:

#include "Arduino.h"

void setup()
{
  Serial.begin(115200);
  Serial.println("Hello World!");
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  Serial.println("Hello again!");
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
}

It seems the program hangs up at startup in the interrupt default handler. With the debugger, I can trace it back to startup_stm32l476xx.s line 117 where I can see this comment:

This is the code that gets called when the processor receives an
unexpected interrupt.  This simply enters an infinite loop, preserving
the system state for examination by a debugger.

Here is the call stack:

WWDG_IRQHandler@0x080041a8 (c:\Users\S\.platformio\packages\framework-arduinoststm32\system\Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\gcc\startup_stm32l476xx.s:117)
<signal handler called>@0xfffffff9 (Unknown Source:0)
??@0x00000000 (Unknown Source:0)

And here is the full debug log:

Processing nucleo_l476rg (platform: ststm32; board: nucleo_l476rg; framework: arduino)
--------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/nucleo_l476rg.html
PLATFORM: ST STM32 (14.0.0) > ST Nucleo L476RG
HARDWARE: STM32L476RGT6 80MHz, 128KB RAM, 1MB Flash
DEBUG: Current (stlink) On-board (stlink) External (blackmagic, cmsis-dap, jlink)
PACKAGES:
 - framework-arduinoststm32 4.20000.210603 (2.0.0)
 - framework-cmsis 2.50700.210515 (5.7.0)
 - toolchain-gccarmnoneeabi 1.90201.191206 (9.2.1)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 10 compatible libraries
Scanning dependencies...
No dependencies
Building in debug mode
Checking size .pio\build\nucleo_l476rg\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   0.7% (used 956 bytes from 131072 bytes)
Flash: [          ]   2.0% (used 20716 bytes from 1048576 bytes)
========================= [SUCCESS] Took 3.64 seconds =========================
Reading symbols from C:\Users\S\Travail\Projets en cours\LaserPacer\Tech\EmbeddedApp\TestPlatformIO3\.pio\build\nucleo_l476rg\firmware.elf...
undefinedC:\Users\S\.platformio\packages\toolchain-gccarmnoneeabi\bin\arm-none-eabi-gdb.exe: warning: Couldn't determine a path for the index cache directory.
PlatformIO Unified Debugger -> http://bit.ly/pio-debug
PlatformIO: debug_tool = stlink
PlatformIO: Initializing remote target...
xPack OpenOCD, x86_64 Open On-Chip Debugger 0.11.0-00155-ge392e485e (2021-03-15-16:44)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
srst_only separate srst_nogate srst_open_drain connect_deassert_srst

Info : tcl server disabled
Info : telnet server disabled
Info : clock speed 500 kHz
Info : STLINK V2J37M27 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.247613
Info : stm32l4x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32l4x.cpu on pipe
Info : accepting 'gdb' connection from pipe
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x61000003 pc: 0x080041a8 msp: 0x2001ffd0
Info : device idcode = 0x10076415 (STM32L47/L48xx - Rev 4 : 0x1007)
Info : flash size = 1024kbytes
Info : flash mode : dual-bank
WWDG_IRQHandler () at C:\Users\S\.platformio\packages\framework-arduinoststm32\system\Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\gcc\startup_stm32l476xx.s:117
117		b	Infinite_Loop
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08004158 msp: 0x20020000
Loading section .isr_vector, size 0x188 lma 0x8000000
Loading section .text, size 0x4774 lma 0x8000188
Loading section .rodata, size 0x8e4 lma 0x80048fc
Loading section .ARM, size 0x8 lma 0x80051e0
Loading section .init_array, size 0x10 lma 0x80051e8
Loading section .fini_array, size 0x8 lma 0x80051f8
Loading section .data, size 0x94 lma 0x8005200
Info : Padding image section 0 at 0x08005294 with 4 bytes (bank write end alignment)
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08004158 msp: 0x20020000
Start address 0x8004158, load size 21140
Transfer rate: 12 KB/sec, 2642 bytes/write.
Info : Unable to match requested speed 500 kHz, using 480 kHz
Info : Unable to match requested speed 500 kHz, using 480 kHz
Unable to match requested speed 500 kHz, using 480 kHz
Unable to match requested speed 500 kHz, using 480 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08004158 msp: 0x20020000
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08004158 msp: 0x20020000
Temporary breakpoint 1 at 0x8004136: file C:\Users\S\.platformio\packages\framework-arduinoststm32\cores\arduino\main.cpp, line 50.
PlatformIO: Initialization completed
PlatformIO: Resume the execution to `debug_init_break = tbreak main`
PlatformIO: More configuration options -> http://bit.ly/pio-debug
Note: automatically using hardware breakpoints for read-only addresses.

Any clue?

I see, then it shouldn’t be the clock that is the issue. The code also looks fine.

The problem with that is that all interrupts which are unhandled (or fatal) go into this infinite loop (so, also the WWDG_IRQHandler), but it doesn’t show which original interrupt it is that caused it to jump there.

Looking at this you can try and execute

p/a *(uint32_t[8] *)$psp

in the “Debug Console”, which is the GDB console. The third-last element might give a clue as to what code was executed previously that caused the fault.

Otherwise I suggest you open the c:\Users\S\.platformio\packages\framework-arduinoststm32\system\Drivers\CMSIS\Device\ST\STM32L4xx\Source\Templates\gcc\startup_stm32l476xx.s file in VSCode (in the context of the opened PlatformIO project of course) and place a breakpoint in the Reset_Handler, then step through the code and see where it crashes into the exception handler. Important parts to catch would be whether it reaches premain(), implemented in C:\Users\S\.platformio\packages\framework-arduinoststm32\cores\arduino\main.cpp for you, then init() in board.c of the same folder, then hw_config_init, then main() and setup().

The result is:

$1 = {0x20020000
, 0x8004159 <Reset_Handler>
5
, 0x80041a9 <WWDG_IRQHandler>
, 0x0
}

which doesn’t look so enlightening to me.

I traced Reset_Handler. It crashes on this line:

bl __libc_init_array

Notice that it crashes when I try to “Step Into” the line, not inside the __libc_init_array function, which I cannot seem to be able to call.

Hm yes it goes into the standard C library there to initialize the constructors of global C++ objects (and those special functions marked as constructors). Does it reach this when you set a breakpoint there and let it run?

No, it never reaches hw_config_init().
Is it expected that I can not trace into __libc_init_array()?

For information, someone here seemed to have the same issue a while back.

Weird. Can you quickly check whether non-arduino projects work? Create a new project for the Nucleo L476RG and choose “STM32Cube” as framework. Then copy the main.c code from stm32cube-hal-blink and add

build_flags = -DL4

to the platformio.ini. This sets it up for the L4 sereies and already uses PA5 (which is the user LED).

Notice when creating new projects, you actively have to select it using the project environment switcher.

The behavior is not exactly the same under STM32Cube:

  1. If I don’t set any breakpoint in the code, the behavior looks identical: the program hangs in the Default_Handler infinite loop, just like with the Arduino platform (but I cannot confirm it’s triggered by the call to __libc_init_array, see below).

  2. If I set a any breakpoint anywhere in the code, the unexpected exception never occurs but the program hangs after lighting the LED the first time, because HAL_GetTick() always returns 0 and so HAL_Delay() never ends.

To answer an older question first:

Yes because the toolchain only has the code for that in compiled form, not in source code form. The function however simply steps through an arary of function pointer (the constructor / init functions) and executes them one by one. See this post. When you go in the debugger to “switch to assembly”, you should be able to trace into it, and after some time you should be getting into user source-code again when the particular init function is available in source code.

Interesting, but it still is completely broken. There really seems to be a problem with the clock or thet MCU itself, in a really weird way. Or the compiler messes up in a way I’ve never seen before.

I have access to a Nucleo L476RG board that I can test this on to cross-verify. For reference, what is the marking on the PCB? There should be something like MB1136 C-04 written somwhere.

The full string is:

MB1136 C-04
A204401979

Thanks, that helps.
So back to the Arduino platform: the unexpected interrupt occurs at the very first line of function __libc_init_array. The line of code is push {r4, r5, r6, lr}. As soon as I execute it, I get to the interrupt default handler. So I can’t even get to the constructors, let alone getting back to user source code.

Notice that I can run programs from Arduino IDE and STM32CubeIde.

You can do a shot in the dark and reinstall all used packages. Close VSCode, open the C:\Users\<user>\.platformio\packages folder and remove all folders inside there, reopen VSCode (it may need to reinstall some core components), then rebuild the project (it will download all deleted packages like the compiler and framework version etc).

Can you also tell the the exact Arduino IDE settings you have when compiling for the board (In the “Tools” menu) and what version of the STM32Duino core you are running ("Tools → Board → Board Manager " → search for “STM32 MCU based boards”, see here).

This didn’t help, the behavior is the same after reinstalling everything.

Tools menu:
image

STM32 MCU based boards:

Really weird. I have access to my L476RG board from work tomorrow, then I can see if I run into the same issues with PlatformIO but not the Arduino IDE.

The used versions are also the same PlatformIO. From your log I see

Which is the latest PlatformIO and Arduino core 2.0.0 version, same as you’re using it in the Arduino IDE.

Ok, thanks a lot, I’m very curious about what you’ll find tomorrow.

At several points during my tests, PlatformIO displayed warnings about the compiler in use. Each time I couldn’t reproduce the issue (I mean I couldn’t get the warning again), so I let it go. It was always about not finding such or such compiler (different each time) and using ‘cl.exe’ instead. Does it ring a bell?