Hi All
I wanted to post the AVR32 interrupt handling method in case any one working with the project was wondering how it is done. Here is the original idea and explanation...
"I found the interrupt controller a bit strange in its use of a 16k range for interrupt code. This is handled differently by whatever compiler is being used and seemed a bit messy. Therefore I decided to ‘invent’ another method which seems a bit more flexibly and compiler independent. I set the first 260 bytes of SRAM as an exception table and I pointed the EVBA to it (just set 0x00000000). At initialization I filled this table with 0xe08f0000 which is the machine code of a forever loop (branch to self). If any exceptions occur, they jump to their own loop and the debugger can easily see which exception it was and look at the saved context to find out where it came from. In between the exceptions there is enough space to define locations to handle peripheral interrupts (20 groups exist in the AT32UC3A) and I have defined each 2 long words. When an interrupt handler for the group is entered its interrupt priority register is loaded with the offset to its group space in the exception table and the address of the handler is written there, together with the long word 0x481fd703 (machine code for load PC with the value at the next long address + NOP). When any peripheral interrupt occurs it thus vectors to the entry in the exception table and them immediately is sent to the handler location anywhere in FLASH. This does take one extra jump instruction but removes restrictions about locating the interrupt routines together in a single 16k area, at a correct boundary, and also the restriction of the EVBA boundary (since 0x00000000 is a perfect case for it). Also there is no more restriction of having many possible interrupt handlers (which can be exchanged at will) since where they are is no longer important – they can have any address in the memory range. Below is the code which has worked well for first peripheral tests. It defines the peripheral group locations, initializes the table and enters interrupts:
// Event table which is put to SRAM to handle all exceptions and interrupts
//
typedef struct stEXCEPTION_TABLE
{
unsigned long evUnrecoverableException;
unsigned long evTLBmultipleHit;
unsigned long evBusErrorDataFetch;
unsigned long evBusErrorInstructionFetch;
unsigned long evNonMaskableInterrupt;
unsigned long evMissingAddress;
unsigned long evITLBProtection;
unsigned long evBreakPoint;
unsigned long evIllegalOpcode;
unsigned long evUnimplementedInstruction;
unsigned long evPrivilegeViolation;
unsigned long evFloatingPoint;
unsigned long evCoprocessorAbsent;
unsigned long evDataAddressRead;
unsigned long evDataAddressWrite;
unsigned long evDTLBProtectionRead;
unsigned long evDTLBProtectionWrite;
unsigned long evDTLBModified;
unsigned long evGroup0; // 0x48
unsigned long evAdd0; // 0x4c
unsigned long evITLBMiss;
unsigned long evGroup1; // 0x54
unsigned long evAdd1; // 0x58
unsigned long evRes1; // 0x5c
unsigned long evITLBMissRead;
unsigned long evGroup2; // 0x64
unsigned long evAdd2; // 0x68
unsigned long evRes2; // 0x6c
unsigned long evITLBMissWrite;
unsigned long evGroup3; // 0x74
unsigned long evAdd3; // 0x78
unsigned long evGroup4; // 0x7c
unsigned long evAdd4; // 0x80
unsigned long evGroup5; // 0x84
unsigned long evAdd5; // 0x88
unsigned long evGroup6; // 0x8c
unsigned long evAdd6; // 0x90
unsigned long evGroup7; // 0x94
unsigned long evAdd7; // 0x98
unsigned long evGroup8; // 0x9c
unsigned long evAdd8; // 0xa0
unsigned long evGroup9; // 0xa4
unsigned long evAdd9; // 0xa8
unsigned long evGroup10; // 0xac
unsigned long evAdd10; // 0xb0
unsigned long evGroup11; // 0xb4
unsigned long evAdd11; // 0xb8
unsigned long evGroup12; // 0xbc
unsigned long evAdd12; // 0xc0
unsigned long evGroup13; // 0xc4
unsigned long evAdd13; // 0xc8
unsigned long evGroup14; // 0xcc
unsigned long evAdd14; // 0xd0
unsigned long evGroup15; // 0xd4
unsigned long evAdd15; // 0xd8
unsigned long evGroup16; // 0xdc
unsigned long evAdd16; // 0xe0
unsigned long evGroup17; // 0xe4
unsigned long evAdd17; // 0xe8
unsigned long evGroup18; // 0xec
unsigned long evAdd18; // 0xf0
unsigned long evGroup19; // 0xf4
unsigned long evAdd19; // 0xf8
unsigned long evRes3; // 0xfc
unsigned long evSupervisorCall; // 0x100
} EXCEPTION_TABLE;
#define BRANCH_TO_SELF 0xe08f0000 // AVR32 machine code to create a forever loop
#define LOAD_PC_WITH_NEXT_VALUE 0x481fd703 // LDDPC relative plus NOP
#define EXCEPTION_VECTOR_BASE_ADDRESS 0x00000000
// Perform very low level AVR32 initialisation - called by the start up code
//
static void AVR32_LowLevelInit(void)
{
EXCEPTION_TABLE *ptrEventTable = (EXCEPTION_TABLE *)EXCEPTION_VECTOR_BASE_ADDRESS; // place an event table at the start of RAM
unsigned long *ulPtrEntries = &ptrEventTable->evUnrecoverableException;
int i = 0;
while (i++ < (sizeof(EXCEPTION_TABLE)/sizeof(unsigned long))) {
*ulPtrEntries++ = BRANCH_TO_SELF; // fill the event table with forever loops to catch unexpected exceptions
}
__set_EVBA(EXCEPTION_VECTOR_BASE_ADDRESS); // set EVBA to the start of SRAM
}
static const unsigned char ucGroupLocation[] = {18, 21, 25, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61};
// Function used to enter interrupts
//
static void fnEnterAVRInterrupt(int iIntGroup, unsigned long ulIntLevel, void (__interrupt *InterruptFunc)(void))
{
unsigned long *ptrEventTable = (unsigned long *)EXCEPTION_VECTOR_BASE_ADDRESS;
unsigned long *ptrIntPriority = (unsigned long *)INTC_BLOCK;
ptrIntPriority += iIntGroup;
ptrEventTable += ucGroupLocation[iIntGroup];
*ptrEventTable++ = LOAD_PC_WITH_NEXT_VALUE;
*ptrEventTable = (unsigned long)InterruptFunc;
*ptrIntPriority = (ulIntLevel | (((unsigned long)ucGroupLocation[iIntGroup]) << 2));
}
Here is how an interrupt handler is entered – eg of the TICK:
fnEnterAVRInterrupt(IR_GROUP_SYSBLOCK, INT_LEVEL_1, _RealTimeInterrupt);
Hope it is basically understandable. I do think that it is a fairly elegant solution to keep this stuff generic, otherwise I have the feeling that the technique is rather dictated by the particular compiler manufacturer...
Regards
Mark