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 1.

Figure 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.