cancel
Showing results for 
Search instead for 
Did you mean: 

Calling a virtual function seems to stop the execution of the MCU (Nucleo F446RE)

ECLEW.1
Associate III

I'm trying to port over a JUCE framework project (a wavetable VCO), and I'd like to test it on a Nucleo-F446RE that I got about a year ago.

My entire build system is a clone of this lady Emilie Gillet's code base that she used to build eurorack modules.  It's not quite HAL, and I guess not quite Bare Metal, but somewhere in between?

My repository is here.

https://github.com/eclewlow/eurorack/tree/master/waves2

I'm just porting over a little bit of code at a time.  One thing I ran into was virtual functions being called just causing the flow of execution to stop.  I don't think it's a hard fault, but the execution of the MCU definitely stops.

For example, in bootloader.cc

https://github.com/eclewlow/eurorack/blob/master/waves2/bootloader/bootloader.cc

void Init() {
  System sys;

  sys.Init(false);

  sys.StartTimers();

  GPIO_ResetBits(GPIOA, GPIO_Pin_5);

  BufferAllocator allocator(shared_buffer, 16384);

  childA.Paint();
  Engine* e = &childA;

  volatile size_t counter = 1000000;
  while (counter--);

  e->Paint(); // the execution reaches here and then stops, and the LED does not blink

  GPIO_SetBits(GPIOA, GPIO_Pin_5);

}

int main(void) {
  Init();

  // after Init calls, infinitely blink once per second
  // If I call the virtual function e->Paint() in Init(), then
  // this following code will never execute.
  while (1) {
    if((system_clock.milliseconds() / 1000) % 2 < 1) {
      GPIO_SetBits(GPIOA, GPIO_Pin_5);
    } else {
      GPIO_ResetBits(GPIOA, GPIO_Pin_5);
    }
  }
}

I'm a newb to compilers and linkers, so if there is an error there, I would have no idea.

I've been messing around with compiler and linker flags, and the linker script.

One thing I noticed was at first the vtable entries in the .map file were missing?  And it wasn't until I edited the linker script file did the vtables show up.  However, it didn't fix the issue.

https://github.com/eclewlow/stmlib/commit/c1e4fb1913e813cdc76abfb34ccc4ab5793ce8a3

https://github.com/eclewlow/stmlib/blob/master/linker_scripts/stm32f4xx_flash.ld

The .map file seems to show a vtable entry for each virtual function, and they are assigned to different spaces in memory.  Are the memory addresses somehow incorrect maybe?

*(.rodata)
 *(.rodata*)
 .rodata._ZTVN6waves26EngineE
                0x0000000008000600       0x10 build/waves2_bootloader/bootloader.o
                0x0000000008000600                vtable for waves2::Engine
 .rodata._ZTVN6waves26ChildAE
                0x0000000008000610       0x10 build/waves2_bootloader/child_a.o
                0x0000000008000610                vtable for waves2::ChildA
 .rodata._ZTVN6waves26ChildBE
                0x0000000008000620       0x10 build/waves2_bootloader/child_b.o
                0x0000000008000620                vtable for waves2::ChildB

I'm building the code on a MacOS Sonoma 14.5, with the arm-4.8.3 release, as recommended by Emilie.  Although, what's really recommended is building in a virtual machine, which I'm not doing.

2 REPLIES 2
TDK
Guru

When you debug the code and step through execution on that line, what happens?

If you feel a post has answered your question, please click "Accept as Solution".
ECLEW.1
Associate III

Thank you for your response.

So I don't know how to debug without CubeIDE, so I created a new CubeIDE project targeting my current Nucleo board.

There was no need to debug there.  The code runs fine.  The virtual function is called followed by blinking the LED.

I tried to dig around a little bit: checking out the makefile and linker scripts that are auto-generated by CubeIDE.  They are different than the build system I was using.

I'll just use CubeIDE.