to main() or not to main() ?

Few years back a solution to annoying problem was to bypass *.ino and use modified Arduino copy of standard main() function.
It is no longer a problem , however, after using “BareMinimun” as a starting point for my code I have decided to go back to main().
To avoid any confusion – no , I do not have to use main(), my apps works fine in Setup() , happily dodging Loop().
The reason for this post is that current (1.6.11.) main() code does some strange things when used direct, without modification. ( see attached )

  1. init() activates WDT causing reset at about 12 seconds
    This has been discussed here recently and hack was found to stop WDT.
  2. initVariant(); supposedly allows for 3rd party something, but it is obviously already implemented and causes multiple main definitions so basically defeats the “weak” attribute function concept
    ( Similar hack is applied to UOTGHS_Handler weak function with “strong” function defined in core. It works, but user should define the strong function, not the core code. )
  3. #if defined(USBCON) I am not sure what this does, I’ll find out later
    USBDevice.attach();
    #endif

I have no illusions or quarrel with “BareMinimum” hide main() function concept, and have no desire to discuss that.
I just like to know why useful options like weak attributes functions are being castrated and main() is no longer useful without digging into basic like init()- as in case of WDT.
Jim

/*
  main.cpp - Main loop for Arduino sketches
  Copyright (c) 2005-2013 Arduino Team.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

Actually there is a significant benefit to implementing your own main() in the sketch. You can get rid of that idiotic serialEventRun thing which slows down and wastes memory in the 99.99% of sketches that don't use serialEvent. In previous Arduino AVR Boards versions it also allowed you to make setup() and loop() static so that they would be inlined but with the new compiler version included since Arduino AVR Boards 1.6.12 LTO is smart enough to do this with the stock main(). I actually find the setup() and loop() system useful but letting the IDE hide away main() somewhere is only reasonable if the developers can be trusted to not throw pointless bloat in there. When I took the time to dig up main.c and found that serialEventRun garbage they lost my trust.

julyjim:

  1. init() activates WDT causing reset at about 12 seconds
    This has been discussed here recently and hack was found to stop WDT.

Which board and which core version have you experienced this with? I don't have that issue using Arduino AVR Boards with any core/board/IDE version I've tested and I use my own main() in many projects. If this was correct then the following sketch should continuously blink:

int main() {
  init();
#if defined(USBCON)
  USBDevice.attach();
#endif
  pinMode(13, OUTPUT);
  for (byte i = 0; i < 12; ++i) {
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
  }
  while (true) {}
  return 0;
}

but for me it stops blinking after 12 seconds. The 12 seconds number doesn't even make sense because the longest AVR timeout value is 8 seconds.

julyjim:
2. initVariant(); supposedly allows for 3rd party something, but it is obviously already implemented and causes multiple main definitions so basically defeats the “weak” attribute function concept

Luckily it's not used for very many boards. If anyone can tell me how to call initVariant() from the sketch I'd really appreciate it.

julyjim:
I just like to know why useful options like weak attributes functions are being castrated and main() is no longer useful without digging into basic like init()- as in case of WDT.

Well I question your claim of a WDT issue but I agree that the ability to use the standard C convention of main() is a valuable feature to retain. I remember reading a discussion with the Arduino developers where they said that the ability to override the stock main() was an accident, not intentional, and that it should not be relied upon as this could change at any time.

I think my first issue with WDT was in 1.6.10.
I am now on 1.6.11 and have no need to move up, so far.
I am using ARM / Due and pretty happy with it for what I want to do.
We discussed the WDT issue here at length, the outcome was strange because ARM lets you write into register only once , I would have to go back to thread to check which one, but it does not matter.
Basically stock main () uses init() to reset the WDT which should not be set in first place.
Than you have to dig into init to find out how to reset it yourself when you use main().
Kind of chicken and egg syndrome.
Ever since I got into computers I always had an issue with people telling me I am on my own when I monkey with THEIR code. That is the lamest excuse - if I modify their code I DO NOT EVER expect them to come to my aid - I can dig myself out of my own hole.

But I do expect OPEN SOURCE IDE to have some continuity and major changes being documented.
And that is as far as I want to discuss this OPEN SOURCE issue, it is pointless to even bring it up.

I also would like someone to show application for this iniVariant weak function. Or at least find out what does the current one do, I just don't have time and desire to trace it.

I had enough headache finding how to hook into UOTGHS_Handler.
I wish developers would leave the weak functions alone instead of defining (some of) them in core code. sysTick is another one the screwed up with - on ARM due.

Actually I am kinda of glad Arduino inc abandoned Due - its way over their heads.

PS I need to get back to coding to figure out how to make several "print" programs cooperate with each other. Class inheritance is "great " fun.

I think I'll start with "printf". You and I discussed that while ago and I did not ever found out where is the actual source code for it.
I may start another thread about this later.

Jim

julyjim:
I am using ARM / Due

Ok, that makes sense. I've only done the main() thing with AVR.

julyjim:
Basically stock main () uses init() to reset the WDT which should not be set in first place.
Than you have to dig into init to find out how to reset it yourself when you use main().

Can't you just call init() from the main() in your sketch?

julyjim:
I also would like someone to show application for this iniVariant weak function. Or at least find out what does the current one do

Here's an example(Arduino/hardware/arduino/avr/variants/gemma/pins_arduino.h at 1.6.12 · arduino/Arduino · GitHub):

void initVariant()
{
 GTCCR |= (1 << PWM1B);
}

Can't you just call init() from the main() in your sketch?

You do, but than you have to tolerate WDT to fire every 12 seconds afterwards.

It has to be just disabled - somewhere- because you cannot write to the offending register again, per ARM spec.

Jim

current (1.6.11.) main() code does some strange things when used direct, without modification.

  1. init() activates WDT causing reset at about 12 seconds

Really? I don't see this (although I'm using 1.6.12, having skipped 11. A quick test program shows that my Due starts up with the WDT disabled. Nor can I find any evidence in the source or git histories that anything in main() or init() has been changed recently. (Hmm. back in 1.5.x, I don't see watchdogSetup() called by main(), but watchdogSetup() normally disables watchdogs...)

This has been discussed here recently and hack was found to stop WDT.

I don't see any recent discussion, either. Do you have a pointer? (maybe my definition of "recent" is shorter than yours.)

  1. initVariant(); supposedly allows for 3rd party something, but it is obviously already implemented and causes multiple main definitions so basically defeats the "weak" attribute function concept

InitVariant() is for any variant that needs special initialization. Due is a variant of the sam3x8e core, therefore it has an initVariant() function. If you were a 3rd party, you could use a different variant file, perhaps one that does not include an initVariant() definition.

But I do expect OPEN SOURCE IDE to have some continuity and major changes being documented.

Between beta and production code, in a section that is not part of the public API or documented features? You've got to be kidding. I mean it's nice that I can define my own main() and bypass Arduino initialization, but the details of what what the initialization (that I've chosen to skip) are not documented, need not have "continuity" and it's up to me to make sure I understand what I'm missing and whether it needs to be replaced. The source code IS available, after all.

It looks like in 1.5.x, Arduino Due core did nothing to the WDT, which means that it was enabled by default as per datasheet:

After a Processor Reset, the value of WDV is 0xFFF, corresponding to the maximum value of the counter with the external reset generation enabled (field WDRSTEN at 1 after a Backup Reset). This means that a default Watchdog is running at reset, i.e., at power-up. The user must either disable it (by setting the WDDIS bit in WDT_MR) if he does not expect to use it or must reprogram it to meet the maximum Watchdog period the application requires.
The Watchdog Mode Register (WDT_MR) can be written only once.

In 1.6.x, the WDT is disabled in the Arduino core implementation of main() (using up that one write, BTW.)

you cannot write to the offending register again, per ARM spec.

The WDT is not part of the ARM core or spec. It's an Atmel thing. (Atmel claims their WDT is "AMBA Compliant", and AMBA is an ARM thing. But I don't see this "write only once" thing in the AMBA specs.)

sysTick is another one they screwed up with - on ARM due.

Systick is the natural and obvious way to implement the millis() timer.
You really can't get mad "because the operating system I want to provide easy-to-use services also grabs some chip resources that I wanted to use for something else." You have to take the annoying with pleasing...