|
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: - To test SRAM after startup;
- Wait until external device will be ready;
- 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 |