Weird behavior of function pointers on ATmega328p

I have got some rather weird behavior with a static array of function pointers on the ATmega328p. when I call the pointed to function, the normal behavior is expected to be that an LED blinks once. some of those functions have the behavior of being called an infinite amount of times. The exact positions of those incorrectly behaving functions in the array are:
Index 1 5 18 21 24

This is the particular code that calls the pointed to functions: lpc1768_blinky_example/InterruptVectorTable.cpp at a07bc577c1c6049e9821a541c3074348974b820e · jxsl13/lpc1768_blinky_example · GitHub. it is being called form the src/main.cpp

You should print all function pointer values before calling into them, to see whether you’re not calling into 0x0000 (reset vector) or the function itself.

Also it could be that the processor automatically calls the ISR again after an ISR handler does not clear the interrupt pending bit for the interrupt? That’s how it works in many processors.

  • the class InterruptVectorTable initializes the array properly with empty functions(constructor defines an empty lambda function).
  • one of the functions in that array is set to a new lambda function that blinks an LED (InterruptVectorTable::setISR(index, function))
  • after that the method triggerISR(index) just simulates an interrupt, no interrupt is actually really triggered. it simply tries to call the function pointer in that static array.

There is no actual ISR behavior there other than ISRs also calling individual functions from that array. But my test aims currently at the method called triggerISR, which simply tries to call the functions directly.

Cannot really print anything, as bare metal and until now(?) there is no debugger for the atmega328p :confused: in PIO.

After some LED testing I can say that the controller is not being reset, otherwise it would initially blink fast and then once slowly. Afterwards these both patterns should repeat, what they do not do.
It simply continues to blink slowly (behavior of the function that’s being passed to the function pointer array).

Edit:
Some previous attempts that did not work were:

  • alignas(sizeof(void*)*[16,32,64,256]) static FpArray
  • making the array volatile (tried all possible positions of that keyword)
  • dereferencing the function pointer before calling the function.

Here is a binary if it helps: http://www.mediafire.com/file/rin7i3gbnmjvbgy/atmega328p.zip/file

hm, slowly approaching goal, but I do not understand, why this helps.

I now have kind of two static arrays, one with uint16_t and another with the old function pointers.
the infinite loop of blinking stopped, but I seem not to be able to reproduce this state without getting the repeated behavior of the function pointer array.
I am guessing that the parallel existence of those two arrays seems to push the second array into some correct ram region, but not sure.

Another problem stays, I cannot execute multiple function calls after each other from that array.
I am not sure what happens.
Is there some IDE for this Microcontroller that I could use to debug the binary somehow?

Location:
src/controllers/atmega328p/InterruptVectorTable.cpp

PIO can apparently be integrated with dwire-debug, as seen in VSCode PIO debugger for AVR, but I haven’t tried that myself.

I don’t have that adapter. Somehow gotta get this to work :frowning:

This is al I have, but I kind of doubt this is the same adapter.

I think it just needs any USB-Serial adapter and a Diode (to properly isolate the bi-directional line). As I said I’m trying to get that to work myself soon. But even with debug printf style debugging some important things should be found out, like function pointer target addresses.

So what does the output say, does adding print statements make it clearer?

You might try to reproduce the project in Atmel Studio, but i’m not sure whether the USB-ASP probe is debug-wire debugging capable.

I also thought about using stuff like SiSy AVR and Atmel Studio. Ended up with atmel studio and some weird linker error.

Seems like its missing some C++ mutex stuf and it also doesn’t like your modern C++ stuff with auto [...] -> void lambda stuff there. Maybe it uses an older compiler version or a lower C++ standard number? Not sure how easy the compiler toolchain can be reconfigured in Atmel Studio to e.g. use the, for this project, working PlatformIO provided toolchain.

Visual Studio does not like the syntax, but seems not to care.
Same result with and without that syntax.

I found a solution for that problem.


Compiler flag:

-fno-threadsafe-statics

(source: Undefined reference to __cxa_guard_acquire and __cxa_guard_release · Issue #356 · bblanchon/ArduinoJson · GitHub)

hm, I could not get the debugging to work, but Atmel Studio allows to simulate the microcontroller.
I was able to reproduce my weird blinking behavior.

Don’t understand, why this happens, hopefully correctly interpreted.

removing the function pointer call from the ISR (index 5) creates proper behavior.
what is going on :smiley:

This is where the fucntion is called:

The called function does not return after this call, but after the call in the ISR, which is weird…(visible in the previous post)

Edit: Using the GNU Compiler Collection (GCC): AVR Options
Kind of found some reference, but don’t quite understand that, yet.

Edit 2:
https://www.avrfreaks.net/comment/1067526#comment-1067526

As for why function pointers are undesirable, note that they must be loaded into the EIND+Z registers to work.

https://www.avrfreaks.net/forum/array-function-pointers-flash

references for myself:

EICALL
EIJMP

ATmega328p has no EIND register.

hm, dunno, the compiler seems to be doing some weird stuff that I cannot comprehend.

switch-case did not work either in order to have a static value accessing the array instead of having a function pointer called by a “variable” value.

This is the example project, maybe someone knows why gcc behaves like that.

Super minimal example: http://www.mediafire.com/file/0udcgzd42l6y03d/ATmega328p_Minimal_Example.zip/file

hm, enabling individual interrupts on the ATmega328p seems to partially already trigger interrupts without them being configured.
(watchdog times etc.)
the arm cortex-m processors seem to behave differently when enabling individual interrupts without having configured them.

Can someone confirm this?