/****************************************************************************** | |
* Filename: interrupt.c | |
* Revised: 2015-11-16 20:04:11 +0100 (Mon, 16 Nov 2015) | |
* Revision: 45095 | |
* | |
* Description: Driver for the NVIC Interrupt Controller. | |
* | |
* Copyright (c) 2015, Texas Instruments Incorporated | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* 1) Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the following disclaimer. | |
* | |
* 2) Redistributions in binary form must reproduce the above copyright notice, | |
* this list of conditions and the following disclaimer in the documentation | |
* and/or other materials provided with the distribution. | |
* | |
* 3) Neither the name of the ORGANIZATION nor the names of its contributors may | |
* be used to endorse or promote products derived from this software without | |
* specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
******************************************************************************/ | |
#include <driverlib/interrupt.h> | |
//***************************************************************************** | |
// | |
// Handle support for DriverLib in ROM: | |
// This section will undo prototype renaming made in the header file | |
// | |
//***************************************************************************** | |
#if !defined(DOXYGEN) | |
#undef IntRegister | |
#define IntRegister NOROM_IntRegister | |
#undef IntUnregister | |
#define IntUnregister NOROM_IntUnregister | |
#undef IntPriorityGroupingSet | |
#define IntPriorityGroupingSet NOROM_IntPriorityGroupingSet | |
#undef IntPriorityGroupingGet | |
#define IntPriorityGroupingGet NOROM_IntPriorityGroupingGet | |
#undef IntPrioritySet | |
#define IntPrioritySet NOROM_IntPrioritySet | |
#undef IntPriorityGet | |
#define IntPriorityGet NOROM_IntPriorityGet | |
#undef IntEnable | |
#define IntEnable NOROM_IntEnable | |
#undef IntDisable | |
#define IntDisable NOROM_IntDisable | |
#undef IntPendSet | |
#define IntPendSet NOROM_IntPendSet | |
#undef IntPendGet | |
#define IntPendGet NOROM_IntPendGet | |
#undef IntPendClear | |
#define IntPendClear NOROM_IntPendClear | |
#endif | |
//***************************************************************************** | |
// | |
//! This is a mapping between priority grouping encodings and the number of | |
//! preemption priority bits. | |
// | |
//***************************************************************************** | |
static const uint32_t g_pui32Priority[] = | |
{ | |
NVIC_APINT_PRIGROUP_0_8, NVIC_APINT_PRIGROUP_1_7, NVIC_APINT_PRIGROUP_2_6, | |
NVIC_APINT_PRIGROUP_3_5, NVIC_APINT_PRIGROUP_4_4, NVIC_APINT_PRIGROUP_5_3, | |
NVIC_APINT_PRIGROUP_6_2, NVIC_APINT_PRIGROUP_7_1 | |
}; | |
//***************************************************************************** | |
// | |
//! This is a mapping between interrupt number and the register that contains | |
//! the priority encoding for that interrupt. | |
// | |
//***************************************************************************** | |
static const uint32_t g_pui32Regs[] = | |
{ | |
0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3, NVIC_PRI0, NVIC_PRI1, | |
NVIC_PRI2, NVIC_PRI3, NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7, | |
NVIC_PRI8, NVIC_PRI9, NVIC_PRI10, NVIC_PRI11, NVIC_PRI12, NVIC_PRI13 | |
}; | |
//***************************************************************************** | |
// | |
//! \brief The default interrupt handler. | |
//! | |
//! This is the default interrupt handler for all interrupts. It simply loops | |
//! forever so that the system state is preserved for observation by a | |
//! debugger. Since interrupts should be disabled before unregistering the | |
//! corresponding handler, this should never be called. | |
//! | |
//! \return None | |
// | |
//***************************************************************************** | |
static void | |
IntDefaultHandler(void) | |
{ | |
// | |
// Go into an infinite loop. | |
// | |
while(1) | |
{ | |
} | |
} | |
//***************************************************************************** | |
// | |
// The processor vector table. | |
// | |
// This contains a list of the handlers for the various interrupt sources in | |
// the system. The layout of this list is defined by the hardware; assertion | |
// of an interrupt causes the processor to start executing directly at the | |
// address given in the corresponding location in this list. | |
// | |
//***************************************************************************** | |
#if defined(__IAR_SYSTEMS_ICC__) | |
#pragma data_alignment=256 | |
static __no_init void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) @ ".vtable_ram"; | |
#elif defined(__TI_COMPILER_VERSION__) || defined(DOXYGEN) | |
#pragma DATA_ALIGN(g_pfnRAMVectors, 256) | |
#pragma DATA_SECTION(g_pfnRAMVectors, ".vtable_ram") | |
void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void); | |
#elif defined (__CC_ARM) | |
static __attribute__((section("vtable_ram"))) | |
void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256))); | |
#else | |
static __attribute__((section("vtable_ram"))) | |
void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) __attribute__((aligned(256))); | |
#endif | |
//***************************************************************************** | |
// | |
//! Registers a function to be called when an interrupt occurs. | |
// | |
//***************************************************************************** | |
void | |
IntRegister(uint32_t ui32Interrupt, void (*pfnHandler)(void)) | |
{ | |
uint32_t ui32Idx, ui32Value; | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Make sure that the RAM vector table is correctly aligned. | |
// | |
ASSERT(((uint32_t)g_pfnRAMVectors & 0x000000ff) == 0); | |
// | |
// See if the RAM vector table has been initialized. | |
// | |
if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors) | |
{ | |
// | |
// Copy the vector table from the beginning of FLASH to the RAM vector | |
// table. | |
// | |
ui32Value = HWREG(NVIC_VTABLE); | |
for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++) | |
{ | |
g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) + | |
ui32Value); | |
} | |
// | |
// Point NVIC at the RAM vector table. | |
// | |
HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors; | |
} | |
// | |
// Save the interrupt handler. | |
// | |
g_pfnRAMVectors[ui32Interrupt] = pfnHandler; | |
} | |
//***************************************************************************** | |
// | |
//! Unregisters the function to be called when an interrupt occurs. | |
// | |
//***************************************************************************** | |
void | |
IntUnregister(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Reset the interrupt handler. | |
// | |
g_pfnRAMVectors[ui32Interrupt] = IntDefaultHandler; | |
} | |
//***************************************************************************** | |
// | |
//! Sets the priority grouping of the interrupt controller. | |
// | |
//***************************************************************************** | |
void | |
IntPriorityGroupingSet(uint32_t ui32Bits) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Bits < NUM_PRIORITY); | |
// | |
// Set the priority grouping. | |
// | |
HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | g_pui32Priority[ui32Bits]; | |
} | |
//***************************************************************************** | |
// | |
//! Gets the priority grouping of the interrupt controller | |
// | |
//***************************************************************************** | |
uint32_t | |
IntPriorityGroupingGet(void) | |
{ | |
uint32_t ui32Loop, ui32Value; | |
// | |
// Read the priority grouping. | |
// | |
ui32Value = HWREG(NVIC_APINT) & NVIC_APINT_PRIGROUP_M; | |
// | |
// Loop through the priority grouping values. | |
// | |
for(ui32Loop = 0; ui32Loop < NUM_PRIORITY; ui32Loop++) | |
{ | |
// | |
// Stop looping if this value matches. | |
// | |
if(ui32Value == g_pui32Priority[ui32Loop]) | |
{ | |
break; | |
} | |
} | |
// | |
// Return the number of priority bits. | |
// | |
return(ui32Loop); | |
} | |
//***************************************************************************** | |
// | |
//! Sets the priority of an interrupt | |
// | |
//***************************************************************************** | |
void | |
IntPrioritySet(uint32_t ui32Interrupt, uint8_t ui8Priority) | |
{ | |
uint32_t ui32Temp; | |
// | |
// Check the arguments. | |
// | |
ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS)); | |
ASSERT(ui8Priority <= INT_PRI_LEVEL7); | |
// | |
// Set the interrupt priority. | |
// | |
ui32Temp = HWREG(g_pui32Regs[ui32Interrupt >> 2]); | |
ui32Temp &= ~(0xFF << (8 * (ui32Interrupt & 3))); | |
ui32Temp |= ui8Priority << (8 * (ui32Interrupt & 3)); | |
HWREG(g_pui32Regs[ui32Interrupt >> 2]) = ui32Temp; | |
} | |
//***************************************************************************** | |
// | |
//! Gets the priority of an interrupt | |
// | |
//***************************************************************************** | |
int32_t | |
IntPriorityGet(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT((ui32Interrupt >= 4) && (ui32Interrupt < NUM_INTERRUPTS)); | |
// | |
// Return the interrupt priority. | |
// | |
return((HWREG(g_pui32Regs[ui32Interrupt >> 2]) >> (8 * (ui32Interrupt & 3))) & | |
0xFF); | |
} | |
//***************************************************************************** | |
// | |
//! Enables an interrupt | |
// | |
//***************************************************************************** | |
void | |
IntEnable(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Determine the interrupt to enable. | |
// | |
if(ui32Interrupt == INT_MEMMANAGE_FAULT) | |
{ | |
// | |
// Enable the MemManage interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_MEM; | |
} | |
else if(ui32Interrupt == INT_BUS_FAULT) | |
{ | |
// | |
// Enable the bus fault interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_BUS; | |
} | |
else if(ui32Interrupt == INT_USAGE_FAULT) | |
{ | |
// | |
// Enable the usage fault interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) |= NVIC_SYS_HND_CTRL_USAGE; | |
} | |
else if(ui32Interrupt == INT_SYSTICK) | |
{ | |
// | |
// Enable the System Tick interrupt. | |
// | |
HWREG(NVIC_ST_CTRL) |= NVIC_ST_CTRL_INTEN; | |
} | |
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47)) | |
{ | |
// | |
// Enable the general interrupt. | |
// | |
HWREG(NVIC_EN0) = 1 << (ui32Interrupt - 16); | |
} | |
else if(ui32Interrupt >= 48) | |
{ | |
// | |
// Enable the general interrupt. | |
// | |
HWREG(NVIC_EN1) = 1 << (ui32Interrupt - 48); | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Disables an interrupt | |
// | |
//***************************************************************************** | |
void | |
IntDisable(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Determine the interrupt to disable. | |
// | |
if(ui32Interrupt == INT_MEMMANAGE_FAULT) | |
{ | |
// | |
// Disable the MemManage interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_MEM); | |
} | |
else if(ui32Interrupt == INT_BUS_FAULT) | |
{ | |
// | |
// Disable the bus fault interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_BUS); | |
} | |
else if(ui32Interrupt == INT_USAGE_FAULT) | |
{ | |
// | |
// Disable the usage fault interrupt. | |
// | |
HWREG(NVIC_SYS_HND_CTRL) &= ~(NVIC_SYS_HND_CTRL_USAGE); | |
} | |
else if(ui32Interrupt == INT_SYSTICK) | |
{ | |
// | |
// Disable the System Tick interrupt. | |
// | |
HWREG(NVIC_ST_CTRL) &= ~(NVIC_ST_CTRL_INTEN); | |
} | |
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47)) | |
{ | |
// | |
// Disable the general interrupt. | |
// | |
HWREG(NVIC_DIS0) = 1 << (ui32Interrupt - 16); | |
} | |
else if(ui32Interrupt >= 48) | |
{ | |
// | |
// Disable the general interrupt. | |
// | |
HWREG(NVIC_DIS1) = 1 << (ui32Interrupt - 48); | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Pends an interrupt | |
// | |
//***************************************************************************** | |
void | |
IntPendSet(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Determine the interrupt to pend. | |
// | |
if(ui32Interrupt == INT_NMI_FAULT) | |
{ | |
// | |
// Pend the NMI interrupt. | |
// | |
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_NMI_SET; | |
} | |
else if(ui32Interrupt == INT_PENDSV) | |
{ | |
// | |
// Pend the PendSV interrupt. | |
// | |
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PEND_SV; | |
} | |
else if(ui32Interrupt == INT_SYSTICK) | |
{ | |
// | |
// Pend the SysTick interrupt. | |
// | |
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET; | |
} | |
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47)) | |
{ | |
// | |
// Pend the general interrupt. | |
// | |
HWREG(NVIC_PEND0) = 1 << (ui32Interrupt - 16); | |
} | |
else if(ui32Interrupt >= 48) | |
{ | |
// | |
// Pend the general interrupt. | |
// | |
HWREG(NVIC_PEND1) = 1 << (ui32Interrupt - 48); | |
} | |
} | |
//***************************************************************************** | |
// | |
//! Query whether an interrupt is pending | |
// | |
//***************************************************************************** | |
bool | |
IntPendGet(uint32_t ui32Interrupt) | |
{ | |
uint32_t ui32IntPending; | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Assume no interrupts are pending. | |
// | |
ui32IntPending = 0; | |
// | |
// The lower 16 IRQ vectors are unsupported by this function | |
// | |
if (ui32Interrupt < 16) | |
{ | |
return 0; | |
} | |
// | |
// Subtract lower 16 irq vectors | |
// | |
ui32Interrupt -= 16; | |
// | |
// Check if the interrupt is pending | |
// | |
ui32IntPending = HWREG(NVIC_PEND0 + (ui32Interrupt / 32)); | |
ui32IntPending &= (1 << (ui32Interrupt & 31)); | |
return ui32IntPending ? true : false; | |
} | |
//***************************************************************************** | |
// | |
//! Unpends an interrupt | |
// | |
//***************************************************************************** | |
void | |
IntPendClear(uint32_t ui32Interrupt) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(ui32Interrupt < NUM_INTERRUPTS); | |
// | |
// Determine the interrupt to unpend. | |
// | |
if(ui32Interrupt == INT_PENDSV) | |
{ | |
// | |
// Unpend the PendSV interrupt. | |
// | |
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_UNPEND_SV; | |
} | |
else if(ui32Interrupt == INT_SYSTICK) | |
{ | |
// | |
// Unpend the SysTick interrupt. | |
// | |
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR; | |
} | |
else if((ui32Interrupt >= 16) && (ui32Interrupt <= 47)) | |
{ | |
// | |
// Unpend the general interrupt. | |
// | |
HWREG(NVIC_UNPEND0) = 1 << (ui32Interrupt - 16); | |
} | |
else if(ui32Interrupt >= 48) | |
{ | |
// | |
// Unpend the general interrupt. | |
// | |
HWREG(NVIC_UNPEND1) = 1 << (ui32Interrupt - 48); | |
} | |
} |