5
votes

I am using Eclipse kepler for AVR development. The code that I have is C (Open Source), and I've gotten it adjusted so it runs perfectly. My target is an ATmega2560, in the form of an arduino mega2560. Using the arduino board is strictly for hardware convenience; we are developing the hardware to be a custom board with most of the core arduino mega2560 components.

I need to use several libraries with this project that are only available as arduino libraries, namely libraries for an e-paper screen (from seeedstudio) and Nordic's BLE nRF8001.

If I create a new arduino project using the plugin in eclipse, I can build and run the tests for the arduino libraries perfectly.

When I try to merge the 2 code bases together, I can't seem to call the functions in the added arduino libraries - if I call them the compiler throws a linking error.

Building target: Virgin2ManualArdInsert.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,Virgin2ManualArdInsert.map -mmcu=atmega2560 -o "Virgin2ManualArdInsert.elf"         ./avr/adc.o ./avr/eeprom.o ./avr/lcd_and_input.o ./avr/main.o ./avr/strings.o ./avr/unimplemented.o ./avr/usart.o  ./aes.o ./baseconv.o ./bignum256.o ./ecdsa.o ./endian.o ./fft.o ./fix16.o ./hash.o ./hmac_sha512.o ./messages.pb.o ./p2sh_addr_gen.o ./pb_decode.o ./pb_encode.o ./pbkdf2.o ./prandom.o ./ripemd160.o ./sha256.o ./statistics.o ./stream_comm.o ./test_helpers.o ./transaction.o ./wallet.o ./xex.o   
./avr/main.o: In function `main':
main.c:(.text.startup.main+0xc): undefined reference to `writeEink'
collect2: error: ld returned 1 exit status
makefile:53: recipe for target 'Virgin2ManualArdInsert.elf' failed
make: *** [Virgin2ManualArdInsert.elf] Error 1

As a test, I'm just trying to call a basic "write to display" call in eInk.cpp from main.c:

extern "C"{
void writeEink()
{

    EPAPER.begin(EPD_SIZE);                             // setup epaper, size
    EPAPER.setDirection(DIRNORMAL);                     // set display direction

    eSD.begin(EPD_SIZE);
    GT20L16.begin();

//    int timer1 = millis();
    EPAPER.drawString("testing", 10, 10);
    EPAPER.drawNumber(12345, 60, 40);
    EPAPER.drawFloat(-1.25, 2, 80, 65);
    EPAPER.display();                                   // use only once

}

Is a static library built from the arduino cores the way to go here? I've tried it (though it seems most of the procedures are outdated) and the libraries do not want to link/be called.

What is the correct procedure for including C++/Arduino calls in my C code? I've tried using extern "C" {function()}; in my .cpp files and .h files but to no use.

Thank you for any help or pointers to where I can figure it out for myself.

2
"the compiler throws a linking error" - what error would that be?Captain Obvlious
You can check for details on link errors by using gcc option -Wl,--verboseMansuro
Added code snippets for clarity.ThesQuid
Have you tried compiling with a C++ compiler? It should still compile your code and will natively support C++.Treesrule14

2 Answers

1
votes

You can try to compile your C code as C++ by simply renaming the files to *.CPP, but chances are that you have to modify your code to make it compile as C++ code. There are things that are allowed for C, but not for C++ (like calling functions that are not declared).

The other solution is to wirte wrappers around the C++ functions that you want to use from C. You have to consider two limitations of C against C++:

  1. C is not object oriented
  2. C does not support overloading of functions

This example for Serial.print() shows how you can handle this with a wrapper:

extern "C" void SerialPrintInteger( int value )
{
    Serial.print( value );
}

In this example you would write similar functions like SerialPrintFloat(), SerialPrintString() etc. The extern "C" prefix tells the compiler to create the function in a way that makes it callable from C.

0
votes

The error you received above isn't a compiler error, it's a linker error. I haven't used Eclipse for Arduino development, I just stick with the Arduino IDE, but the standard Arduino projects expect all of your code to be in a single source file, which it compiles and then links with the Arduino libraries. Arduino programs don't have a C/UNIX-style "main" function, the standard functions are "setup" and "loop."

I recommend going back to one of the Arduino example programs, blink for instance, and watching the console log as Eclipse compiles and links the program. What's happening here is:

  1. The C/C++ compiler compiles your source code, including setup(), loop(), and any other functions you have created, into an object file.
  2. The Linker links this single object file with the Arduino runtime, and any Arduino libraries you have specified. The output of this is an image of the program, in your example above it's trying to make 'Virgin2ManualArdInsert.elf'.
  3. The uploader (probably avrdude) loads this image into your Arduino and resets it.
  4. The Arduino comes out of reset and runs your new code.

If your program is reasonably small, say not more than a few hundred lines, just put all the functions in the one source file, then you won't have to learn how to drive the linker.

If you need, for some reason, to have the sources in a separate file (maybe they're shared with another program, or another platform), then you'll have to learn how to get Eclipse to link the object files from your multiple source files. This may just involve adding the sources into your Eclipse project properly, or you may have to write a Makefile or something similar.

As for C vs C++ source code, you can usually drop a C function into a C++ source file and compile it. There are a few differences, but this way you don't need to worry about "C" linkage or any of that silliness.