Arduino Forum

Development => Suggestions for the Arduino Project => Topic started by: madworm on Oct 10, 2011, 12:25 pm

Title: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 10, 2011, 12:25 pm
Code: [Select]
#define ARDUINO_MAIN // [required]
#include <Arduino.h> // [required] - make sure everything that is required by the core libraries is known to the compiler

int main(void) // [required]
{
        init(); // [required] - make sure everything that is required by the core libraries to work is set up correctly

        setup(); // run user-defined initialization code - see below
   
        for (;;) { // [required] - never exit from main()
                loop(); // run user-defined code - repeated forever - see below
        }

        return 0;
}

void setup(void)
{
  // user-defined initialization code goes here
}

void loop(void)
{
// user-defined program code goes here
}


Function prototypes could still be automatic.

Why am I asking for this? The newly added SerialEvent stuff takes more than 200 bytes away and essentially is just a function call added in main() after loop(). I hate that, as I will never use it.

The structure of main() is not difficult to understand at all... add enough comments and even my mother could use it.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: robtillaart on Oct 10, 2011, 10:06 pm
50% workaround :)
Code: [Select]

void setup()
{
  mymain();
}
void loop(){}

mymain()
{
  // enter your code here ....
}
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 10, 2011, 10:12 pm
OK, that probably works too.

All I'm saying is that with the above shown 'template' ("bare minimum"), every user will sooner or later find out what goes where. There's really no need to hide that. Or add code that usually doesn't do anything and steals 200 bytes of flash.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: bubulindo on Oct 11, 2011, 01:51 am
Why not stop using the IDE?
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 11, 2011, 08:19 am
You can do that now.

Old way:

Code: [Select]
void setup ()
{
  Serial.begin (115200);
  Serial.println ("hello, world");
}

void loop () {}


Compiles as:

Code: [Select]
Binary sketch size: 1970 bytes (of a 32256 byte maximum)

Let's just use main:

Code: [Select]
int main ()
{
  Serial.begin (115200);
  Serial.println ("hello, world");
  return 0;
}


Compiles as:

Code: [Select]
Binary sketch size: 1696 bytes (of a 32256 byte maximum)


That saved 274 bytes. Both work.

Or if you need init  (you may not):

Code: [Select]
int main ()
{
  init ();
 
  Serial.begin (115200);
  Serial.println ("hello, world");
  return 0;
}


That compiled as:

Code: [Select]
Binary sketch size: 1962 bytes (of a 32256 byte maximum)
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: CrossRoads on Oct 11, 2011, 08:24 am
Seems like a somewhat silly discussion - from what I read here, most programs seem to run out of SRAM before they run out of Flash memory.

Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 11, 2011, 10:10 am
@CrossRoads:

That attitude is what has brought us things like .NET installations that gobble up half of your disk space and take 2 weeks to install. Just look at AVRStudio5 vs. 4!

I happen to play with ATtiny chips more often, and at just 2k of flash, wasting more than 200 bytes is an absolute no no.

I just don't understand why something that simple has to be hidden. Why? If people can use for-loops inside "loop()", they can do the same in "main()".

@bubulindo:

I do that already when I can. The arduino IDE leaves a lot to be desired compared to say Code::Blocks, Eclipse...

I'm just giving feedback. I'm not against simplifications - when actually helpful. Hiding main() is just evil.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: bubulindo on Oct 11, 2011, 02:03 pm

@bubulindo:

I do that already when I can. The arduino IDE leaves a lot to be desired compared to say Code::Blocks, Eclipse...

I'm just giving feedback. I'm not against simplifications - when actually helpful. Hiding main() is just evil.


I guess the objective of the IDE is in fact to hide these things from the average user. If you have enough knowledge to skip the IDE and use whatever you please, go ahead.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 11, 2011, 02:43 pm
But why hide something that is SIMPLE ?

I can understand that it is not encouraged to write your own interrupt handlers on day one. That's why we have wrappers like attachInterrupt() - I don't use them either, but I'm perfectly fine with them. But hiding main() ... come one! Thats less than 10 lines of perfectly understandable code. The most intellectual part of it is the for-loop. No pointers, no object oriented code, no if statement, no boolean operators... how simple can it get?

If you really think that hiding main() is _necessary_, then I don't want to know how simple-minded the user-base is thought to be. Every beginner should instantly feel offended by that. That's outrageous!
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 11, 2011, 02:49 pm
@Nick:

have you tried adding pinMode()? or tested it with 1.0 beta ?

Edit:

how about something like this:

main.cpp
Code: [Select]
#define ARDUINO_MAIN
#include <Arduino.h>
#include <main.h> // <-- new line

int main(void)
{
       init();

#if defined(USBCON)
       USB.attach();
#endif

       setup();

       for (;;) {
               loop();
               if (serialEventRun) serialEventRun();
       }

       return 0;
}


main.h
Code: [Select]
#ifndef _main_h_
#define _main_h_

int main(void) __attribute__((weak)); // if the user defines his/her own main() it will be used instead

#endif


Now the 'hidden' main() can be overridden by a user-defined main. On Arduino 1.0 this saves a couple of bytes of flash.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: CrossRoads on Oct 11, 2011, 03:18 pm
@madworm,
I was thinking more along the '328 lines. That's a good point about the smaller parts - I imagine you are not using any bootloader on those then? Just download sketches via the ICSP interface?
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 11, 2011, 03:28 pm
Correct. The ATtiny24 and 2313 don't even have a bootloader section (I believe, could be wrong though).
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: CrossRoads on Oct 11, 2011, 03:32 pm
This came up in another thread as well - do you know how to download a sketch via the ICSP pins using the IDE?
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 11, 2011, 03:51 pm
At least for the bigger chips I use custom 'boards.txt' entries, but I suppose it'll be the same thing for the tiny ones. And I don't use the IDE for the tiny ones...
From what I've seen of 1.0, switching between bootloader and a real programmer will be much easier (menu based, which is great). The fuse settings don't change though, one doesn't regain any flash space that way.


off-topic:

The next big step would be to use one of the bigger ATmegaXX-U chips on the arduino boards with enough flash space to hold both the serial port emulation AND and ISP emulation at the same time. This should once an for all kill this damn "can't upload" issue. Pololu has a programming adapter that does just that, but it doesn't seem to be 'open' and requires winblows tools to change settings.

But I guess the inclusion of avrdude 5.11 (which itself can resets the target board now using '-c arduino') will be a big increase for upload reliability.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 11, 2011, 09:57 pm

@Nick:

have you tried adding pinMode()? or tested it with 1.0 beta ?


I'm not sure I understand the question. I didn't before, but this compiles:

Code: [Select]
int main ()
{
//  init ();
 
  Serial.begin (115200);
  Serial.println ("hello, world");
  pinMode (2, OUTPUT);
  return 0;
}


(With or without init () commented out).

This is the contents of main.cpp:

Code: [Select]
#include <WProgram.h>

int main(void)
{
init();

setup();
   
for (;;)
loop();
       
return 0;
}



If you supply your own main, the linker doesn't attempt to use the inbuilt one. I don't see any problem here.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: bubulindo on Oct 12, 2011, 12:57 am

But why hide something that is SIMPLE ?


To you it is simple... for someone that just started in programming and embedded devices (which is probably the majority of Arduino users) main() makes a lot less sense than setup() and loop().

I can understand you. I only use the board and the bootloader from Arduino, but I also see why Arduino is made the way it is now. But the good thing is that it allows people to evolve and try different ways of using the hardware and software according to their own personal knowledge.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: JChristensen on Oct 12, 2011, 03:23 am

This came up in another thread as well - do you know how to download a sketch via the ICSP pins using the IDE?


Adding entries to boards.txt similar to below works for me (I have others that are just different clock freqs). Your programmer may vary ;-)

Code: [Select]
uno16.name=Arduino Uno ICSP @ 16MHz
uno16.upload.using=arduino:usbtinyisp
uno16.upload.protocol=stk500
uno16.upload.maximum_size=32256
uno16.upload.speed=115200
uno16.bootloader.low_fuses=0xff
uno16.bootloader.high_fuses=0xde
uno16.bootloader.extended_fuses=0x05
uno16.bootloader.path=optiboot
uno16.bootloader.file=optiboot_atmega328.hex
uno16.bootloader.unlock_bits=0x3F
uno16.bootloader.lock_bits=0x0F
uno16.build.mcu=atmega328p
uno16.build.f_cpu=16000000L
uno16.build.core=arduino
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: CrossRoads on Oct 12, 2011, 04:10 am
So you replace

uno16.bootloader.file=optiboot_atmega328.hex

this file with the sketch file to use instead?
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 12, 2011, 12:48 pm
@Nick:

That doesn't seem to work on 1.0 for me. I have to add the 'weak' attribute there.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 12, 2011, 09:54 pm
I don't have version 1.0.  I thought I had version 0022, but I suppose that is alpha, right?

I can't find version version 1.0 on the download page.

I wonder why version 0022 works? They don't have the weak attribute.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 12, 2011, 09:56 pm
@CrossRoads: no.

Code: [Select]
##############################################################
#
# to activate this board, select it and use:
#
# 'Burn Bootloader' - 'w/ USBtinyISP' just once
# this makes sure the correct FUSE settings are used
#
8x8RGBLedMatrix1.name=8x8 RGB LED Matrix - ATmega168 / 16MHz Quartz / USBtiny
8x8RGBLedMatrix1.upload.maximum_size=16384
8x8RGBLedMatrix1.upload.speed=115200
8x8RGBLedMatrix1.upload.using=arduino:usbtinyisp
8x8RGBLedMatrix1.bootloader.low_fuses=0xFF
8x8RGBLedMatrix1.bootloader.high_fuses=0xDD
8x8RGBLedMatrix1.bootloader.extended_fuses=0x05

## just so the IDE doesn't throw an error
## it will be overwritten, but we need the correct FUSE settings
8x8RGBLedMatrix1.bootloader.path=optiboot
8x8RGBLedMatrix1.bootloader.file=optiboot_diecimila.hex
##

8x8RGBLedMatrix1.bootloader.unlock_bits=0x3F
8x8RGBLedMatrix1.bootloader.lock_bits=0x3F
8x8RGBLedMatrix1.build.mcu=atmega168
8x8RGBLedMatrix1.build.f_cpu=16000000L
8x8RGBLedMatrix1.build.core=arduino
#
#
#
##############################################################


If I want to do without a bootloader, I change the fuse settings, lockbits and the available flash size to respect that fact. Uploading works as usual.

Uploading is currently slower with an usbtiny than with optiboot. There is a trivial 'patch' for that, but it was not accepted... it involves adding the bitclock parameter '-B 1' to the programmers.txt and a tiny modification in the java code that deals with uploading. This would increase upload speed at least 10x.

programmers.txt
Code: [Select]
usbtinyisp.name=USBtinyISP
usbtinyisp.protocol=usbtiny
usbtinyisp.bitclock=1


app/src/processing/app/debug/AvrdudeUploader.java
Code: [Select]

@@ -104,6 +104,10 @@ public class AvrdudeUploader extends Uploader  {
Map<String, String> programmerPreferences = target.getProgrammers().get(programmer);
List params = new ArrayList();
params.add("-c" + programmerPreferences.get("protocol"));
+
+ if (programmerPreferences.get("bitclock") != null) {
+ params.add("-B" + Integer.parseInt(programmerPreferences.get("bitclock")));
+ }

if ("usb".equals(programmerPreferences.get("communication"))) {
params.add("-Pusb");


I have given up getting anything added/patched in the IDE, it has proven to be pointless for me. I just complain here.

This will be ignored too I guess, but it is less painful for me overall.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: CapnBry on Oct 13, 2011, 05:26 pm

Let's just use main:

O.O I had no idea you could do that and this is 100% awesome. I just shaved 132 bytes off my sketch and now have enough space to implement a URL decode function (94 bytes) to fix that bug that's been annoying me for months.

Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 13, 2011, 05:33 pm
See! It is useful.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 13, 2011, 09:16 pm

O.O I had no idea you could do that and this is 100% awesome. I just shaved 132 bytes off my sketch and now have enough space to implement a URL decode function (94 bytes) to fix that bug that's been annoying me for months.


Glad that helped. Better not upgrade to version 1.0 though, unless they fix that <hint>.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: pjrc on Oct 16, 2011, 11:05 pm
You CAN use main() instead of setup() and loop().  Really, yes, you can.

Quote

void setup() {
  Serial.begin(9600);
  Serial.println("setup does not run");
}

void loop() {
  Serial.println("loop does not run");
}

int main() {
  init();
  Serial.begin(9600);
  while (1) {
    Serial.println("My main is running");
    delay(1000);
  }
}


This works because main() is inside the core, which gets compiled to a ".a" library archive.  If you use any function with the same name, the linker will put your copy into the final output, rather than the one from the library.

So go ahead and use main().  The ability to do so has been there all along.  Just make sure you call init() to initialize the hardware, so things like millis() and delay() will work properly.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 16, 2011, 11:39 pm
Well... this

Code: [Select]
void setup() {
 Serial.begin(9600);
 Serial.println("setup does not run");
}

void loop() {
 Serial.println("loop does not run");
 pinMode(13,OUTPUT);
}

int main() {
 init();
 Serial.begin(9600);
 while (1) {
   Serial.println("My main is running");
   delay(1000);
 }
}


compiles on 0022 and not on 1.0-rc1.

I've had a quick look on the compiler/linker parameters, but can't find a difference.

Error on 1.0-rc1:

Code: [Select]

avr-gcc -Os -Wl,--gc-sections -mmcu=atmega168 -o /tmp/build792419732568248348.tmp/sketch_oct16a.cpp.elf /tmp/build792419732568248348.tmp/sketch_oct16a.cpp.o /tmp/build792419732568248348.tmp/core.a -L/tmp/build792419732568248348.tmp -lm
core.a(main.cpp.o): In function `main':
/XXX/arduino-1.0-rc1/hardware/arduino/cores/arduino/main.cpp:6: multiple definition of `main'
sketch_oct16a.cpp.o:sketch_oct16a.cpp:16: first defined here


This error vanishes when adding the 'weak' attribute as pointed out before.

I feel that if this compiles (works?) on 0022, it should do the same on 1.0
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: Coding Badly on Oct 18, 2011, 09:57 pm

The difference is that the pin definition data structures have been moved (through a header file) into main.cpp.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 18, 2011, 10:12 pm
Forgive my ignorance, but is using the 'weak' attribute for the linker to only way (correct?) to make it work again in 1.0 ?

Is the reason for the complaint that the user-provided main() is therefore not equivalent to the library one anymore?
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 18, 2011, 10:22 pm

The difference is that the pin definition data structures have been moved (through a header file) into main.cpp.


Why do that? In fact why not change main.cpp from:

Code: [Select]
#include <WProgram.h>

int main(void)
{
init();

setup();
   
for (;;)
loop();
       
return 0;
}


to:

Code: [Select]

void init ();
void setup ();
void loop ();

int main(void)
{
  init();
  setup();
  while (true)
    loop();
  return 0;
}


Then it compiles on its own without any header files, and will only be used if the user doesn't supply their own main function.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: Coding Badly on Oct 18, 2011, 10:39 pm
Forgive my ignorance, but is using the 'weak' attribute for the linker to only way (correct?) to make it work again in 1.0 ?


That is one way.  The other way would be to move the pin definition data structures to another module.  Where they were (wiring_digital) is a good choice.  I would move them to their own module.

Quote
Is the reason for the complaint that the user-provided main() is therefore not equivalent to the library one anymore?


Someone else will have to answer that one.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: Coding Badly on Oct 18, 2011, 10:49 pm
Why do that?


I believe it is an attempt to make the core more portable.  The idea is to have the pins defined in a header file that is located and included when a sketch is built. 

But I don't know why main.cpp was used to pull in the pin definitions.

Quote
In fact why not change main.cpp from ... Then it compiles on its own without any header files, and will only be used if the user doesn't supply their own main function.


I almost agree.  There is some safety in using a common header file for function prototypes.  Well, with overloading, maybe there isn't.  Let me check ... never mind.  I must be thinking of ObjectPascal.

I agree.  The second version is a good alternative.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: nickgammon on Oct 18, 2011, 11:56 pm

I believe it is an attempt to make the core more portable.  The idea is to have the pins defined in a header file that is located and included when a sketch is built. 


Since the developers control what the IDE does when it compiles, why not just have it copy the pins file anyway? I mean, if they are going to copy main.cpp, why not copy pins_arduino.h as well? This seems a convoluted way of doing it.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: Coding Badly on Oct 19, 2011, 01:40 am

I have no idea why it was done the way it was.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: pjrc on Oct 19, 2011, 03:15 pm
I believe the idea was to allow 3rd party boards to use the standard Arduino core more easily.  All the pinout-specific stuff is supposed to go into a single header file, and boards.txt can specify the directory.  So in theory, a board which only needs to customize pins could just add a directory and its own copy of pins_arduino.h, and not need to modify any files, except perhaps boards.txt.

Compiling the code into main.cpp was probably just an oversight?  It very likely belongs in either wiring_digital.c (where it's actually used), or in its own dedicated .c file (as it was in prior to 1.0).

If you delete the ARDUINO_MAIN line from main.cpp, and add it into wiring_digital.c like this:

Code: [Select]
#define ARDUINO_MAIN
#include "wiring_private.h"
#include "pins_arduino.h"


I believe that solves this problem.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: mellis on Oct 23, 2011, 01:00 am
We can certainly move the pins_arduino.h include from main.cpp to some other file, if it helps.  Just submit a issue / patch to the Google Code list: http://code.google.com/p/arduino/issues/list (http://code.google.com/p/arduino/issues/list)
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: pjrc on Oct 23, 2011, 08:33 pm
Done, issue #691, including a patch!  :)

http://code.google.com/p/arduino/issues/detail?id=691

Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: pjrc on Oct 27, 2011, 11:05 pm
Bump.

This patch became part of 1.0-rc2.  Anyone who really cares about main() might want to give 1.0-rc2 a try before 1.0 officially releases?

http://code.google.com/p/arduino/wiki/Arduino1
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 28, 2011, 12:12 am
This example compiles and works:

Code: [Select]
int main(void) {
  init();
  Serial.begin(9600);
  pinMode(2, INPUT);
  while(1) {
    int sensorValue = digitalRead(2);
    Serial.println(sensorValue);
  }
}


I see that all compiler warnings have been turned on, probably only for testing.

Some observations:

Code: [Select]
avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -DARDUINO=100 -I/***/arduino-1.0-rc2/hardware/arduino/cores/arduino -I/***/arduino-1.0-rc2/hardware/arduino/variants/standard /***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.cpp -o/tmp/build4743758903281560802.tmp/IPAddress.cpp.o
In file included from /***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.cpp:3:
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.h: In member function 'IPAddress::operator uint32_t()':
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.h:51: warning: dereferencing type-punned pointer will break strict-aliasing rules
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.h: In member function 'bool IPAddress::operator==(const IPAddress&)':
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.h:52: warning: dereferencing type-punned pointer will break strict-aliasing rules
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/IPAddress.h:52: warning: dereferencing type-punned pointer will break strict-aliasing rules


Code: [Select]
avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -DARDUINO=100 -I/***/arduino-1.0-rc2/hardware/arduino/cores/arduino -I/***/arduino-1.0-rc2/hardware/arduino/variants/standard /***/arduino-1.0-rc2/hardware/arduino/cores/arduino/Tone.cpp -o/tmp/build4743758903281560802.tmp/Tone.cpp.o
/***/arduino-1.0-rc2/hardware/arduino/cores/arduino/Tone.cpp:108: warning: only initialized variables can be placed into program memory area


The last one can be silenced by using 'const prog_uint8_t var_name' instead of 'const uint8_t PROGMEM var_name'.

See: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=57011

I'm using:

* avr-gcc (GCC) 4.4.3
* avr-libc 1.7.1

Thanks for making it work.
Title: Re: Why not (finally) expose main.cpp to the user ?
Post by: madworm on Oct 29, 2011, 06:16 pm
The PROGMEM issue seems identical to

http://code.google.com/p/arduino/issues/attachmentText?id=688&aid=6880000003&name=0004-Avoid-spurious-pgmspace-warnings.-See-http-gcc.gnu.o.patch&token=9f0e77f0e7d48a831b326a901e2ed403