Arduino Due UART vtable undefined when tunrning off optimizations

Hi,

I got this error when compiling for the Arduino Due with -O0:

build-arduino_due_x/libcore.a(UARTClass.cpp.o): In function `HardwareSerial::HardwareSerial()':
/home/fjrg76/.arduino15/packages/arduino/hardware/sam/1.6.12/cores/arduino/HardwareSerial.h:26: undefined reference to `vtable for HardwareSerial'
collect2: error: ld returned 1 exit status
make: *** [/home/fjrg76/KleOS-1.0-Linux/arduino-1.8.13/arduino_mk/Arduino.mk:1694: build-arduino_due_x/Due.elf] Error 1

When I turn optimizations on (-Os) it compiles.

This is part of the Makefile:

C_OPTIMIZATION_LEVEL = -O0
CXX_OPTIMIZATION_LEVEL = -O0
WARNING_FLAGS = -Wall -Wextra
BUILD_EXTRA_FLAGS = -I. 
BUILD_EXTRA_FLAGS += -I$(FREERTOS_PORT_PATH)
BUILD_EXTRA_FLAGS += -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM

CXXFLAGS_STD = -c -g $(CXX_OPTIMIZATION_LEVEL) -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD
CXXFLAGS_STD += ${BUILD_EXTRA_FLAGS} ${WARNING_FLAGS}

CFLAGS_STD = -c -g $(C_OPTIMIZATION_LEVEL) -std=gnu11 -ffunction-sections -fdata-sections -MMD -fno-fat-lto-objects
CFLAGS_STD += ${BUILD_EXTRA_FLAGS} ${WARNING_FLAGS} 

I'm JTAG-debugging a code, so I need to turn off optimizations (code size is not a problem) to find out why SPI on Arduino Due isn't working (but that's another issue).

Any hint? Thank you!

Search for : hardwareserial vtable
Then you can find others with the same problem and maybe a solution: https://learn.adafruit.com/proper-step-debugging-atsamd21-arduino-zero-m0/paths-and-optimizations#fixing-some-core-files-2469468-17.

Let's talk about the real issue then :face_with_raised_eyebrow:
Do you have a Logic Analyzer ? A USB Logic Analyzer costs between 10 and 30 dollars.

The SPI bus is fast, and perhaps the problem only occurs when it is fast. I don't see how a debugger can do more than what you can do with debug messages to the Serial Monitor.
The SPI bus is not a standard, so it might be the wrong timing/clock/data for the device. Some devices have such a strange "SPI" interface that the Arduino can not use the SPI library for it.

I think you should start a new topic for the SPI problem (you may give a link there to this topic).

Seems promising. I'll take it a look closer. However, I dont't see why someone needs to modify an API whenever optimizations are on of off. That violates one or two programming principles.

I just mentioned the SPI thing because that brought me to the vtable problem. But I found a solution. A silly one, BTW. SPI pins on the Due are not the same that those on the UNO board! For long time I thought Arduino was a standard; however, it's not, at least on the Due boards. It may be because the Due board has a very different form factor than that on the UNO. I can't think of another valid reason (UNO shields that use SPI don't work on the Due).

In the Due board the SPI pines are located in a 6 pin group connector near the main chip. Now my system works as expected! (In regards of the SPI issue).

Thank you for the tip!

Well, you started this problem :rofl:

The Arduino 2.0 has debugging included. They are at version 2.0.0-rc3 now, but there are still problems with it.

Arduino has split the development into a few different building environments: ArduinoCore-avr, ArduinoCore-mbed, ArduinoCore-sam, and so on. I think the future is ArduinoCore-API.

I'm not sure, but I think that the Arduino Due is the only board in the ArduinoCore-sam.
The Arduino Due has not the priority of the Arduino team anymore. It has already problems with the I2C bus and there are known compatibility problems.

The 6 pins is called the ICSP header. The Arduino Uno has it as well.
Good shields are compatible with 5V boards and 3.3V boards and use that ICSP header for the SPI bus. For example the Ethernet shield uses it.

2 Likes

That is supposed to be the STANDARD location.

In the original Uno, that connector was for ISP programming of the ATmega chip, which happens to use SPI, so they were connected to the same pins as digital 11,12,13. That was all swell til the Arduino MEGA came along, and they wanted to put PWM on all of the original digital pins (0-13), and put SPI ... elsewhere (WAY elsewhere.) But since SPI was still used for chip programming, it was still on the 6pin connectors, and they said "just take SPI from there - it's the same across both boards!" So that's what you're supposed to do.

Unfortunately, that left many older shield designs trying to talk SPI on 11,12,13, and those shields don't work with Mega, or Due, or most of the other new boards :frowning:

1 Like

I wasn't aware of so many problems with the Due board. I chose it because it is 32 bits (as my beloved LPC microcontrollers from NXP) and it can be debugged with a bunch of debbugers (right now I'm using j-link from Segger and its beautiful tool called Ozone).

The Due board has two 6 pin group: one is ICSP for programming the auxiliar uC, and the other one is just SPI from the SAM chip. I learnt it the hard way =)

I'm used to use the gVim editor and makefiles on Linux. I tried the IDE 2.0 but it's as unusable as the previous one.

The problem debugging the ATMEGA328 under debugWire is that everytime I need to change the fuses. Even worst, it's almost impossible to debug on this chip when the real time operating system FreeRTOS is incorporated into the design, and I use it a lot! For an unknown reason the ATMEGA328 doesn't respond to GDB commands like step, step into and breakpoints (however, it works as a charm when running freely... most of the time).

Actually the project I'm working on is for the UNO board, but it got out of control and I need desesperately to debug the code. Once the program is complete, then I will go back to the UNO board. Naively I thought the pinout was the same for the Arduino's different boards.

If you want you can see my setup here on Ig.

EDIT: The SPI is for driving the display segments through the HC595 shift register chip.

So much trouble for just a 74HC595 ?

Debugging for the 74HC595 can even be done with Wokwi. Although I must say that I have not been able to use the debugger yet.
Working examples for the 74HC595 are here: https://docs.wokwi.com/parts/wokwi-74hc595.
If you install PulseView, then you can use the simulated Logic Analyzer: https://docs.wokwi.com/guides/logic-analyzer.

You should have asked us before going down this path. We would have told you:

  1. Don't buy the Due.
  2. Use the FreeRTOS on a ESP32 or Mbed-rtos on a Mbed/Arduino combination. The Raspberry Pi Pico can use the Arduino scheduler which uses the Mbed-rtos. You can test the ESP32 in Wokwi, and you can test the Mbed-rtos on the Raspberry Pi Pico in Wokwi.
  3. A good 32-bit board is with a SAMD21G processor, they are on the Arduino Zero and most MKR boards. The simple Arduino scheduler can be used with them and switches tasks during a delay. The ESP32 is also a good 32-bit board.
  4. Use Wokwi to test a 7-segment display: https://docs.wokwi.com/parts/wokwi-7segment
  5. Use MAX7219 modules if possible. Yes, Wokwi has them as well: https://docs.wokwi.com/parts/wokwi-max7219-matrix

You could start a new topic with the 74HC595 problem. Show the code and the hardware.

In case I forgot, there is a Arduino simulation called "Wokwi". It's great. Have a look at it:

1 Like

No, driving a 7 segments display through the HC595 was a little part of the job. I've done that for years for so many boards, and actually it was nicely working in a UNO board. And now it works as expected in my Due (I'll write an article on this regards ASAP).

This is my setup:

The problems began when I started coding the business logic of the application (hardware independent); everything went out of control, so I needed to debug that part of the code.

When I ported the application from the UNO to the Due board I naively thought it was 100% compatible, so I wired SPI signals to the Due's pins 13 and 11... and nothing happened. The oscillocope (I do also own a logic analizer, but for this matter the oscilloscope was enough) showed me nothing, and then I thought I was doing something wrong, until I reviewed the Due's pinout. I realized the SPI pins are in other place than that of the UNO's boards. Now the display and a keypad are working beautifully (the keypad accepts short, long, and repetitive presses; you can see an article of my own on this matter here).

In regards to FreeRTOS, I love it. I started coding this project using the awful Arduino's super-loop, but this doesn't scale very well, so I ported the app to FreeRTOS. When the applications is ready, I will ported to the UNO board back.

I also have experience with FreeRTOS and I got some hardware debuggers, and the Due board works as a charm with the Segger j-link probe (and its Ozone debugger companion program) as you've seen in the above image.

Actually I wrote an introductory FreeRTOS course (in spanish) for the Arduino UNO boards (here), and I've integrated the UNO and Due APIs to such operating system in an ongoing project I called KleOS. (Both uses their main ticks as FreeRTOS' system tick, and programs can be written either in sketches or in the command line.)

The wokwi simulator sounds promising! I'll take it a look ASAP, thank you for the TIP.

Asking a good question on this forum can be harder than answering a question :woozy_face:
For the next time, ask about the actual problem and show the sketch and tell how it is connected.
We know that the SPI bus is on other pins, and you should have showed the sketch that caused the problem and tell what happens and what you expect that it should do. Some of us can spot a problem in thousands lines of code.

Do you know the XY-problem ? https://xyproblem.info/

You may like this funny little project (Arduino + Schedular + Mbed + rtos + Wokwi + Raspberry Pi Pico): https://wokwi.com/arduino/projects/319520489491923538

Hi,

The question was crystal clear:

"Arduino Due UART vtable undefined when tunrning off optimizations."

And someone has already answered it, but I haven't had time to explore it. I mentioned the SPI thing just for context.

Usually I try to explore the Internet looking for answers before I post my question in a forum when I can't get my own. Say they are the last resource.

But for the vtable problem I didn't find anything, or I didn't make the right question, I agree with you in that matter.

While waiting for any answer for the vtable problem (actually that wasn't critical) I started looking for the SPI thing, and as I've already download a nice pinout diagram (here) I realized the Due's SPI pins are not in the same place as that of the UNO boards. And then I found that I need to get them from the 6 pin group. This was a critical problem because without the display I have nothing.

Happily now things are moving forward smoothly and I appreciate the help of all of you that took the time to support me. Thank you, sincerely!

Ok. The "crystal clear answer" is that you shouldn't "turn off optimizations" when using gcc.

With some compilers, "no optimization" means "not much optimization", and it's sort-of OK. With gcc, -O0 means "output really obvious and awful code that might be useful for figuring out what the compiler was thinking when debugging compiler bugs."

You should always used at least -O1
For the best debugging experience, use -Og
(better yet, learn to debug with the "production" optimization settings, even when it's unpleasant.)

No. I must be able to turn optimizations on or off whenever it's needed, and the compiler must compile the program in either situation. It's not ok that an API relies on optimization flags.

I SHOULD NOT tweak a third party code so that it compiles whenever optimization flags changes. As I said, that brokes one or two SOLID principles.

Most of us use the GCC compiler for Arduino, so that the concept of "some compilers" doesn't apply in this situation. Do you use another compiler for your Arduino programs?

I've tried it, but didn't work. The assembler output is the same as -Os.

It's not about pleasure; it's about to get the job done.

And as I said before, now the display and buttons are working as expected. Now I need some time to try the advice that was given to me before.

Happy coding!

I am curious: is there an explanation for the cause of this bug? (the site with the "fix" just had replacement code.)

I suspect that this is related to HardwareSerial not being the "bottom level" class on Due (Could be a UART, could be a USART...)

1 Like

Why not? You've clearly "tweaked" the "core" SW (adding FreeRTOS) and build environment far past the "vendor supported configuration"... While I guess I agree that this is a bug (somewhere - hoping for an explanation of exactly where), my experience says that it's unusual to be able to change that much and not run into SOME problems.

My own experience in this area is that some libraries will try to pass around pointers to HardwareSerial objects when they probably should be passing around pointers to Stream (otherwise Serial-like behavior won't work on native USB, for example.)

FWIW, if I switch the Arduino platform.txt so that builds are with -O0, I get the same incorrect behavior even on a plain AsciiTable example. But it does work with -O1, and I get dramatically different .o files (setup() is 2a bytes with O0 and only 16 with 01, for example.) (Are you sure you re-compiled after changing the Makefile? The Makefile itself is rarely included in target dependencies, so you could have re-linked stale O0 object files...)

1 Like

Hi West!

I love to hack code (and I guess must of us do), but that doesn't mean that it's ok when an API used by thousands of enthusiasts needs to be modifed so it compiles whenever an optimization flag changes. That's not ok.

The changes I've done to the Arduino's core are minimal (but not easy at all!), but from the begining of the project I wanted to avoid to say to the KleOS users: "Find and open these files and then paste this and that code here and there". Instead I've packed the full solution into a single download that doesn't need to be installed and it can work along with an already Arduino "normal" installation.

Maybe with more time one needs to go down very deep into the source of this bug.

Have a nice coding!