zephyr/include/arch/arm/cortex_m/nvic.h

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_ */