Labrador/AVR_Code/USB_BULK_TEST/src/ASF/xmega/drivers/pmic/pmic.h

353 lines
10 KiB
C

/**
* \file
*
* \brief Programmable Multilevel Interrupt Controller driver
*
* Copyright (c) 2010-2015 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 PMIC_H
#define PMIC_H
#include <compiler.h>
#include <ccp.h>
/**
* \defgroup pmic_group Programmable Multilevel Interrupt Controller
*
* See \ref xmega_pmic_quickstart.
*
* This is a low-level driver implementation for the AVR XMEGA Programmable
* Multilevel Interrupt Controller.
*
* \note If these functions are used in interrupt service routines (ISRs), any
* non-ISR code or ISR code for lower level interrupts must ensure that the
* operations are atomic, i.e., by disabling interrupts during the function
* calls.
* @{
*/
/**
* \brief Interrupt level bitmasks
*
* \note These may be OR'ed, e.g., if multiple levels are to be enabled or
* disabled.
*/
enum pmic_level {
PMIC_LVL_LOW = PMIC_LOLVLEN_bm, //!< Low-level interrupts
PMIC_LVL_MEDIUM = PMIC_MEDLVLEN_bm, //!< Medium-level interrupts
PMIC_LVL_HIGH = PMIC_HILVLEN_bm, //!< High-level interrupts
/**
* \brief Non-maskable interrupts
* \note These cannot be enabled nor disabled.
*/
PMIC_LVL_NMI = PMIC_NMIEX_bp,
};
//! Interrupt vector locations
enum pmic_vector {
PMIC_VEC_APPLICATION, //!< Application section
PMIC_VEC_BOOT, //!< Boot section
PMIC_NR_OF_VECTORS, //!< Number of interrupt vector locations
};
//! Interrupt scheduling schemes
enum pmic_schedule {
PMIC_SCH_FIXED_PRIORITY, //!< Default, fixed priority scheduling
PMIC_SCH_ROUND_ROBIN, //!< Round-robin scheduling
PMIC_NR_OF_SCHEDULES, //!< Number of interrupt scheduling schemes
};
/**
* \brief Initialize the PMIC
*
* Enables all interrupt levels, with vectors located in the application section
* and fixed priority scheduling.
*/
static inline void pmic_init(void)
{
PMIC.CTRL = PMIC_LVL_LOW | PMIC_LVL_MEDIUM |
PMIC_LVL_HIGH;
}
/**
* \brief Enable interrupts with specified \a level(s).
*
* \param level Interrupt level(s) to enable.
*/
static inline void pmic_enable_level(enum pmic_level level)
{
Assert((level & PMIC_LVL_NMI));
PMIC.CTRL |= level;
}
/**
* \brief Disable interrupts with specified \a level(s).
*
* \param level Interrupt level(s) to disable.
*/
static inline void pmic_disable_level(enum pmic_level level)
{
Assert((level & PMIC_LVL_NMI));
PMIC.CTRL &= ~level;
}
/**
* \brief Check if specified interrupt \a level(s) is enabled.
*
* \param level Interrupt level(s) to check.
*
* \return True if interrupt level(s) is enabled.
*/
static inline bool pmic_level_is_enabled(enum pmic_level level)
{
Assert((level & PMIC_LVL_NMI));
return PMIC.CTRL & level;
}
/**
* \brief Get currently enabled level(s)
*
* \return Bitmask with currently enabled levels.
*/
static inline enum pmic_level pmic_get_enabled_levels(void)
{
return (enum pmic_level)(PMIC.CTRL & (PMIC_LVL_LOW | PMIC_LVL_MEDIUM
| PMIC_LVL_HIGH));
}
/**
* \brief Check if an interrupt level(s) is currently executing.
*
* \param level Interrupt level(s) to check.
*
* \return True if interrupt level(s) is currently executing.
*/
static inline bool pmic_level_is_executing(enum pmic_level level)
{
return PMIC.STATUS & level;
}
/**
* \brief Set interrupt scheduling for low-level interrupts.
*
* \param schedule Interrupt scheduling method to set.
*
* \note The low-priority vector, INTPRI, must be set to 0 when round-robin
* scheduling is disabled to return to default interrupt priority order.
*/
static inline void pmic_set_scheduling(enum pmic_schedule schedule)
{
Assert(schedule < PMIC_NR_OF_SCHEDULES);
switch (schedule) {
case PMIC_SCH_FIXED_PRIORITY:
PMIC.CTRL &= ~PMIC_RREN_bm;
PMIC.INTPRI = 0;
break;
case PMIC_SCH_ROUND_ROBIN:
PMIC.CTRL |= PMIC_RREN_bm;
break;
default:
break;
};
}
/**
* \brief Set location of interrupt vectors.
*
* \param vector Location to use for interrupt vectors.
*/
static inline void pmic_set_vector_location(enum pmic_vector vector)
{
uint8_t ctrl = PMIC.CTRL;
Assert(vector < PMIC_NR_OF_VECTORS);
switch (vector) {
case PMIC_VEC_APPLICATION:
ctrl &= ~PMIC_IVSEL_bm;
break;
case PMIC_VEC_BOOT:
ctrl |= PMIC_IVSEL_bm;
break;
default:
break;
}
ccp_write_io((uint8_t*)&PMIC.CTRL, ctrl);
}
//! @}
/**
* \page xmega_pmic_quickstart Quick start guide for PMIC driver
*
* This is the quick start guide for the \ref pmic_group "PMIC driver" and
* the closely related \ref interrupt_group "global interrupt driver", with
* step-by-step instructions on how to configure and use the drivers in a
* selection of use cases.
*
* The use cases contain several code fragments. The code fragments in the
* steps for setup can be copied into a custom initialization function, while
* the steps for usage can be copied into, e.g., the main application function.
*
* \section pmic_basic_use_case Basic use case
* In this basic use case, the PMIC is configured for:
* - all interrupt levels enabled
* - round-robin scheduling
*
* This will allow for interrupts from other modules being used.
*
* \section pmic_basic_use_case_setup Setup steps
*
* \subsection pmic_basic_use_case_setup_prereq Prerequisites
* For the setup code of this use case to work, the following must
* be added to the project:
* -# Interrupts for the module requiring the PMIC module have to be
* enabled.
* -# An Interrupt Service Routine (ISR) for a given interrupt vector has to be
* defined, where the interrupt vectors available are defined by toolchain and
* listed in the subsection 'Interrupt Vector Summary' in the data sheet.
* \code
ISR(interrupt_vector){
//Interrupt Service Routine
}
\endcode
*
* \subsection pmic_basic_use_case_setup_code Example code
* Add to the initialization code:
* \code
pmic_init();
pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN);
cpu_irq_enable();
\endcode
*
* \subsection pmic_basic_use_case_setup_flow Workflow
* -# call the PMIC driver's own init function to enable all interrupt levels:
* - \code pmic_init(); \endcode
* -# enable round-robin instead of fixed priority interrupt scheduling:
* - \code pmic_set_scheduling(PMIC_SCH_ROUND_ROBIN); \endcode
* -# enable interrupts globally:
* - \code cpu_irq_enable(); \endcode
* - \attention Interrupts will not trigger without this step.
*
* \section pmic_use_cases Advanced use cases
* For more advanced use of the PMIC driver, see the following use cases:
* - \subpage pmic_use_case_1 : atomic operations
*/
/**
* \page pmic_use_case_1 Use case #1
*
* In this use case, the PMIC is configured for:
* - all interrupt levels enabled
*
* This will allow for interrupts from other modules being used.
*
* This use case shows how to make an operation which consists of multiple
* instructions uninterruptible, i.e., into an atomic operation. This is often
* necessary if there is a risk that data can be accessed by interrupt handlers
* while other code is accessing it, and at least one of them modifies it.
*
* \section pmic_use_case_1_setup Setup steps
*
* \subsection pmic_basic_use_case_setup_prereq Prerequisites
* For the setup code of this use case to work, the following must
* be added to the project:
* -# Interrupts for the module requiring the PMIC module have to be
* enabled.
* -# An Interrupt Service Routine (ISR) for a given interrupt vector has to be
* defined, where the interrupt vectors available are defined by toolchain and
* listed in the subsection 'Interrupt Vector Summary' in the data sheet.
* \code
ISR(interrupt_vector){
//Interrupt Service Routine
}
\endcode
*
* \subsection pmic_use_case_1_setup_code Example code
* Add to application initialization:
* \code
pmic_init();
cpu_irq_enable();
\endcode
*
* \subsection pmic_use_case_1_setup_flow Workflow
* -# call the PMIC driver's own init function to enable all interrupt levels:
* - \code pmic_init(); \endcode
* -# set global interrupt enable flag:
* - \code cpu_irq_enable(); \endcode
*
* \section pmic_use_case_1_usage Usage steps
*
* \subsection pmic_use_case_1_usage_code Example code
* \code
Add to application:
void atomic_operation(void)
{
irqflags_t flags;
flags = cpu_irq_save();
// Uninterruptible block of code
cpu_irq_restore(flags);
}
\endcode
*
* \subsection pmic_use_case_1_usage_flow Workflow
* -# allocate temporary storage for interrupt enable:
* - \code irqflags_t flags; \endcode
* -# clear global interrupt enable flag while saving its previous state:
* - \code flags = cpu_irq_save(); \endcode
* -# restore the previous state of global interrupt flag after operation:
* - \code cpu_irq_restore(flags); \endcode
*/
#endif /* PMIC_H */