Go Down

Topic: Arduino+Eclipse tutorial, from start to finish (Read 19330 times) previous topic - next topic

eclipser

May 24, 2011, 08:22 pm Last Edit: May 24, 2011, 08:44 pm by eclipser Reason: 1
Hello all, because the "official" Eclipse tutorial has some holes, and is missing some directories and flags, here's my tutorial (based on that one) of how you replicate all the functions of the Arduino IDE in Eclipse. The forum kind of mangles the formatting because I'm too lazy to put in all the markup, but you get the idea. There are some more aggressive compiler and linker flags that you can use, but I tried to closely replicate the flags the Arduino IDE uses here.

This guide is aimed at people who have used Eclipse before and know at least a tiny bit about how a C/C++ program is compiled.

My system is a Debian Linux system, with Eclipse (Helios/3.6) and an Arduino Uno. Most instructions will be the same, but your paths may vary... You need the CDT plugin for Eclipse, you can download the prepackaged version or you can add the CDT to your current install through Eclipse's update manager.

1. Install System Prerequisites
Get the AVR programmer and toolchain for cross-compilation and debugging. You probably already have some of this from the Arduino IDE prerequisites:
apt-get install avrdude binutils-avr gcc-avr avr-libc gdb-avr

2. Install Eclipse Plugins
AVR tools for programming, compiling, etc:
http://avr-eclipse.sourceforge.net/updatesite/
Get the plugin: CDT Optional Features->AVR Eclipse Plugin and install it and any dependencies.

RXTX library for the serial monitor:
http://rxtx.qbang.org/eclipse/
Get the latest runtime (currently RXTX 2.1-7r4->RXTX End-User Runtime) and install it and any dependencies.

GUI for the serial monitor:
It's in the default Helios update site.
Get Mobile and Device Development->Target Management Terminal and install it and any dependencies.

3. Creating a Template Project
In almost all embedded development, especially on constricted architectures like AVR, you will find yourself knee-deep in cryptic compiler flags. The Arduino IDE is very good at doing this in the background, but you can see what's going on if you get the sources. So we'll set this up once and just copy a "base" project for all new projects.

First of all, create a new workspace just for your Arduino development so you can set workspace global defaults.

Create a new C/C++ project. Let's call it "Template". The project type should be AVR Cross Target Application->Empty Project, and the toolchain should be AVR-GCC Toolchain. Hit Next twice.

For the Uno the MCU type is ATMega328p, the MCU frequency is 16000000. Your hardware may vary. Hit Finish to create the project.

4. Importing the Core Arduino Library
All projects using the Arduino environment need the precompiled Arduino library, if you aren't compiling together with your own custom core. Open an example project in the Arduino IDE and "verify" it. Now in your Eclipse project, import the library from the filesystem, which is probably in /tmp/buildXXXXXXXXXXXXXXXXXXXXX.tmp/core.a. Put it in a new subfolder "arduino" within the project, and rename it libcore.a.

5. Compiler Settings
Open your project properties, edit from the defaults and remember to Apply at the end:
Under C/C++ Build->Settings:
Additional Tools in Toolchain
Check Generate HEX file for FLASH memory
Check Print Size
Check AVRDude if you want to flash automatically every time you build
AVR Compiler
Directories
Add the directory of the Arduino header files, located in the Arduino IDE directory <location of IDE>/hardware/arduino/cores/arduino . Alternately, you can copy all these files into your template project, perhaps in the /arduino where the core library is, and point to that location in the Workspace instead.
Add the directory of the Arduino libraries, located in the Arduino IDE directory <location of IDE>/libraries . Again, you can copy these directly into your project if desired.
Symbols
Unnecessary, but you can add a define of ARDUINO=22 (or whatever your version is)
Optimization
Set Optimization Level to Size Optimizations (-Os) . This tells the compiler to turn on optimizations that generate smaller code sizes.
Uncheck Pack Structs, this aligns structs in the binary in a way that may be longer and the core is not compiled with it on.
Uncheck Short Enums, this allocates enums only enough space to cover the possible range, but since this is not how the rest of the Arduino core is compiled you should turn it off.
Other Optimization Flags: -ffunction-sections -fdata-sections
These flags separate functions and data into their own sections, which allows the linker to do certain optimizations.
Miscellaneous
Other flags: --pedantic -c
The -c flag tells it to just compile, not link yet. The –pedantic causes even the most inane thing to generate a warning, it can be very helpful if you are tracing an obscure issue but can generally be ignored.
AVR C++ Compiler
Make exactly the same changes as the previous section.
AVR C++ Linker
Command: avr-gcc
General
Other Arguments: -Wl,--gc-sections
This flag allows linker optimization using the results of -ffunction-sections and -fdata-sections from compilation.
Libraries
Libraries: add c, m, printf_flt, scanf_flt, and core.
These are the C core library, the math library, printf and scanf libraries with float support (the default versions don't have it), and the Arduino core library. Not all are necessary for all projects, but they are frequently needed and it's easy to add or remove them if you want.
Libraries Path: click add, select Workspace... and select the folder where you saved the libcore.a. It will end up like "${workspace_loc:/${ProjName}/arduino}".

6. Template Code Setup
The Arduino IDE does a little bit of source mangling before compilation which we need to replicate. Add this code to a header file like cppsupport.h and #include it in your main.cpp source file, or have it inline. It provides some C++ style wrappers for malloc and the guards protect against accessing invalid memory locations. There is also a handler to catch calls to purely virtual functions.

#include <stdlib.h>

extern "C" void __cxa_pure_virtual()
{
  cli();
  for (;;);
}

__extension__ typedef int __guard __attribute__((mode (__DI__)));

void * operator new(size_t size)
{
  return malloc(size);
}

void operator delete(void * ptr)
{
  free(ptr);
}

void * operator new[](size_t size)
{
    return malloc(size);
}

void operator delete[](void * ptr)
{
   if (ptr)
      free(ptr);
}

int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}
void __cxa_guard_release (__guard *g) {*(char *)g = 1;}
void __cxa_guard_abort (__guard *) {}

Now create or edit main.cpp and paste the following skeleton code - you don't see it, but the IDE rearranges your sketch to look like this before compilation:

// The Arduino core
#include <Wprogram.h>
// Uncomment if you need it for C++ style new/delete and pointer protection
//#include "cppsupport.h"

void setup()
{
}

void loop()
{
}

int main(void)
{
   init();

   setup();

   for (;;)
      loop();

   return 0;
}

Technically you don't need to use setup and loop anymore... Ok, now put in some simple blink code or something into setup() and loop(), and build it. In the build console you'll see all the steps and eventually a printout of the code size. For the Blink example program, you should come in just under 1000 bytes. If you are significantly higher, you probably missed a flag in the settings.

7. Flashing to Arduino
Hook up your Arduino to your computer and figure out the address of the serial port. For the Uno, it's always /dev/ttyACM0, or 1,2,3... if you have multiple devices or unplug and plug it in again quickly. Go into Window->Preferences->AVR->AVRDude and Add... a programmer configuration. Name it Arduino, select Arduino in the Programmer Hardware (-c) list, and set Override default port (-P) to your serial port. Hit OK and Apply.

Back in Project->Properties->AVR->AVRDude, select the Programmer Configuration you just created and Apply.

Now build the blink template project, and AVR->Upload Project to Target Device. Make sure nothing else is using that port, like the Arduino IDE serial monitor. Hooray, you have just flashed your Arduino from Eclipse.

8. Serial Monitor
The last piece is a serial monitor inside Eclipse. To access it, open Window->Show view...->Other and select Terminal->Terminal, it will probably open where your compiler console is. Click the Settings icon; set Connection Type to Serial and supply the appropriate Port and Baud Rate, the rest should be fine. Click OK and hopefully the terminal should connect, try some test code with Serial.print. Be sure to disconnect before flashing because it will interfere.

9. Cleanup
Set your main.cpp back to the skeleton, run a clean (but not a build) in your Template project to flush out the binaries, and save it. Now whenever you need a new Arduino project, just copy the Template project so you don't have to change all the settings. Enjoy!

Prawnhead

Arduino+Eclipse+Linux tutorial, that is. Got any tips for Windows?
There are 3 kinds of people in the world. Those who are good at maths, and those who aren't.

PaulS

What does this code do:
   for (;;)
      loop();
I don't have the smiley face on my keyboard. Be a good idea to learn how to post code properly.

mmcp42


What does this code do:
   for (;;)
      loop();
I don't have the smiley face on my keyboard. Be a good idea to learn how to post code properly.


Code: [Select]
   for (;;)
      loop();


put it inside {code} {/code} (only use square brackets instead of braces!

oh and it will loop for quite a while!
(eek I think)
there are only 10 types of people
them that understands binary
and them that doesn't

FalconFour

#4
Jun 08, 2011, 11:45 am Last Edit: Jun 08, 2011, 02:36 pm by FalconFour Reason: 1
Many thanks for clarifying this stuff. According to the clock, I've spent about 3 hours now trying to make Eclipse compile this:

void setup() {
   pinMode(13,OUTPUT);
}
void loop() {
   digitalWrite(13,~digitalRead(13));
   delay(500);
}
And the resulting vomit:
Code: [Select]
**** Build of configuration Release for project Template ****

make all
Building file: ../blink.c
Invoking: AVR Compiler
avr-gcc -I"C:\Users\Falcon\Desktop\Software\arduino-0022\hardware\arduino\cores\arduino" -I"C:\Users\Falcon\Desktop\Software\arduino-0022\libraries" -Wall -Os -ffunction-sections -fdata-sections -std=gnu99 -funsigned-char -funsigned-bitfields --pedantic -c -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"blink.d" -MT"blink.d" -c -o"blink.o" "../blink.c"
../blink.c: In function 'setup':
../blink.c:2: warning: implicit declaration of function 'pinMode'
../blink.c:2: error: 'OUTPUT' undeclared (first use in this function)
../blink.c:2: error: (Each undeclared identifier is reported only once
../blink.c:2: error: for each function it appears in.)
../blink.c: In function 'loop':
../blink.c:5: warning: implicit declaration of function 'digitalWrite'
../blink.c:5: warning: implicit declaration of function 'digitalRead'
../blink.c:6: warning: implicit declaration of function 'delay'
make: *** [blink.o] Error 1


Simple, right? That's what I jot into Arduino IDE. That's what I want to jot into Eclipse. It's just that Eclipse has a nicer browser, syntax completion, all sorts of fancy stuff that would be AWESOME to use with Arduino. With Arduino. I'm not a C programmer, I don't write desktop programs. But I make some *seriously* complex and (when I put my mind to it) streamlined code that does some really cool stuff with Arduino. Some of it is 20+ pages long, compiling to 25+ KB on the chip. I'd LOVE to be able to link various files together to make the program easier to read.

But Eclipse just isn't cutting it, because it refuses to behave like Arduino. As soon as I strip out the setup() and loop() functions, the compiler explodes. Why?! I can't understand it! It's supposed to chain together all the files that are in the project, right? And reference one another? I don't even know how to include another segment file of the same project. I assume main.c is the primary file in the project, and all others are referenced to find what main.c is referring to (like setup() and loop()). Nope! It tries compiling blink.c first, which results - obviously - in catastrophe.

I've Googled constantly thoughout these past 3 hours and have come up blank. This is the closest guide I've found so far, but still doesn't cut it (oh god, oh god please, I do NOT want to involve C++ in my already-well-founded C knowledge, it's just too much for one month). I just want it to work like Arduino. EXACTLY like Arduino, in its code behavior at least.

Why is that so important to me? Because I want to share my code with the community without sounding like a pompous, elitist jerk saying "oh, this won't compile in the Arduino IDE, you have to use Eclipse". D-Baggery at its finest, and I've seen a few examples. I want to produce code with Eclipse that I can actually post for Arduino users to use in the Arduino IDE. Eclipse just makes it easier to see, debug, and visualize the program flow. An editing tool. I don't need all this C-syntax headache... :/

So with the intent of mirroring Arduino's compile abilities pretty well explained, is this possible? Maybe you could be the first person to write a complete guide to mirroring this kind of behavior in Eclipse? :D

edit: Good god. 2 more hours later, now. I got the code to compile by erasing main.c and adding "#include <main.cpp>" in my program - that's all. OK, it compiles. Does it upload? Hell no. The version of avrdude bundled with the "stable" version of WinAVR is worthless... buggy "Arduino" implementation (since they made the stellar decision to stop pulsing DTR in the newer versions), and guess what? Nope, the damn thing doesn't upload. It uploads and verifies the Flash, but it craps on the low fuses. WTH. So now I download the SVN repo for avrdude and compile it. But to do that I need to somehow add Subversion (they couldn't call it "svn", huh, like everything else in Linux, called by its command name? oh NOooo, that'd be too easy to find - spent another 10 minutes trying to find that), then download the code, hope I have a sane build environment (probably not), and... SERIOUSLY? How is this making it easier for me as a developer? >.<

edit: /rage_delete again here... third time rewriting this. 6 hours of frustration and Googling (making the problem worse since Google returns COMPLETELY irrelevant results for most specific things and quotes I search for), and all I get is a pile of "undefined reference to" errors, even after all my work to resolve every error it's whined about. You simply can't compile Arduino-compatible sketches in this thing. Does not work. Shiny interface, yes, I'd love to use it. Can we? No. We're stuck with Arduino for now... :(

tastewar

Quote
How is this making it easier for me as a developer? >.<
:smiley-eek:
I can't help you, though I applaud your efforts. I'd like a more "professional" tool at times, too, but I'm not as ambitious about it as you. I would only suggest that, while I understand your frustration (been there...), start by admitting to yourself that you've intentionally avoided the easy path. It's OK to vent, though. Deep breath...  :)

Good luck! I think if you get to the point you want to, a lot of people will appreciate it!

FalconFour


Quote
How is this making it easier for me as a developer? >.<
:smiley-eek:
I can't help you, though I applaud your efforts. I'd like a more "professional" tool at times, too, but I'm not as ambitious about it as you. I would only suggest that, while I understand your frustration (been there...), start by admitting to yourself that you've intentionally avoided the easy path. It's OK to vent, though. Deep breath...  :)

Good luck! I think if you get to the point you want to, a lot of people will appreciate it!

Yeah, I think I've given up on this. At least for now. Frankly, the GNU/Linux (as a "slash" that is) community really ticks me off with the whole holier-than-Windows attitude, the shambled and disorganized way things are managed, the complete lack of UI design skills in almost every aspect of the system ("unknown parameter -?", being my most hated one)... just... ugh. I'm too tired for this crap.

I'll leave you with this log clip to mull over:
Code: [Select]
Falcon@Viper ~/avrdude
$ make
make  all-recursive
make[1]: Entering directory `/home/Falcon/avrdude'
Making all in windows
make[2]: Entering directory `/home/Falcon/avrdude/windows'
gcc -DHAVE_CONFIG_H -I. -I..     -g -O2 -mno-cygwin -DWIN32NATIVE -MT loaddrv.o
-MD -MP -MF .deps/loaddrv.Tpo -c -o loaddrv.o loaddrv.c
mv -f .deps/loaddrv.Tpo .deps/loaddrv.Po
gcc  -g -O2 -mno-cygwin -DWIN32NATIVE  -static -o loaddrv.exe loaddrv.o
make[2]: Leaving directory `/home/Falcon/avrdude/windows'
make[2]: Entering directory `/home/Falcon/avrdude'
/bin/sh ./ylwrap config_gram.y y.tab.c config_gram.c y.tab.h config_gram.h y.out
put config_gram.output -- bison -y  -d
C:\WinAVR-20100110\utils\bin\bison.exe: /home/falcon/avrdude/config_gram.y: No s
uch file or directory
make[2]: *** [config_gram.c] Error 1
make[2]: Leaving directory `/home/Falcon/avrdude'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/Falcon/avrdude'
make: *** [all] Error 2

Falcon@Viper ~/avrdude
$

"C:\WinAVR-20100110\utils\bin\bison.exe: /home/falcon/avrdude/config_gram.y: No s
uch file or directory"
" /home/falcon/ "
>> "make[2]: Entering directory `/home/Falcon/avrdude'"

... even their own programs can't get case-sensitivity straight.

tastewar


... even their own programs can't get case-sensitivity straight.


Ouch. :-(

Aeturnalus

Code: [Select]

C:\WinAVR-20100110\utils\bin\bison.exe: /home/falcon/avrdude/config_gram.y: No s
uch file or directory


This doesn't quite look like Linux... xD.  The backslashes and the C: in front kind of make me wonder how you have thing set up.

Also, have you tried
Code: [Select]

#include "WProgram.h"

anywhere?  Not including the Arduino libraries would be a good way to generate lots of fun errors...

FalconFour


Code: [Select]

C:\WinAVR-20100110\utils\bin\bison.exe: /home/falcon/avrdude/config_gram.y: No s
uch file or directory


This doesn't quite look like Linux... xD.  The backslashes and the C: in front kind of make me wonder how you have thing set up.

Also, have you tried
Code: [Select]

#include "WProgram.h"

anywhere?  Not including the Arduino libraries would be a good way to generate lots of fun errors...

It's cygwin; ports of Linux apps. The problem above is that the file exists, but cygwin's case-sensitivity combined with the program (I found it was "bison.exe"'s fault, part of the WinAVR toolkit) that was changing the case of the filename, resulted in the program not being able to find any file that exists under a capitalized path (e.g. "Falcon").

And yes, main.cpp includes WProgram.h, which chains together the Arduino library set. The only thing that accomplishes is it gives me access to the Arduino (Wiring) functions like digitalWrite() and pinMode() - that is, allowing us to run the "blink" program. All Arduino libraries are incompatible with eclipse's compiler options, as they're broken up into subdirectories in a common folder (which makes sense, from a development point of view!). I would have to redundantly specify "#include <LiquidCrystal/LiquidCrystal.h>" in all my programs - and not only that, but dependent libraries (like phi_prompt which relies on LiquidCrystal and phi_buttons) have to be modified with that path syntax as well. Finally, when I modified my libraries to make the C++ compiler happy, it barfed on a bunch of "unknown reference" errors in the linker, without any cause or resolve.

The problem is a combination of factors: the Arduino IDE does some code pre-processing and a good handful (arguably a totally redundant amount) of pre-compiling of libraries and re-arranging of definitions of functions, whenever you compile a program. You could theoretically emulate that program flow with another IDE, but that's not the worst of it. The avr-gcc (I'm guessing is its title?) toolchain has changed pretty dramatically from the ~'2007 version used in Arduino, resulting in a number of compiler warnings and outright errors that Arduino didn't have to deal with in the older toolchain. For example, the "stk500v1" programmer profile in Arduino's old avrdude actually pulses the DTR line to send the chip reset before programming (maybe that's an Arduino modified version?), and the new avrdude does not; it has its own "arduino" programmer definition that takes care of that. However, the current version doesn't write the chip fuses properly, it mis-reads (or mis-writes) the fuse values and craps out on the fuses phase. To get avrdude to work, you have to give up fuse capability. No biggie for most uses, of course, but it's just another one on the list of things it can't do right.

For me it's a combination of pebkac as well as program error, as I've never worked in a full and proper IDE before - I write all my scripts, websites, and other code in simple Notepad++. But the signs I've seen along the way point to bigger problems with the toolkit than just a simple missed include or compiler option... I'd actually love - genuinely would like - to see someone that develops Arduino-compatible code in Eclipse, with Arduino libraries and all. I'd love to know how it's set up, because I'd really like to be able to use it! It just kept me up for about 6 hours last night trying to grind through its deficiencies, and it just left me with a *really* bad first impression. :/

Aeturnalus

I actually use Eclipse for 99.5% of my Arduino development, which is why I've been following this thread. 

However, I actually run linux as a primary OS, which is probably why I haven't encountered, for example, your case sensitivity issues - it runs without any such errors in my case.

As for includes, the path specification in the linker settings (project properties -> C/C++ build -> linker) allows you to set default paths to look in for library header files, which should resolve the inclusion problems you're having.

One notable difference, I think, is that I've imported the Arduino core as a separate project in Eclipse, and I can thus recompile the code for whatever processor and clock speed I might be using.

In regards to the toolchain:

avr-gcc is the compiler and linker, and it hasn't changed in any significant way for a number of years.
avrdude is the firmware flasher, which interfaces with a hardware programmer of some sort - this, admittedly, has made some pretty big shifts (arguably for the better).

The Arduino system has most compiler warnings and errors disabled, which is why you usually don't encounter them - it's not a compatibility issue so much as just hiding the output.

As for fuses in Eclipse: Eclipse's fuse editor is very well designed, BUT the Arduino bootloader doesn't support writing fuses (I believe it returns 0x00 for everything).  Go to the avrdude settings and disable fuse burning, and the errors should disappear.  The fuses in the Arduino IDE's boards.conf are used when burning the bootloader, which requires a full hardware programmer of some sort (be it the AVR-ISP sketch or an avrispv2). 

FalconFour

Interesting! Good to know about the fuses thing. Funny that avrdude using its "arduino" configuration still tries to write fuses, then. It's admirable that avrdude includes an "arduino" config to begin with, of course! I think the fuses thing may be due to the fact that it imports the stk500v1 (oh yes, I did a LOT of work on this stuff last night) loading procedure after doing some custom setup for Arduino (reset with DTR, etc).

Maybe the avr-gcc system hasn't changed much, but something about the way it compiles... I directly slapped the avr-gcc binaries from WinAVR into my Arduino software in their respective folders, and it nearly ate itself... the best I got to was some error about "cc1.exe" unable to load some file (and cc1.exe wasn't in the referenced folder to begin with). Nothing I could do would make it work right, so I just gave up and reverted to the backup files from Arduino. It seems like every aspect of compilation -> linking -> assembly -> upload is custom in some way to Arduino...

I'm curious about how you managed to get it to compile included Arduino libraries, though. What's your library folder structure look like, are the libraries in individual folders like Arduino? Do you use different #include statements or anything? I'd really like to use Eclipse, as it builds and uploads really quick (although I sorely dislike that the default button is "build all" - I only ever want to build the current project, and it insists on building them all!), and has some really amazing structure management that'd help move development along on some of my bigger projects... I'm not writing it off entirely, but I mean, it REALLY took a toll on me, mentally and physically, last night trying to get it working right :(

Aeturnalus

I always got the impression that the 'arduino' config was left in for compatibility purposes - using a bootloader, in general, precludes fuse changes.

My folder structure is as such:

Code: [Select]

Arduino-328P (this is a static library)
  |Debug (compiled binaries)
  |various files from the source folder on Arduino.cc
Blinkenlights (example blink program)
  |Debug (compiled binaries)
  | main.cc
  | pins.h


In the build settings, all paths are set to include "${workspace_loc:/Arduino-328P/Debug}" and "${workspace_loc:/Arduino-328P}", with debugging info disabled (Arduino bootloader doesn't support JTAG, and it saves compiled code size)

I have attached an Eclipse export of my configuration for you (I honestly don't remember all the things I changed), so hopefully that will help you out.  I reiterate, though, that I'm running the whole thing on a full install of Linux, and thus have avoided at least a few of your problems.

sixeyes

I have Eclipse working on Windows XP. It took ages to get working. I think I had three attempts and for some reason on the third attempt it just worked.

I had the Arduino library compiled as a separate project. I've also got GLCD as a separate library. I think I had to set up the include paths in a particular way to get it to compile, but I've not worked with it for over six months so I can't remember what I did.

Re: Build all, if you don't build all, eclipse doesn't detect dependencies correctly. There's a bug logged about it but it hadn't been fixed in the Helios build I installed last year. The down side with this is if you're working with libraries (I was) your changes don't get compiled into the image :-(

So I ended up having to build all every time. At least it doesn't compile every file like the Arduino IDE, it only checks for out of date files.

Iain

oscarcar

BTW, I've had lots of problems with cygwin and changing the "/" and "\" and such.

And it runs differently when running in a windows command shell compared to running in a cygwin shell.

I would go with a virtual machine or a dual-boot of linux, or a separate pc that you remote into.

Go Up