Upload fails (error writing to flash at 0x08000000) on Nucleo F303K8 only when initializing CAN peripheral

Hi everyone,

I’m experiencing an issue where instantiating a CAN object or configuring the CAN peripheral causes OpenOCD to fail during the flash upload process on my STM32 board.

If I comment out the CAN initialization, the board flashes perfectly and runs fine. If I leave it in, OpenOCD crashes while trying to write to the flash memory.

My Setup:

  • Hardware: ST Nucleo F303K8 (I have tried this on two separate boards to rule out a hardware defect). I am wiring two STM32s to two CAN transceivers on a breadboard.

  • Framework: Arduino

  • Library: STM32_CAN (by pazi88) - I have also tried raw HAL with the exact same result.

  • IDE: PlatformIO

The Problem: When I attempt to upload code that initializes the CAN peripheral, the upload fails with an OpenOCD error at address 0x08000000.

Things I have already tried:

  1. Deferred Instantiation: I know that calling STM32 HAL functions before main() sets up the system clocks can cause a HardFault. I tried changing the global object to a pointer and using new STM32_CAN(PA11, PA12) inside setup(). The upload still fails.

  2. Raw HAL: I bypassed the Arduino library entirely and tried bare-metal HAL CAN initialization. The exact same upload error occurs.

  3. Reset Configurations: I added upload_flags = -c reset_config none to my platformio.ini to let ST-LINK handle the reset via software. No change.

  4. Manual Reset: I tried holding the physical reset button on the board and releasing it the exact moment OpenOCD connects.

  5. Hardware Swapping: Tested on a completely fresh F303K8 board.

Code (main.cpp):

#include <Arduino.h>
#include "STM32_CAN.h"

// Note: I have also tried deferring this to setup() using a pointer with the same result
STM32_CAN Can1(PA11, PA12); 

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println("Hello, World");
}

Configuration (platformio.ini):

[env:nucleo_f303k8]
platform = ststm32
board = nucleo_f303k8
framework = arduino
debug_tool = stlink
upload_protocol = stlink
build_flags = 
    -DHAL_CAN_MODULE_ENABLED
upload_flags =
    -c reset_config none 
monitor_speed = 115200
lib_deps =
    https://github.com/pazi88/STM32_CAN

The Error Log:

[stm32f3x.cpu] halted due to breakpoint, current mode: Thread 
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
[stm32f3x.cpu] halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
** Programming Started **
Warn : Adding extra erase range, 0x080041c4 .. 0x080047ff
Error: error writing to flash at address 0x08000000 at offset 0x00000000
embedded:startup.tcl:1516: Error: ** Programming Failed **

Is there a known issue with OpenOCD, the ST-LINK, and the F303K8 when the CAN peripheral is invoked? Does CAN share pins/memory with the SWD debug interface on this specific chip that I need to remap?

Any guidance would be hugely appreciated!

Does this also happen with the CAN transceviers disconnected from the board?

SWD programming happens via PA13 / PA14, so the CAN pins PA11 and PA12 should be separate from that, just sharing the same GPIO port.

Unfortunately not. When I completely disconnect the can transceivers I get the exact same 0x08000000 flash error.

Your point about them sharing the GPIOA port with the SWD pins is interesting though. Is it possible that the STM32_CAN library or some other underlying core is conflicting with CAN initialization?

If it helps, GitHub - pazi88/STM32_CAN: CAN bus Library for Arduino STM32 is the library I am using.

I’ve looked at the constructor code and the library and it should not do anything, the construction of the STM32_CAN object only initializes values in the object itself, and does not call any STM32HAL function. That’s the

STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize)

constructor in particular. It should have no problems. The interrupt handlers it defines should also not break anything (CAN_TX_IRQHandler, CAN_RX0_IRQHandler, CAN_RX1_IRQHandler, CAN_SCE_IRQHandler).

Can you try using the https://www.st.com/en/development-tools/stm32cubeprog.html to upload the .bin file? (Into 0x8000000). Maybe it’s just OpenOCD having problems. Do a clean erase, upload and check if the serial messages come through.

That worked! I was able to perform a full chip erase and then write directly from my firmware.bin to0x08000000. I see “Hello, World” coming through serial.

This tells me the code and hardware is just fine. I suppose OpenOCD is the problem, then? If so, why would adding this specific library cause OpenOCD to fail?

Can you manually download the latest release of OpenOCD for your operating system

https://github.com/xpack-dev-tools/openocd-xpack/releases/

And use the commandline to use that new version to upload your firmware? You can get the command that PlatformIO uses with project tasks → Advanced → Verbose Upload.

Don’t forget to adapt all the paths to your new OpenOCD download location.

That way, you should find out whether a newer OpenOCD version fixes your problem. Considering that a mass-erase with STM32CubeProgrammer hasn’t solved the problem with the currently used OpenOCD version anyways.

I was able to install the xPack release (v0.12.0+dev) at C:\openocd\ and run it via command line. Unfortunately, it still fails, but I think I now understand what’s happening.

The issue is a RAM overflow during the flash process:

Info : device id = 0x10016438
Info : flash size = 64 KiB
Warn : Adding extra erase range, 0x080041f8 .. 0x080047ff
Error: Failed to write memory at 0x20003008
Error: error writing to flash at address 0x08000000 at offset 0x00000000

The F303K8 only has 12KB of SRAM (0x3000 bytes). The memory map ends at 0x20002FFF. OpenOCD is trying to write to 0x20003008. This is physically non-existent memory on the chip.

Maybe loading STM32_CAN leaves too little space for OpenOCD to load? This is new territory for me so I may not have the lingo correct. What do you make of this?

That’s weird, OpenOCD is also configured to only use a workarea of 12KB, so it should not try to go beyond that.

Can you add something like

-c "set WORKAREASESIZE 0x2000"

to the flashing command, before the “program” command? Or if needed, find the stm32f3x.cfg file in the OpenOCD folder and fix it there?

Edit: I see that this has been corrected only recently, it was 16 KB before, and that xPack build might have the older version still:

See original ticket and PR

https://review.openocd.org/c/openocd/+/9283

That would also explain why OpenOCD fails to upload. If in the OpenOCD version that PlatformIO uses, OpenOCD’s stm32f3x.cfg is configured for 16 KB maximum worksize are, then the root of the problem is exactly that (with a 12K microcontroller), and the pure file size of the firmware alone made it expose that bug. Without the CAN library, the firmware is smaller than the RAM size of the microcontroller, so the workarea is not fully utilitized. Beyond 12K, it accesses invalid RAM.

Something like

upload_flags =
  -c
  "set WORKAREASESIZE 0x2000"

might even fix it for PlatformIO if the flags are correctly injected.

I found the stm32f3x.cfg in the newly installed xPack release and it looks like we found the issue.

# Work-area is a space in RAM used for flash programming
# By default use 16kB
if { [info exists WORKAREASIZE] } {
   set _WORKAREASIZE $WORKAREASIZE
} else {
   set _WORKAREASIZE 0x4000
}

So while it has been fixed, you are correct that the current xPack build is still outdated. Updating this file fixes the issue.

If anyone else encounters this problem, it does not look like PlatformIO correctly injects the WORKAREASIZE flag mentioned above. Therefore, it is necessary to find and update the stm32fx3.cfg on your system. For windows users, this is at C:\Users\[Name]\.platformio\packages\tool-openocd\openocd\scripts\target\stm32f3x.cfg