424 lines
11 KiB
C
424 lines
11 KiB
C
|
//###########################################################################
|
||
|
//
|
||
|
// FILE: interrupt.c
|
||
|
//
|
||
|
// TITLE: C28x Interrupt (PIE) driver.
|
||
|
//
|
||
|
//###########################################################################
|
||
|
// $Copyright:
|
||
|
// Copyright (C) 2022 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"
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! \internal
|
||
|
//! Clears the IFR flag in the CPU.
|
||
|
//!
|
||
|
//! \param group specifies the interrupt group to be cleared.
|
||
|
//!
|
||
|
//! This function clears the IFR flag. This switch is needed because the
|
||
|
//! clearing of the IFR can only be done with a constant.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
static void Interrupt_clearIFR(uint16_t group)
|
||
|
{
|
||
|
switch(group)
|
||
|
{
|
||
|
case 0x0001U:
|
||
|
IFR &= ~(uint16_t)0x0001U;
|
||
|
break;
|
||
|
case 0x0002U:
|
||
|
IFR &= ~(uint16_t)0x0002U;
|
||
|
break;
|
||
|
case 0x0004U:
|
||
|
IFR &= ~(uint16_t)0x0004U;
|
||
|
break;
|
||
|
case 0x0008U:
|
||
|
IFR &= ~(uint16_t)0x0008U;
|
||
|
break;
|
||
|
case 0x0010U:
|
||
|
IFR &= ~(uint16_t)0x0010U;
|
||
|
break;
|
||
|
case 0x0020U:
|
||
|
IFR &= ~(uint16_t)0x0020U;
|
||
|
break;
|
||
|
case 0x0040U:
|
||
|
IFR &= ~(uint16_t)0x0040U;
|
||
|
break;
|
||
|
case 0x0080U:
|
||
|
IFR &= ~(uint16_t)0x0080U;
|
||
|
break;
|
||
|
case 0x0100U:
|
||
|
IFR &= ~(uint16_t)0x0100U;
|
||
|
break;
|
||
|
case 0x0200U:
|
||
|
IFR &= ~(uint16_t)0x0200U;
|
||
|
break;
|
||
|
case 0x0400U:
|
||
|
IFR &= ~(uint16_t)0x0400U;
|
||
|
break;
|
||
|
case 0x0800U:
|
||
|
IFR &= ~(uint16_t)0x0800U;
|
||
|
break;
|
||
|
case 0x1000U:
|
||
|
IFR &= ~(uint16_t)0x1000U;
|
||
|
break;
|
||
|
case 0x2000U:
|
||
|
IFR &= ~(uint16_t)0x2000U;
|
||
|
break;
|
||
|
case 0x4000U:
|
||
|
IFR &= ~(uint16_t)0x4000U;
|
||
|
break;
|
||
|
case 0x8000U:
|
||
|
IFR &= ~(uint16_t)0x8000U;
|
||
|
break;
|
||
|
default:
|
||
|
//
|
||
|
// Invalid group mask.
|
||
|
//
|
||
|
ASSERT((bool)false);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Interrupt_initModule
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
void
|
||
|
Interrupt_initModule(void)
|
||
|
{
|
||
|
//
|
||
|
// Disable and clear all interrupts at the CPU
|
||
|
//
|
||
|
(void)Interrupt_disableGlobal();
|
||
|
IER = 0x0000U;
|
||
|
IFR = 0x0000U;
|
||
|
|
||
|
//
|
||
|
// Clear all PIEIER registers
|
||
|
//
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER1) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER2) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER3) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER4) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER5) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER6) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER7) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER8) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER9) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER10) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER11) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IER12) = 0U;
|
||
|
|
||
|
//
|
||
|
// Clear all PIEIFR registers
|
||
|
//
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR1) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR2) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR3) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR4) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR5) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR6) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR7) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR8) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR9) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR10) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR11) = 0U;
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_IFR12) = 0U;
|
||
|
|
||
|
//
|
||
|
// Enable vector fetching from PIE block
|
||
|
//
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_CTRL) |= PIE_CTRL_ENPIE;
|
||
|
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! The default interrupt handler.
|
||
|
//!
|
||
|
//! \return None.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
__interrupt void Interrupt_defaultHandler(void)
|
||
|
{
|
||
|
uint16_t pieVect;
|
||
|
uint16_t vectID;
|
||
|
|
||
|
//
|
||
|
// Calculate the vector ID. If the vector is in the lower PIE, it's the
|
||
|
// offset of the vector that was fetched (bits 7:1 of PIECTRL.PIEVECT)
|
||
|
// divided by two.
|
||
|
//
|
||
|
pieVect = HWREGH(PIECTRL_BASE + PIE_O_CTRL);
|
||
|
vectID = (pieVect & 0xFEU) >> 1U;
|
||
|
|
||
|
//
|
||
|
// If the vector is in the upper PIE, the vector ID is 128 or higher.
|
||
|
//
|
||
|
if(pieVect >= 0x0E00U)
|
||
|
{
|
||
|
vectID += 128U;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Something has gone wrong. An interrupt without a proper registered
|
||
|
// handler function has occurred. To help you debug the issue, local
|
||
|
// variable vectID contains the vector ID of the interrupt that occurred.
|
||
|
//
|
||
|
ESTOP0;
|
||
|
for(;;)
|
||
|
{
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! The default illegal instruction trap interrupt handler.
|
||
|
//!
|
||
|
//! \return None.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
__interrupt void Interrupt_illegalOperationHandler(void)
|
||
|
{
|
||
|
//
|
||
|
// Something has gone wrong. The CPU has tried to execute an illegal
|
||
|
// instruction, generating an illegal instruction trap (ITRAP).
|
||
|
//
|
||
|
ESTOP0;
|
||
|
for(;;)
|
||
|
{
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//! The default non-maskable interrupt handler.
|
||
|
//!
|
||
|
//! \return None.
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
__interrupt void Interrupt_nmiHandler(void)
|
||
|
{
|
||
|
//
|
||
|
// A non-maskable interrupt has occurred, indicating that a hardware error
|
||
|
// has occurred in the system. You can use SysCtl_getNMIFlagStatus() to
|
||
|
// to read the NMIFLG register and determine what caused the NMI.
|
||
|
//
|
||
|
ESTOP0;
|
||
|
for(;;)
|
||
|
{
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Interrupt_initVectorTable
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
void
|
||
|
Interrupt_initVectorTable(void)
|
||
|
{
|
||
|
uint16_t i;
|
||
|
|
||
|
EALLOW;
|
||
|
|
||
|
//
|
||
|
// We skip the first three locations because they are initialized by Boot
|
||
|
// ROM with boot variables.
|
||
|
//
|
||
|
for(i = 3U; i < 224U; i++)
|
||
|
{
|
||
|
HWREG(PIEVECTTABLE_BASE + (2U * i)) =
|
||
|
(uint32_t)Interrupt_defaultHandler;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NMI and ITRAP get their own handlers.
|
||
|
//
|
||
|
HWREG(PIEVECTTABLE_BASE + ((INT_NMI >> 16U) * 2U)) =
|
||
|
(uint32_t)Interrupt_nmiHandler;
|
||
|
HWREG(PIEVECTTABLE_BASE + ((INT_ILLEGAL >> 16U) * 2U)) =
|
||
|
(uint32_t)Interrupt_illegalOperationHandler;
|
||
|
|
||
|
EDIS;
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
//Interrupt_enable
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
void
|
||
|
Interrupt_enable(uint32_t interruptNumber)
|
||
|
{
|
||
|
bool intsDisabled;
|
||
|
uint16_t intGroup;
|
||
|
uint16_t groupMask;
|
||
|
uint16_t vectID;
|
||
|
|
||
|
vectID = (uint16_t)(interruptNumber >> 16U);
|
||
|
|
||
|
//
|
||
|
// Globally disable interrupts but save status
|
||
|
//
|
||
|
intsDisabled = Interrupt_disableGlobal();
|
||
|
|
||
|
//
|
||
|
// PIE Interrupts
|
||
|
//
|
||
|
if(vectID >= 0x20U)
|
||
|
{
|
||
|
intGroup = (uint16_t)(((interruptNumber & 0xFF00UL) >> 8U) - 1U);
|
||
|
groupMask = (uint16_t)1U << intGroup;
|
||
|
|
||
|
HWREGH((PIECTRL_BASE + PIE_O_IER1 + (intGroup * 2U))) |=
|
||
|
(uint16_t)1U << ((interruptNumber & 0xFFU) - 1U);
|
||
|
|
||
|
//
|
||
|
// Enable PIE Group Interrupt
|
||
|
//
|
||
|
IER |= groupMask;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// INT13, INT14, DLOGINT, & RTOSINT
|
||
|
//
|
||
|
else if((vectID >= 0x0DU) && (vectID <= 0x10U))
|
||
|
{
|
||
|
IER |= (uint16_t)1U << (vectID - 1U);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Other interrupts
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Re-enable interrupts if they were enabled
|
||
|
//
|
||
|
if(!intsDisabled)
|
||
|
{
|
||
|
(void)Interrupt_enableGlobal();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//*****************************************************************************
|
||
|
//
|
||
|
// Interrupt_disable
|
||
|
//
|
||
|
//*****************************************************************************
|
||
|
void
|
||
|
Interrupt_disable(uint32_t interruptNumber)
|
||
|
{
|
||
|
bool intsDisabled;
|
||
|
uint16_t intGroup;
|
||
|
uint16_t groupMask;
|
||
|
uint16_t vectID;
|
||
|
|
||
|
vectID = (uint16_t)(interruptNumber >> 16U);
|
||
|
|
||
|
intsDisabled = Interrupt_disableGlobal();
|
||
|
|
||
|
//
|
||
|
// PIE Interrupts
|
||
|
//
|
||
|
if(vectID >= 0x20U)
|
||
|
{
|
||
|
intGroup = (uint16_t)(((interruptNumber & 0xFF00UL) >> 8U) - 1U);
|
||
|
groupMask = (uint16_t)1U << intGroup;
|
||
|
|
||
|
//
|
||
|
// Disable individual PIE interrupt
|
||
|
//
|
||
|
HWREGH((PIECTRL_BASE + PIE_O_IER1 + (intGroup * 2U))) &=
|
||
|
~(1U << ((interruptNumber & 0xFFUL) - 1U));
|
||
|
|
||
|
//
|
||
|
// Wait for any pending interrupts to get to the CPU
|
||
|
//
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
|
||
|
Interrupt_clearIFR(groupMask);
|
||
|
|
||
|
//
|
||
|
// Acknowledge any interrupts
|
||
|
//
|
||
|
HWREGH(PIECTRL_BASE + PIE_O_ACK) = groupMask;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// INT13, INT14, DLOGINT, & RTOSINT
|
||
|
//
|
||
|
else if((vectID >= 0x0DU) && (vectID <= 0x10U))
|
||
|
{
|
||
|
IER &= ~((uint16_t)1U << (vectID - 1U));
|
||
|
|
||
|
//
|
||
|
// Wait for any pending interrupts to get to the CPU
|
||
|
//
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
NOP;
|
||
|
|
||
|
Interrupt_clearIFR((uint16_t)1U << (vectID - 1U));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Other interrupts
|
||
|
//
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Re-enable interrupts if they were enabled
|
||
|
//
|
||
|
if(!intsDisabled)
|
||
|
{
|
||
|
(void)Interrupt_enableGlobal();
|
||
|
}
|
||
|
}
|