7.2 Example

To take advantage of the smaller vector table it is necessary to replace the standard start files used by AVR-GCC. These are disabled by setting the linker flag -nostartfiles when compiling the project. In Atmel Studio 7.0 this can be found in Project Properties (Alt+F7) - Toolchain - AVR/GNU Linker - General, as seen in Figure 7-1.

Figure 7-1. Configuring "Do not use standard start files", Atmel Studio 7.0

The following code snippet shows an example for the code needed to replace the standard start files. In a future Toolchain release, this step will not be needed to configure the Compact Vector Table.

Example start-up code for Compact Vector Table
// io.h includes the device header file with necessary defines
#include <avr/io.h>

// Letting the compiler know there will be something called main
extern int main(void);

// Being nice to the compiler by predeclaring the ISRs
void __vector_cvt_nmi(void) __attribute__((weak, alias("dummy_handler")));
void __vector_cvt_lvl1(void) __attribute__((weak, alias("dummy_handler")));
void __vector_cvt_lvl0(void) __attribute__((weak, alias("dummy_handler")));

// Setting up the vector section
// The rjmp instruction can handle 8k code space, so this is used for
// vector tables on devices with 8k flash or smaller. Other devices
// use the jmp instruction.
__attribute__((section(".vectors"), naked)) void vectors(void)
{
#if (PROGMEM_SIZE <= 0x2000)
    asm("rjmp __ctors_end");
    asm("rjmp __vector_cvt_nmi");
    asm("rjmp __vector_cvt_lvl1");
    asm("rjmp __vector_cvt_lvl0");
#else
    asm("jmp __ctors_end");
    asm("jmp __vector_cvt_nmi");
    asm("jmp __vector_cvt_lvl1");
    asm("jmp __vector_cvt_lvl0");
#endif
}

// Initialize the AVR core
__attribute__((section(".init2"), naked)) void init2(void)
{
    // GCC expects r1 to be zero
    asm("clr r1");
    // Make sure the status register has a known state
    SREG = 0;
    // Point the stack pointer to the end of stack
    SPL  = INTERNAL_SRAM_END & 0xff; // (low byte)
    SPH  = (INTERNAL_SRAM_END >> 8); // (high byte)
}

// Handling main
__attribute__((section(".init9"), naked)) void init9(void)
{
    main();

    // Jump to avr libc defined exit handler
    // (Disables interrupts and runs an empty loop forever)
    asm("jmp _exit");
}

// Dummy handler alias for unused ISRs
void dummy_handler(void)
{
    while (1)
        ;
}
                
                

The following code snippet shows an example on how to configure the Compact Vector Table, using the interrupt vector names defined in the example start-up code from above.

Compact Vector Table configuration code
// io.h includes the device header file with register and vector defines,
// it also includes xmega.h, containing the CCP macro _PROTECTED_WRITE().
#include <avr/io.h>
// interrupt.h contains the ISR related content
#include <avr/interrupt.h>

void compact_vector_table_example(void) {
    // Set the Compact Vector Table
    // read-modify-write to preserve other configured bits 
    _PROTECTED_WRITE(CPUINT.CTRLA, (CPUINT.CTRLA | CPUINT_CVT_bm));

    //Enable global interrupts
    sei();
}

ISR(__vector_cvt_lvl0) {
	// All level 0 interrupt will be handled here
	if (PORTA.INTFLAGS) {
        // Example on how to handle PORTA interrupts in CVT mode 	
	}
}

ISR(__vector_cvt_lvl1) {
	// If enabled, level 1 interrupt will be handled here
}

ISR(__vector_cvt_nmi) {
	// If enabled, NMI interrupts will be handled here
}

Atmel | START example

A use case example for Compact Vector Table using Atmel | START is also available. For more information, see the Get Source Code from Atmel | START chapter.