225 lines
5.1 KiB
C
225 lines
5.1 KiB
C
/* nvic.c - ARM CORTEX-M Series Nested Vector Interrupt Controller */
|
|
|
|
/*
|
|
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* DESCRIPTION
|
|
* Provide an interface to the Nested Vectored Interrupt Controller found on
|
|
* ARM Cortex-M processors.
|
|
*
|
|
* The API does not account for all possible usages of the NVIC, only the
|
|
* functionalities needed by the kernel.
|
|
*
|
|
* The same effect can be achieved by directly writing in the registers of the
|
|
* NVIC, with the layout available from scs.h, using the __scs.nvic data
|
|
* structure (or hardcoded values), but these APIs are less error-prone,
|
|
* especially for registers with multiple instances to account for potentially
|
|
* 240 interrupt lines. If access to a missing functionality is needed, this is
|
|
* the way to implement it.
|
|
*
|
|
* Supports up to 240 IRQs and 256 priority levels.
|
|
*/
|
|
|
|
#ifndef _NVIC_H_
|
|
#define _NVIC_H_
|
|
|
|
#include <arch/arm/cortex_m/scs.h>
|
|
|
|
/* for assembler, only works with constants */
|
|
#define _EXC_PRIO(pri) (((pri) << (8 - CONFIG_NUM_IRQ_PRIO_BITS)) & 0xff)
|
|
#if defined(CONFIG_ZERO_LATENCY_IRQS)
|
|
#define _EXC_IRQ_DEFAULT_PRIO _EXC_PRIO(0x03)
|
|
#else
|
|
#define _EXC_IRQ_DEFAULT_PRIO _EXC_PRIO(0x02)
|
|
#endif
|
|
|
|
/* no exc #0 */
|
|
#define _EXC_RESET 1
|
|
#define _EXC_NMI 2
|
|
#define _EXC_HARD_FAULT 3
|
|
#define _EXC_MPU_FAULT 4
|
|
#define _EXC_BUS_FAULT 5
|
|
#define _EXC_USAGE_FAULT 6
|
|
/* 7-10 reserved */
|
|
#define _EXC_SVC 11
|
|
#define _EXC_DEBUG 12
|
|
/* 13 reserved */
|
|
#define _EXC_PENDSV 14
|
|
#define _EXC_SYSTICK 15
|
|
/* 16+ IRQs */
|
|
|
|
#define NUM_IRQS_PER_REG 32
|
|
#define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG)
|
|
#define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG)
|
|
|
|
#if !defined(_ASMLANGUAGE)
|
|
|
|
#include <stdint.h>
|
|
#include <misc/__assert.h>
|
|
|
|
/**
|
|
*
|
|
* @brief Enable an IRQ
|
|
*
|
|
* Enable IRQ #@a irq, which is equivalent to exception #@a irq+16
|
|
*
|
|
* @param irq IRQ number
|
|
*
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicIrqEnable(unsigned int irq)
|
|
{
|
|
__scs.nvic.iser[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Find out if an IRQ is enabled
|
|
*
|
|
* Find out if IRQ #@a irq is enabled.
|
|
*
|
|
* @param irq IRQ number
|
|
* @return 1 if IRQ is enabled, 0 otherwise
|
|
*/
|
|
|
|
static inline int _NvicIsIrqEnabled(unsigned int irq)
|
|
{
|
|
return __scs.nvic.iser[REG_FROM_IRQ(irq)] & (1 << BIT_FROM_IRQ(irq));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Disable an IRQ
|
|
*
|
|
* Disable IRQ #@a irq, which is equivalent to exception #@a irq+16
|
|
* @param irq IRQ number
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicIrqDisable(unsigned int irq)
|
|
{
|
|
__scs.nvic.icer[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Pend an IRQ
|
|
*
|
|
* Pend IRQ #@a irq, which is equivalent to exception #@a irq+16. CPU will handle
|
|
* the IRQ when interrupts are enabled and/or returning from a higher priority
|
|
* interrupt.
|
|
* @param irq IRQ number
|
|
*
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicIrqPend(unsigned int irq)
|
|
{
|
|
__scs.nvic.ispr[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Find out if an IRQ is pending
|
|
*
|
|
* Find out if IRQ #@a irq is pending
|
|
*
|
|
* @param irq IRQ number
|
|
* @return 1 if IRQ is pending, 0 otherwise
|
|
*/
|
|
|
|
static inline int _NvicIsIrqPending(unsigned int irq)
|
|
{
|
|
return __scs.nvic.ispr[REG_FROM_IRQ(irq)] & (1 << BIT_FROM_IRQ(irq));
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Unpend an IRQ
|
|
*
|
|
* Unpend IRQ #@a irq, which is equivalent to exception #@a irq+16. The previously
|
|
* pending interrupt will be ignored when either unlocking interrupts or
|
|
* returning from a higher priority exception.
|
|
*
|
|
* @param irq IRQ number
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicIrqUnpend(unsigned int irq)
|
|
{
|
|
__scs.nvic.icpr[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Set priority of an IRQ
|
|
*
|
|
* Set priority of IRQ #@a irq to @a prio. There are 256 priority levels.
|
|
*
|
|
* @param irq IRQ number
|
|
* @param prio Priority
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicIrqPrioSet(unsigned int irq, unsigned int prio)
|
|
{
|
|
__ASSERT(prio < 256, "invalid priority\n");
|
|
__scs.nvic.ipr[irq] = prio;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Get priority of an IRQ
|
|
*
|
|
* Get priority of IRQ #@a irq.
|
|
*
|
|
* @param irq IRQ number
|
|
*
|
|
* @return the priority level of the IRQ
|
|
*/
|
|
|
|
static inline uint32_t _NvicIrqPrioGet(unsigned int irq)
|
|
{
|
|
return __scs.nvic.ipr[irq];
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Trigger an interrupt via software
|
|
*
|
|
* Trigger interrupt #@a irq. The CPU will handle the IRQ when interrupts are
|
|
* enabled and/or returning from a higher priority interrupt.
|
|
*
|
|
* @param irq IRQ number
|
|
* @return N/A
|
|
*/
|
|
|
|
static inline void _NvicSwInterruptTrigger(unsigned int irq)
|
|
{
|
|
#if defined(CONFIG_PLATFORM_TI_LM3S6965_QEMU)
|
|
/* the QEMU does not simulate the STIR register: this is a workaround */
|
|
_NvicIrqPend(irq);
|
|
#else
|
|
__scs.stir = irq;
|
|
#endif
|
|
}
|
|
|
|
#endif /* !_ASMLANGUAGE */
|
|
|
|
#endif /* _NVIC_H_ */
|