529 lines
15 KiB
C
529 lines
15 KiB
C
//###########################################################################
|
|
//
|
|
// FILE: interrupt.c
|
|
//
|
|
// TITLE: Driver for the NVIC Interrupt Controller.
|
|
//
|
|
//###########################################################################
|
|
// $TI Release: F2838x Support Library v3.04.00.00 $
|
|
// $Release Date: Fri Feb 12 19:08:49 IST 2021 $
|
|
// $Copyright:
|
|
// Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions
|
|
// are met:
|
|
//
|
|
// Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 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.
|
|
//
|
|
// Neither the name of Texas Instruments Incorporated 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
|
|
// OWNER 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 "interrupt.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// RAM Vector Table to be used as srcVectorTable in
|
|
// Interrupt_initRAMVectorTable(). Set the size of the vector table to the
|
|
// largest number of interrupts of any device.
|
|
//
|
|
//*****************************************************************************
|
|
#ifndef USE_RTOS
|
|
#pragma DATA_ALIGN(vectorTableRAM, 1024U)
|
|
#pragma DATA_SECTION(vectorTableRAM, ".vtable")
|
|
#pragma WEAK(vectorTableRAM)
|
|
void (*vectorTableRAM[NUM_INTERRUPTS])(void);
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_enable()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_enable(uint32_t interruptNum)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum < NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Enable the interrupt.
|
|
//
|
|
if(interruptNum == FAULT_MPU)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_MEMFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_BUSFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_USGFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SYST_CSR) |= NVIC_SYST_CSR_TICKINT;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ISER0 +
|
|
(NVIC_OFFSET_INC * ((interruptNum - 16U) / 32U))) =
|
|
(uint32_t)1U << ((interruptNum - 16U) & 0x1FU);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_disable()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_disable(uint32_t interruptNum)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum <= NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Disable the interrupt.
|
|
//
|
|
if(interruptNum == FAULT_MPU)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_MEMFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_BUSFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_USGFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SYST_CSR) &= ~NVIC_SYST_CSR_TICKINT;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICER0 +
|
|
(NVIC_OFFSET_INC * ((interruptNum - 16U) / 32U))) =
|
|
(uint32_t)1U << ((interruptNum - 16U) & 0x1FU);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_isEnabled()
|
|
//
|
|
//*****************************************************************************
|
|
bool
|
|
Interrupt_isEnabled(uint32_t interruptNum)
|
|
{
|
|
uint32_t status;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum <= NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Return the interrupt status
|
|
//
|
|
if(interruptNum == FAULT_MPU)
|
|
{
|
|
status = HWREG(NVIC_BASE + NVIC_O_SHCSRS) & NVIC_SHCSRS_MEMFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
status = HWREG(NVIC_BASE + NVIC_O_SHCSRS) & NVIC_SHCSRS_BUSFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
status = HWREG(NVIC_BASE + NVIC_O_SHCSRS) & NVIC_SHCSRS_USGFAULTENA;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
status = HWREG(NVIC_BASE + NVIC_O_SYST_CSR) & NVIC_SYST_CSR_TICKINT;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
status = HWREG(NVIC_BASE + (uint32_t)NVIC_O_ISER0 +
|
|
(NVIC_OFFSET_INC * ((interruptNum - 16U) / 32U))) &
|
|
(1U << ((interruptNum - 16U) & 0x1FU));
|
|
}
|
|
else
|
|
{
|
|
status = 0U;
|
|
}
|
|
|
|
//
|
|
// Return peripheral interrupt status.
|
|
//
|
|
return(status != 0U);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_pend()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_pend(uint32_t interruptNum)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum <= NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Pends the corresponding channel interrupt.
|
|
//
|
|
if(interruptNum == FAULT_NMI)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICSR) |= NVIC_ICSR_NMIPENDSET;
|
|
}
|
|
else if(interruptNum == FAULT_PENDSV)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICSR) |= NVIC_ICSR_PENDSVSET;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICSR) |= NVIC_ICSR_PENDSTSET;
|
|
}
|
|
else if(interruptNum == FAULT_SVCALL)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_SVCALLPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_BUSFAULTPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_MPU)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_MEMFAULTPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) |= NVIC_SHCSRS_USGFAULTPENDED;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ISPR0 +
|
|
(NVIC_OFFSET_INC * ((interruptNum - 16U) / 32U))) =
|
|
(uint32_t)1U << ((interruptNum - 16U) & 0x1FU);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_unpend()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_unpend(uint32_t interruptNum)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum <= NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Unpends the corresponding channel interrupt.
|
|
//
|
|
if(interruptNum == FAULT_PENDSV)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICSR) |= NVIC_ICSR_PENDSVCLR;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICSR) |= NVIC_ICSR_PENDSTCLR;
|
|
}
|
|
else if(interruptNum == FAULT_SVCALL)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_SVCALLPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_BUSFAULTPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_MPU)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_MEMFAULTPENDED;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHCSRS) &= ~NVIC_SHCSRS_USGFAULTPENDED;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_ICPR0 +
|
|
(NVIC_OFFSET_INC * ((interruptNum - 16U) / 32U))) =
|
|
(uint32_t)1U << ((interruptNum - 16U) & (uint32_t)0x1FU);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_setPriority()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_setPriority(uint32_t interruptNum, uint32_t priority)
|
|
{
|
|
uint32_t offset, shift;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT((interruptNum >= 4U) && (interruptNum < NUM_INTERRUPTS));
|
|
|
|
//
|
|
// Set the interrupt priority.
|
|
//
|
|
if(interruptNum == FAULT_MPU)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR1) = (HWREG(NVIC_BASE + NVIC_O_SHPR1) &
|
|
~(uint32_t)NVIC_SHPR1_PRI_4_M) |
|
|
(priority << NVIC_SHPR1_PRI_4_S);
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR1) = (HWREG(NVIC_BASE + NVIC_O_SHPR1) &
|
|
~(uint32_t)NVIC_SHPR1_PRI_5_M) |
|
|
(priority << NVIC_SHPR1_PRI_5_S);
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR1) = (HWREG(NVIC_BASE + NVIC_O_SHPR1) &
|
|
~(uint32_t)NVIC_SHPR1_PRI_6_M) |
|
|
(priority << NVIC_SHPR1_PRI_6_S);
|
|
}
|
|
else if(interruptNum == FAULT_SVCALL)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR2) = (HWREG(NVIC_BASE + NVIC_O_SHPR2) &
|
|
~(uint32_t)NVIC_SHPR2_PRI_11_M) |
|
|
(priority << NVIC_SHPR2_PRI_11_S);
|
|
}
|
|
else if(interruptNum == FAULT_PENDSV)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR3) = (HWREG(NVIC_BASE + NVIC_O_SHPR3) &
|
|
~(uint32_t)NVIC_SHPR3_PRI_14_M) |
|
|
(priority << NVIC_SHPR3_PRI_14_S);
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
HWREG(NVIC_BASE + NVIC_O_SHPR3) = (HWREG(NVIC_BASE + NVIC_O_SHPR3) &
|
|
~(uint32_t)NVIC_SHPR3_PRI_15_M) |
|
|
(priority << NVIC_SHPR3_PRI_15_S);
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
offset = (uint32_t)NVIC_OFFSET_INC * ((interruptNum - 16U) / 4U);
|
|
shift = ((uint32_t)8U * (interruptNum & 0x3U)) + 5U;
|
|
|
|
HWREG(NVIC_BASE + NVIC_O_IPR0 + offset) =
|
|
(HWREG(NVIC_BASE + (uint32_t)NVIC_O_IPR0 + offset) &
|
|
~((uint32_t)NVIC_IPR0_PRI_0_M << shift)) |
|
|
(priority << shift);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_getPriority()
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
Interrupt_getPriority(uint32_t interruptNum)
|
|
{
|
|
uint32_t offset, shift, status;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT((interruptNum >= 4U) && (interruptNum < NUM_INTERRUPTS));
|
|
|
|
//
|
|
// Set the interrupt priority.
|
|
//
|
|
if(interruptNum == FAULT_MPU)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR1) & NVIC_SHPR1_PRI_4_M) >>
|
|
NVIC_SHPR1_PRI_4_S;
|
|
}
|
|
else if(interruptNum == FAULT_BUS)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR1) & NVIC_SHPR1_PRI_5_M) >>
|
|
NVIC_SHPR1_PRI_5_S;
|
|
}
|
|
else if(interruptNum == FAULT_USAGE)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR1) & NVIC_SHPR1_PRI_6_M) >>
|
|
NVIC_SHPR1_PRI_6_S;
|
|
}
|
|
else if(interruptNum == FAULT_SVCALL)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR2) & NVIC_SHPR2_PRI_11_M) >>
|
|
NVIC_SHPR2_PRI_11_S;
|
|
}
|
|
else if(interruptNum == FAULT_PENDSV)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR3) & NVIC_SHPR3_PRI_14_M) >>
|
|
NVIC_SHPR3_PRI_14_S;
|
|
}
|
|
else if(interruptNum == FAULT_SYSTICK)
|
|
{
|
|
status = (HWREG(NVIC_BASE + NVIC_O_SHPR3) & NVIC_SHPR3_PRI_15_M) >>
|
|
NVIC_SHPR3_PRI_15_S;
|
|
}
|
|
else if(interruptNum >= 16U)
|
|
{
|
|
offset = (uint32_t)NVIC_OFFSET_INC * ((interruptNum - 16U) / 4U);
|
|
shift = ((uint32_t)8U * (interruptNum & 0x3U)) + 5U;
|
|
|
|
status = (HWREG(NVIC_BASE + (uint32_t)NVIC_O_IPR0 + offset) >> shift) &
|
|
0xFFU;
|
|
}
|
|
else
|
|
{
|
|
status = 0U;
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_initRAMVectorTable()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_initRAMVectorTable(void (*srcVectorTable[])(void),
|
|
void (*dstVectorTable[])(void))
|
|
{
|
|
uint32_t index;
|
|
|
|
//
|
|
// Check whether dstVectorTable lies in RAM and is correctly aligned.
|
|
//
|
|
ASSERT((uint32_t)dstVectorTable >= 0x20000000U);
|
|
ASSERT(((uint32_t)dstVectorTable & 0x000003FFU) == 0U);
|
|
|
|
if(HWREG(NVIC_BASE + NVIC_O_VTOR) != (uint32_t)dstVectorTable)
|
|
{
|
|
//
|
|
// Point the NVIC at the RAM vector table.
|
|
//
|
|
HWREG(NVIC_BASE + NVIC_O_VTOR) = (uint32_t)dstVectorTable;
|
|
}
|
|
|
|
//
|
|
// Copy the ISRs from temp vector table to RAM vector table.
|
|
//
|
|
for(index = 0U; index < NUM_INTERRUPTS; index++)
|
|
{
|
|
dstVectorTable[index] = srcVectorTable[index];
|
|
}
|
|
}
|
|
//*****************************************************************************
|
|
//
|
|
// Interrupt_registerHandler()
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
Interrupt_registerHandler(uint32_t interruptNum, void (*intHandler)(void))
|
|
{
|
|
uint32_t index, value;
|
|
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(interruptNum < NUM_INTERRUPTS);
|
|
|
|
//
|
|
// Make sure that the RAM vector table is correctly aligned.
|
|
// Check vector table alignment in device datasheet.
|
|
//
|
|
ASSERT(((uint32_t)vectorTableRAM & 0x000003FFU) == 0U);
|
|
|
|
//
|
|
// See if the RAM vector table has been initialized.
|
|
//
|
|
if(HWREG(NVIC_BASE + NVIC_O_VTOR) != (uint32_t)vectorTableRAM)
|
|
{
|
|
//
|
|
// Copy the vector table from the beginning of FLASH to the RAM vector
|
|
// table.
|
|
//
|
|
value = HWREG(NVIC_BASE + NVIC_O_VTOR);
|
|
for(index = 0U; index < NUM_INTERRUPTS; index++)
|
|
{
|
|
vectorTableRAM[index] = (void (*)(void))HWREG((index * 4U) + value);
|
|
}
|
|
|
|
//
|
|
// Point the NVIC at the RAM vector table.
|
|
//
|
|
HWREG(NVIC_BASE + NVIC_O_VTOR) = (uint32_t)vectorTableRAM;
|
|
}
|
|
|
|
//
|
|
// Save the interrupt handler.
|
|
//
|
|
vectorTableRAM[interruptNum] = intHandler;
|
|
}
|