main function of an AVR program

Go To Last Post
33 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What happens when the main method of an AVR program returns? Is it possible to have your application function solely on interrupts?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It disables interrupts and goes into an infinite loop.

You can check using "avr-objdump -d file.elf" on the elf file for your program.   See code starting at (byte) address 0xac below.

Disassembly of section .text:

00000000 <__vectors>:
   0:	0c 94 50 00 	jmp	0xa0	; 0xa0 <__ctors_end>
   4:	0c 94 5a 00 	jmp	0xb4	; 0xb4 <__bad_interrupt>
   ...

000000a0 <__ctors_end>:
  a0:	11 24       	eor	r1, r1
  a2:	1f be       	out	0x3f, r1	; 63
  a4:	cf ef       	ldi	r28, 0xFF	; 255
  a6:	cd bf       	out	0x3d, r28	; 61
  a8:	df e3       	ldi	r29, 0x3F	; 63
  aa:	de bf       	out	0x3e, r29	; 62
  ac:	0e 94 5c 00 	call	0xb8	; 0xb8 <main>
  b0:	0c 94 5f 00 	jmp	0xbe	; 0xbe <_exit>

000000be <_exit>:
  be:	f8 94       	cli

000000c0 <__stop_program>:
  c0:	ff cf       	rjmp	.-2      	; 0xc0 <__stop_program>

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thats very good to know! So I guess if I want an interrupt based application I need to loop infinitely rather than exiting the main function

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

testdrone wrote:

Thats very good to know! So I guess if I want an interrupt based application I need to loop infinitely rather than exiting the main function

 

That sounds like good practice (you are in control).   Try writing a main with loop and see that assembly comes out.

There is also the option of putting the CPU to sleep.  The infinite loop would have a sleep inside.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All embedded (non OS) micro programs should remain in main() even if this just means an empty while(1). While avr-gcc does have the catch all that Matt showed there was one version of this compiler+library that did not do this and it caused absolute havoc among the many programs that had been written to rely on a catch-all that now did not exist!
.
Obviously if your C code is in a "hosted" environment you will want to return from main() at some stage and even return an int value to say if it worked (0) or the reason why not (1.. MAX_INT).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One option that you can use if you don't want to do anything in main() but don't want to just "spin your wheels" endlessly, is to use one of the sleep modes.  If you enter sleep in main it will remain there until an interrupt occurs.  The CPU will wake from sleep and service the interrupt.  Then the control will return to main() where it will again hit the sleep function and go back to sleep.

 

This can also save considerable power if that's an issue in your design.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jwhance wrote:
Then the control will return to main() where it will again hit the sleep function and go back to sleep.

But that still needs a while(1) loop.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
jwhance wrote:
Then the control will return to main() where it will again hit the sleep function and go back to sleep.
But that still needs a while(1) loop.

 

Yes, that's true.  Although if you really don't like while, you can always use a for loop...  ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is it possible to have your application function solely on interrupts?

If there is nothing else, what would the interrupt be interrupting? Then sounds more like a wake/sleep/wake...

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As I recall, "running off the end of the code" in assembler causes a processor reset when it enters unprogrammed flash space.  S.

 

Edited to add:  Probably because 0xFFFF (unprogrammed space) is interpreted as 0x0000 (NOP), and then the PC just runs until it wraps the counter back to 0x0000 (reset vector).  S.

Last Edited: Mon. Jan 4, 2021 - 12:16 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

testdrone wrote:
What happens when the main method of an AVR program returns?

The 'C' language specification wrote:

The effect of program termination [ie, exiting main] in a freestanding environment is implementation-defined

in other words, it depends on what toolchain you are using.

 

As already noted, GCC has a loop to "catch" any exit from main - but other toolchains may not ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scroungre wrote:
Probably because 0xFFFF (unprogrammed space) is interpreted as 0x0000 (NOP),
Just to be pedantic but it actually behaves as SBRS R31,7 so, unlike a NOP, if bit 7 of R31 is set it will execute every second 0xFFFF not every single 0xFFFF as would be the case if were really behaving like NOP.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now when we are " pedantic " then the instruction 0xffff is NOT SBRS R31,7 but undefined, it's correct that original AVR's did that instruction because it made a incomplete instruction decoding, (there is only one 0), but in the future (perhaps some of the newer AVR's already have a instruction there I have not checked it). 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:
then the instruction 0xffff is NOT SBRS R31,7 but undefined,
which is why I very deliberately used the word " behaves as" because I'm well aware it is not actually SBRS R31,7 ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And if bit 7 of R31 is not set it behaves as NOP.  So there.  devil   S.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure that the newer AVR designs also behave that way ? ( 0-series and 16 register AVR's etc. )

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW the default for avr-gcc is hosted.

The reason for the choice is documented somewhere.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can declare main as "no return" it will save some space in flash, __attribute__ ((noreturn))

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

12oclocker wrote:
You can declare main as "no return"

This does not prevent the function from returning - it remains up to you to ensure that it really does not return.

 

There are also some other provisos - see:

 

https://gcc.gnu.org/onlinedocs/g...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

12oclocker wrote:
You can declare main as "no return"

This does not prevent the function from returning - it remains up to you to ensure that it really does not return.

 

There are also some other provisos - see:

 

https://gcc.gnu.org/onlinedocs/g...

 

 

Interestingly, I didn't catch in that linked discussion where noreturn is related to main().

 

All the while the Kingston Trio runs through my head...

Well did he ever return, no he never returned
And his fate is still unlearned (what a pity)
He may ride forever 'neath the streets of Boston
He's the man who never returned

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

o/~  Did it ever return?

No it never returned

And its value is still unlearn'd

It will run forever

Down in the Flash RAM

It's the main() that never returned...  o/~   S.

 

(eta: and theusch beat me to it, too)

(apologies to the Kingston Trio et. al.)

Last Edited: Tue. Jan 5, 2021 - 01:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
 I didn't catch in that linked discussion where noreturn is related to main()

The link doesn't specifically mention main() at all - but some things seem applicable; eg,

 

The GCC documentation wrote:
The noreturn keyword tells the compiler to assume that [the function] cannot return.

The OP question was, "What happens when the main method of an AVR program returns?" - so use of noreturn really doesn't address that question.

 

Perhaps  12oclocker has misunderstood, and thought that noreturn would prevent main from returning?

 

The GCC documentation also wrote:
It does not make sense for a noreturn function to have a return type other than void.

But GCC also insists that main() have a return type of int.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
But GCC also insists that ...

That should have been the emphasis in the first responses --  what toolchain are you using?  ... it will vary among toolchains and options ... what do you expect to happen? ... and similar.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
But GCC also insists that main() have a return type of int.

 

To void main(), or not to void main(),

That is the question,

Is it nobler to return from main or not!

 

Personally in an embedded app, I have always used:

#define forever 1

void main(void)
{
    while(forever)
    {
        //do some thing useful!
    }
}

as a starting point, the usual standard return(0) never made sense to me in an embedded app.  I do acknowledge the origin of the standard, and which ever way you prefer is ok with me.

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
That should have been the emphasis in the first responses --  what toolchain are you using? 

Indeed - #11 was my first response.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry I was not clear, I did not misunderstand, I was simply stating, in your main loop, since you should never allow main to return anyway, declare it void with no return attributes, and save some flash space.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
But GCC also insists that main() have a return type of int.
Not just gcc: C standards insist that main have return type int.

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The exit function in avr-gcc is a weak function, so if you prefer to pretend you are running a pc you can return into a black hole of your own creation. Since the exit function is declared as a noreturn function in stdlib.h, you would simply be moving your endless loop from main to exit along with any other code that could have simply stayed in main. In other words, what I just said is useless information (not unusual) except to point out you do have a choice if you wish. The other side of main in an mcu is like a black hole- observe/understand all you want, but there is no reason to enter.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

skeeve wrote:
C standards insist that main have return type int.

actually not:

The C language specification wrote:
In a freestanding environment (in which C program execution may take place without any benefit of an operating system), the name and type of the function called at program startup are implementation-defined.

 

But skeeve wrote:
the default for avr-gcc is hosted.

 

For a Hosted environment, the C language specification wrote:
The function called at program startup is named main ... It can be defined with no parameters:

int main( void )

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ISO/IEC 9899:201x

[top of page 32]

5.1.2.2.3 Program termination

...

If the return type is not compatible with int, the termination status returned to the host environment is unspecified.

due to Main function - cppreference.com (mid-page, third special property)

 


ISO/IEC JTC1/SC22/WG14 - C: Approved standards

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

ki0bk wrote:

awneil wrote:
But GCC also insists that main() have a return type of int.

 

To void main(), or not to void main(),

That is the question,

Is it nobler to return from main or not!

 

Personally in an embedded app, I have always used:

#define forever 1

void main(void)
{
    while(forever)
    {
        //do some thing useful!
    }
}

as a starting point, the usual standard return(0) never made sense to me in an embedded app.  I do acknowledge the origin of the standard, and which ever way you prefer is ok with me.

Jim

 

My preferred (mis)use of the preprocessor is:

#define ever (;;)

int main(void)
{
    for ever {
        // something useful
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:
(mis)use of the preprocessor

How about:

#define forever while(1)

do
{

    // stuff

} forever;

or even

forever
{

    // stuff

} ;

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:

#define ever (;;)

I like it!!! 

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"