Example of using sections in WinAVR

Before you start reading this

it is recommended to read

 

described in avrlibc documentation

to get picture what it is all about.

In this article you will see how

to create projects by memory using sections

for solving many tasks before

main program starts. Let's say wee need: 

  1. To test SRAM after startup;
  2. Wait until external device will be ready;
  3. and then Prepare I/O ports;

Bellow is a programm with comments:

#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

// Redirect all unused interrupts to reti
EMPTY_INTERRUPT( __vector_default );
extern void __ctors_end(void) __attribute__((__noreturn__));

// macros for entering subprograms
#define __JMP_INIT__ __asm__ __volatile__ ("rjmp __ctors_end" )

/*First function which is performed after reset.
Later this
function controls program process*/

void __init(void) __attribute__((naked));
void __init(void)
{
/*some kind of operations
(setting ports, ram testing,...)
which are performed before initialization
of stack __zero_reg__ */
DDRC = 0B00001110;
// setting port
volatile register uint8_t *data = (uint8_t*)0x0060;
//__attribute__((section(".data")));
for( register uint16_t i=0; i<1024; i++)
{
data[i] = 0x55;
if( data[i] != 0x55 )
{
PORTC |= _BV(PC3);
break;
}
data[i] = 0xAA;
if( data[i] != 0xAA )
{
PORTC |= _BV(PC3);
break;
}
}
//waiting for external devices to be ready
// then continue program flow
while( (PINC&_BV(PC0)) == 1 );
/*because function is marked as “naked”
then after each “}” initialization
jumps to following program.
If there is need to set up __zero_reg__
and stack pointer, then go to standard
point of calling macro program*/
__JMP_INIT__;
}
/*Following program will be placed just after
__zero_reg__ ans stack pointer initialization*/
void init3(void) __attribute__((section(".init3"))) __attribute__((naked));
void init3(void)
{
DDRB = 0xFF;
PORTB = 0xFF;
DDRD = 0xFF;
PORTD = 0;
}

int main(void)
{
uint8_t ii=0;
while( 1 )
{
for( uint8_t i=0; i<100; i++ )
{
PORTD ^= _BV(PC1);
}
if( ii++ >= 100 ) break;
} // end while
return 0;
}

Now lets see what happened in assembly code after compiling this program

(file sections.lss in project folder):

After reset without __init() and init3 it looks like:

Disassembly of section .text:
00000000 <__vectors>:
0: 12 c0 rjmp .+36 ; 0x26 <__ctors_end>

if __init() and init3 are used we see that exit code was placed in __inti():

Disassembly of section .text:

00000000 <__vectors>:
0: 34 c0 rjmp .+104 ; 0x6a <__init> <------------
2: 31 c0 rjmp .+98 ; 0x66 <__bad_interrupt>

subprogram __init():

void __init(void) __attribute__((naked));
void __init(void)
{
/*some kind of operations
(setting ports, ram testing,...)
which are performed before initialization
of stack __zero_reg__ */
DDRC = 0B00001110; // setting port
68: 8e e0 ldi r24, 0x0E ; 14
6a: 84 bb out 0x14, r24 ; 20
...
__JMP_INIT__;
9e: c3 cf rjmp .-122 ; 0x26 <__ctors_end> go to section .init2

000000a0 <main>:
}

we see that in subprogram init3() there is no prologue and epilogue because of using “naked”:

00000032 <init3>:
32: 8f ef ldi r24, 0xFF ; 255
34: 87 bb out 0x17, r24 ; 23
36: 88 bb out 0x18, r24 ; 24
38: 81 bb out 0x11, r24 ; 17
3a: 12 ba out 0x12, r1 ; 18

Then follows program code:

0000003c <__do_copy_data>:
3c: 10 e0 ldi r17, 0x00 ; 0
3e: a0 e6 ldi r26, 0x60 ; 96
40: b0 e0 ldi r27, 0x00 ; 0
42: ea ec ldi r30, 0xCA ; 202
44: f0 e0 ldi r31, 0x00 ; 0
46: 02 c0 rjmp .+4 ; 0x4c <.do_copy_data_start>

In other hand if we used other entering functions (belonging to sections .init0 or .init1) instead __inti():

void init0(void) __attribute__((section(".init0"))) __attribute__((naked));
void init0(void)
{
DDRC = 0B00001110;

volatile register uint8_t *data = (uint8_t*)0x0060;
//__attribute__((section(".data")));

//....

while( (PINC&_BV(PC0)) == 1 );
}

Then we get another code which shows that there is no need to show entering point

__ctors_end() in to macro __JMP_INIT__ :

Disassembly of section .text:

00000000 <__vectors>:
0: 12 c0 rjmp .+36 ; 0x26 <init0>
2: 4b c0 rjmp .+150 ; 0x9a <__bad_interrupt>
...

00000026 <init0>:

DDRC = 0B00001110;
26: 8e e0 ldi r24, 0x0E ; 14
28: 84 bb out 0x14, r24 ; 20

volatile register uint8_t *data = (uint8_t*)0x0060;
//__attribute__((section(".data")));

for( register uint16_t i=0; i<1024; i++)
2a: 20 e0 ldi r18, 0x00 ; 0
...
while( (PINC&_BV(PC0)) == 1 );
58: 98 99 sbic 0x13, 0 ; 19
5a: fe cf rjmp .-4 ; 0x58 <__SREG__+0x19>

start of section .init2
5c: 11 24 eor r1, r1
5e: 1f be out 0x3f, r1 ; 63
60: cf e5 ldi r28, 0x5F ; 95
62: d4 e0 ldi r29, 0x04 ; 4
64: de bf out 0x3e, r29 ; 62
66: cd bf out 0x3d, r28 ; 61

00000068 <init3>:
68: 8f ef ldi r24, 0xFF ; 255
6a: 87 bb out 0x17, r24 ; 23

...
Source: avr.h15.ru