8f26d181c3
Everything works fine without USB being plugged in but faults (I think) when USB is plugged in. This is switched away from the USB code from the bootloader onto the USB code thats generated by Atmel Studio using the high level classes from ASF.
352 lines
12 KiB
C
352 lines
12 KiB
C
/**
|
|
* \file
|
|
*
|
|
* \brief Global interrupt management for 32-bit AVR
|
|
*
|
|
* Copyright (c) 2010-2016 Atmel Corporation. All rights reserved.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* 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. The name of Atmel may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* 4. This software may only be redistributed and used in connection with an
|
|
* Atmel microcontroller product.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
/*
|
|
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
|
*/
|
|
#ifndef UTILS_INTERRUPT_INTERRUPT_H
|
|
#define UTILS_INTERRUPT_INTERRUPT_H
|
|
|
|
#include <compiler.h>
|
|
#include <preprocessor/tpaste.h>
|
|
|
|
/**
|
|
* \weakgroup interrupt_group
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
//! Pointer to interrupt handler.
|
|
#if (defined __GNUC__)
|
|
typedef void (*__int_handler)(void);
|
|
#elif (defined __ICCAVR32__)
|
|
typedef void (__interrupt *__int_handler)(void);
|
|
#endif
|
|
|
|
/**
|
|
* \name Interrupt Service Routine definition and registration
|
|
*
|
|
* @{
|
|
*/
|
|
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
|
|
|
/**
|
|
* \brief Macro to declare an interrupt service routine
|
|
*
|
|
* With GCC, this macro only causes the function to be defined as an interrupt
|
|
* service routine, i.e., it does not add any initialization code. A valid
|
|
* function name is required for use with \ref irq_register_handler.
|
|
*
|
|
* With IAR, this macro defines the function as an interrupt service routine and
|
|
* causes the compiler to add initialization code for the interrupt controller
|
|
* (INTC). The interrupt group and level, as well as a valid function name are
|
|
* therefore required.\n
|
|
* \note If \ref CONFIG_INTERRUPT_FORCE_INTC is defined, only a valid function
|
|
* name is required for use with \ref irq_register_handler. The initialization
|
|
* code will be handled by the interrupt controller itself.
|
|
*
|
|
* Usage:
|
|
* \code
|
|
ISR(foo_irq_handler, AVR32_xxx_IRQ_GROUP, n)
|
|
{
|
|
// Function definition
|
|
...
|
|
}
|
|
\endcode
|
|
*
|
|
* \param func Name for the function, needed by \ref irq_register_handler.
|
|
* \param int_grp Interrupt group to define service routine for.
|
|
* \param int_lvl Priority level to set for the interrupt group, in the range
|
|
* \c 0 to \c 3.
|
|
*
|
|
* \note The interrupt groups can be found in the device header files for the
|
|
* IAR toolchain (avr32/io\<part\>.h).
|
|
*
|
|
* \todo Update to use IRQ numbers when these are made available in the
|
|
* device header files of both IAR and GCC.
|
|
*/
|
|
# define ISR(func, int_grp, int_lvl) \
|
|
__attribute__((__interrupt__)) static void func (void)
|
|
|
|
#elif defined(__ICCAVR32__) && defined(CONFIG_INTERRUPT_FORCE_INTC)
|
|
# define ISR(func, int_grp, int_lvl) \
|
|
__interrupt static void func (void)
|
|
|
|
#elif defined(__ICCAVR32__)
|
|
# define ISR0(...) _Pragma(#__VA_ARGS__)
|
|
# define ISR(func, int_grp, int_lvl) \
|
|
ISR0(handler=int_grp, int_lvl) \
|
|
__interrupt static void func (void)
|
|
#endif
|
|
|
|
#if defined(__GNUC__) || defined(__DOXYGEN__) || defined(CONFIG_INTERRUPT_FORCE_INTC)
|
|
# include <intc.h>
|
|
|
|
/**
|
|
* \brief Initialize interrupt vectors
|
|
*
|
|
* With GCC, this macro adds code for initialization of the interrupt vectors
|
|
* with the driver for the interrupt controller (INTC).
|
|
*
|
|
* With IAR and unless \ref CONFIG_INTERRUPT_FORCE_INTC is defined this macro
|
|
* adds no code, since initialization of the INTC is handled by the compiler.
|
|
* \note Defining \ref CONFIG_INTERRUPT_FORCE_INTC will force the use of the
|
|
* INTC driver, replacing the compiler built-in interrupt handler.
|
|
*
|
|
* This must be called prior to \ref irq_register_handler.
|
|
*/
|
|
# define irq_initialize_vectors() INTC_init_interrupts()
|
|
|
|
/**
|
|
* \brief Register handler for interrupt
|
|
*
|
|
* With GCC, this macro adds code for registering an interrupt handler with the
|
|
* driver for the interrupt controller (INTC).
|
|
*
|
|
* With IAR and unless \ref CONFIG_INTERRUPT_FORCE_INTC is defined this macro
|
|
* adds no code, since initialization of the INTC is handled by the compiler.
|
|
* \note Defining \ref CONFIG_INTERRUPT_FORCE_INTC will force the use of the
|
|
* INTC driver, replacing the compiler built-in interrupt handler.
|
|
*
|
|
* \param func Name of handler function to register for interrupt.
|
|
* \param int_num Number of the interrupt line to register function for.
|
|
* \param int_lvl Priority level to set for the interrupt's group, in the range
|
|
* \c 0 to \c 3.
|
|
*
|
|
* Usage:
|
|
* \code
|
|
irq_initialize_vectors();
|
|
irq_register_handler(foo_irq_handler, AVR32_xxx_IRQ, n);
|
|
\endcode
|
|
*
|
|
* \note The function \a func must be defined with the \ref ISR macro.
|
|
* \note The interrupt line number can be found in the device header files for
|
|
* the GCC toolchain (avr32/\<part\>.h).
|
|
*/
|
|
# define irq_register_handler(func, int_num, int_lvl) \
|
|
INTC_register_interrupt(func, int_num, \
|
|
TPASTE2(AVR32_INTC_INT, int_lvl))
|
|
|
|
#elif defined(__ICCAVR32__)
|
|
# define irq_initialize_vectors() do{ } while(0)
|
|
# define irq_register_handler(func, int_num, int_lvl) do{ } while(0)
|
|
#endif
|
|
|
|
//@}
|
|
|
|
#if (defined __GNUC__)
|
|
# define cpu_irq_enable() \
|
|
do { \
|
|
barrier(); \
|
|
__builtin_csrf(AVR32_SR_GM_OFFSET); \
|
|
} while (0)
|
|
# define cpu_irq_disable() \
|
|
do { \
|
|
__builtin_ssrf(AVR32_SR_GM_OFFSET); \
|
|
barrier(); \
|
|
} while (0)
|
|
#elif (defined __ICCAVR32__)
|
|
# if (defined CONFIG_INTERRUPT_FORCE_INTC)
|
|
# define cpu_irq_enable() \
|
|
do { \
|
|
barrier(); \
|
|
__clear_status_flag(AVR32_SR_GM_OFFSET); \
|
|
} while(0)
|
|
# define cpu_irq_disable() \
|
|
do { \
|
|
__set_status_flag(AVR32_SR_GM_OFFSET); \
|
|
barrier(); \
|
|
} while (0)
|
|
# else
|
|
# define cpu_irq_enable() __enable_interrupt()
|
|
# define cpu_irq_disable() __disable_interrupt()
|
|
# endif
|
|
#endif
|
|
|
|
typedef uint32_t irqflags_t;
|
|
|
|
static inline irqflags_t cpu_irq_save(void)
|
|
{
|
|
volatile irqflags_t flags;
|
|
|
|
flags = sysreg_read(AVR32_SR);
|
|
cpu_irq_disable();
|
|
|
|
return flags;
|
|
}
|
|
|
|
static inline bool cpu_irq_is_enabled_flags(irqflags_t flags)
|
|
{
|
|
return !(flags & AVR32_SR_GM_MASK);
|
|
}
|
|
|
|
static inline void cpu_irq_restore(irqflags_t flags)
|
|
{
|
|
barrier();
|
|
|
|
/* Restore the global IRQ mask status flag if it was previously set */
|
|
if ( cpu_irq_is_enabled_flags(flags) ) {
|
|
cpu_irq_enable();
|
|
}
|
|
|
|
barrier();
|
|
}
|
|
|
|
#define cpu_irq_is_enabled() cpu_irq_is_enabled_flags(sysreg_read(AVR32_SR))
|
|
|
|
//! \name Global interrupt levels
|
|
//@{
|
|
|
|
/**
|
|
* \brief Check if interrupt level is enabled in supplied flags
|
|
*
|
|
* \param flags State of interrupt flags.
|
|
* \param level Bit position for interrupt level.
|
|
*
|
|
* \return True if interrupt level is enabled.
|
|
*/
|
|
static inline bool cpu_irq_level_is_enabled_flags(irqflags_t flags,
|
|
uint32_t level)
|
|
{
|
|
return !(flags & (1 << level));
|
|
}
|
|
|
|
/**
|
|
* \brief Check if interrupt level is enabled
|
|
*
|
|
* \param level Interrupt level (0 to 3).
|
|
*
|
|
* \return True if interrupt level \a level is enabled.
|
|
*
|
|
* \note The interrupt level must be known at compile time.
|
|
*/
|
|
#define cpu_irq_level_is_enabled(level) \
|
|
cpu_irq_level_is_enabled_flags(sysreg_read(AVR32_SR), \
|
|
TPASTE3(AVR32_SR_I, level, M_OFFSET))
|
|
|
|
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
|
/**
|
|
* \brief Enable interrupt level
|
|
*
|
|
* \param level Interrupt level to enable (0 to 3).
|
|
*
|
|
* \note The interrupt level must be known at compile time.
|
|
*/
|
|
# define cpu_irq_enable_level(level) \
|
|
do { \
|
|
barrier(); \
|
|
__builtin_csrf(TPASTE3(AVR32_SR_I, level, M_OFFSET)); \
|
|
} while (0)
|
|
|
|
/**
|
|
* \brief Disable interrupt level
|
|
*
|
|
* \param level Interrupt level to disable (0 to 3).
|
|
*
|
|
* \note The interrupt level must be known at compile time.
|
|
*/
|
|
# define cpu_irq_disable_level(level) \
|
|
do { \
|
|
__builtin_ssrf(TPASTE3(AVR32_SR_I, level, M_OFFSET)); \
|
|
barrier(); \
|
|
} while (0)
|
|
|
|
#elif (defined __ICCAVR32__)
|
|
# define cpu_irq_enable_level(level) \
|
|
do { \
|
|
barrier(); \
|
|
__clear_status_flag(TPASTE3(AVR32_SR_I, level, M_OFFSET)); \
|
|
} while(0)
|
|
# define cpu_irq_disable_level(level) \
|
|
do { \
|
|
__set_status_flag(TPASTE3(AVR32_SR_I, level, M_OFFSET)); \
|
|
barrier(); \
|
|
} while (0)
|
|
#endif
|
|
|
|
//@}
|
|
|
|
//@}
|
|
|
|
/**
|
|
* \weakgroup interrupt_deprecated_group
|
|
* @{
|
|
*/
|
|
|
|
#define Enable_global_interrupt() cpu_irq_enable()
|
|
#define Disable_global_interrupt() cpu_irq_disable()
|
|
#define Is_global_interrupt_enabled() cpu_irq_is_enabled()
|
|
|
|
#define Enable_interrupt_level(level) cpu_irq_enable_level(level)
|
|
#define Disable_interrupt_level(level) cpu_irq_disable_level(level)
|
|
#define Is_interrupt_level_enabled(level) cpu_irq_level_is_enabled(level)
|
|
|
|
/**
|
|
* \name Interrupt protection of code sections
|
|
* \note Use \ref cpu_irq_save and \ref cpu_irq_restore instead of these macros.
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* \brief Start section with code protected against interrupts
|
|
*/
|
|
#define AVR32_ENTER_CRITICAL_REGION() \
|
|
{ \
|
|
bool global_interrupt_enabled = Is_global_interrupt_enabled(); \
|
|
Disable_global_interrupt();
|
|
|
|
/**
|
|
* \brief End section with code protected against interrupts
|
|
*
|
|
* \note This macro must always be used in conjunction with
|
|
* \ref AVR32_ENTER_CRITICAL_REGION so that interrupts are enabled again.
|
|
*/
|
|
#define AVR32_LEAVE_CRITICAL_REGION() \
|
|
if (global_interrupt_enabled) Enable_global_interrupt(); \
|
|
}
|
|
|
|
//@}
|
|
|
|
//@}
|
|
|
|
#endif /* UTILS_INTERRUPT_INTERRUPT_H */
|