MCUXpresso_LPC55S69/devices/LPC55S69/drivers/fsl_common_arm.h

899 lines
33 KiB
C

/*
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
* Copyright 2016-2022 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef FSL_COMMON_ARM_H_
#define FSL_COMMON_ARM_H_
/*
* For CMSIS pack RTE.
* CMSIS pack RTE generates "RTC_Components.h" which contains the statements
* of the related <RTE_Components_h> element for all selected software components.
*/
#ifdef _RTE_
#include "RTE_Components.h"
#endif
/*!
* @addtogroup ksdk_common
* @{
*/
/*! @name Atomic modification
*
* These macros are used for atomic access, such as read-modify-write
* to the peripheral registers.
*
* Take @ref SDK_ATOMIC_LOCAL_CLEAR_AND_SET as an example: the parameter @c addr
* means the address of the peripheral register or variable you want to modify
* atomically, the parameter @c clearBits is the bits to clear, the parameter
* @c setBits it the bits to set.
* For example, to set a 32-bit register bit1:bit0 to 0b10, use like this:
*
* @code
volatile uint32_t * reg = (volatile uint32_t *)REG_ADDR;
SDK_ATOMIC_LOCAL_CLEAR_AND_SET(reg, 0x03, 0x02);
@endcode
*
* In this example, the register bit1:bit0 are cleared and bit1 is set, as a result,
* register bit1:bit0 = 0b10.
*
* @note For the platforms don't support exclusive load and store, these macros
* disable the global interrupt to pretect the modification.
*
* @note These macros only guarantee the local processor atomic operations. For
* the multi-processor devices, use hardware semaphore such as SEMA42 to
* guarantee exclusive access if necessary.
*
* @{
*/
/*!
* @def SDK_ATOMIC_LOCAL_ADD(addr, val)
* Add value \a val from the variable at address \a address.
*
* @def SDK_ATOMIC_LOCAL_SUB(addr, val)
* Subtract value \a val to the variable at address \a address.
*
* @def SDK_ATOMIC_LOCAL_SET(addr, bits)
* Set the bits specifiled by \a bits to the variable at address \a address.
*
* @def SDK_ATOMIC_LOCAL_CLEAR(addr, bits)
* Clear the bits specifiled by \a bits to the variable at address \a address.
*
* @def SDK_ATOMIC_LOCAL_TOGGLE(addr, bits)
* Toggle the bits specifiled by \a bits to the variable at address \a address.
*
* @def SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits)
* For the variable at address \a address, clear the bits specifiled by \a clearBits
* and set the bits specifiled by \a setBits.
*/
/* clang-format off */
#if ((defined(__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \
(defined(__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \
(defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ == 1)) || \
(defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ == 1)))
/* clang-format on */
/* If the LDREX and STREX are supported, use them. */
#define _SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXB(addr); \
(ops); \
} while (0UL != __STREXB((val), (addr)))
#define _SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXH(addr); \
(ops); \
} while (0UL != __STREXH((val), (addr)))
#define _SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, val, ops) \
do \
{ \
(val) = __LDREXW(addr); \
(ops); \
} while (0UL != __STREXW((val), (addr)))
static inline void _SDK_AtomicLocalAdd1Byte(volatile uint8_t *addr, uint8_t val)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalAdd2Byte(volatile uint16_t *addr, uint16_t val)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalAdd4Byte(volatile uint32_t *addr, uint32_t val)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val += val);
}
static inline void _SDK_AtomicLocalSub1Byte(volatile uint8_t *addr, uint8_t val)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSub2Byte(volatile uint16_t *addr, uint16_t val)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSub4Byte(volatile uint32_t *addr, uint32_t val)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val -= val);
}
static inline void _SDK_AtomicLocalSet1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalSet2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalSet4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val |= bits);
}
static inline void _SDK_AtomicLocalClear1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalClear2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalClear4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val &= ~bits);
}
static inline void _SDK_AtomicLocalToggle1Byte(volatile uint8_t *addr, uint8_t bits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalToggle2Byte(volatile uint16_t *addr, uint16_t bits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalToggle4Byte(volatile uint32_t *addr, uint32_t bits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val ^= bits);
}
static inline void _SDK_AtomicLocalClearAndSet1Byte(volatile uint8_t *addr, uint8_t clearBits, uint8_t setBits)
{
uint8_t s_val;
_SDK_ATOMIC_LOCAL_OPS_1BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
static inline void _SDK_AtomicLocalClearAndSet2Byte(volatile uint16_t *addr, uint16_t clearBits, uint16_t setBits)
{
uint16_t s_val;
_SDK_ATOMIC_LOCAL_OPS_2BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
static inline void _SDK_AtomicLocalClearAndSet4Byte(volatile uint32_t *addr, uint32_t clearBits, uint32_t setBits)
{
uint32_t s_val;
_SDK_ATOMIC_LOCAL_OPS_4BYTE(addr, s_val, s_val = (s_val & ~clearBits) | setBits);
}
#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalAdd1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(val)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalAdd2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(val)) : \
_SDK_AtomicLocalAdd4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(val))))
#define SDK_ATOMIC_LOCAL_SUB(addr, val) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalSub1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(val)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalSub2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(val)) : \
_SDK_AtomicLocalSub4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(val))))
#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalSet1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
((2UL == sizeof(*(addr))) ? _SDK_AtomicLocalSet2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
_SDK_AtomicLocalSet4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalClear1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
((2UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalClear2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
_SDK_AtomicLocalClear4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalToggle1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(bits)) : \
((2UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalToggle2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(bits)) : \
_SDK_AtomicLocalToggle4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(bits))))
#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
((1UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalClearAndSet1Byte((volatile uint8_t *)(volatile void *)(addr), (uint8_t)(clearBits), (uint8_t)(setBits)) : \
((2UL == sizeof(*(addr))) ? \
_SDK_AtomicLocalClearAndSet2Byte((volatile uint16_t *)(volatile void *)(addr), (uint16_t)(clearBits), (uint16_t)(setBits)) : \
_SDK_AtomicLocalClearAndSet4Byte((volatile uint32_t *)(volatile void *)(addr), (uint32_t)(clearBits), (uint32_t)(setBits))))
#else
#define SDK_ATOMIC_LOCAL_ADD(addr, val) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) += (val); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#define SDK_ATOMIC_LOCAL_SUB(addr, val) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) -= (val); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#define SDK_ATOMIC_LOCAL_SET(addr, bits) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) |= (bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#define SDK_ATOMIC_LOCAL_CLEAR(addr, bits) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) &= ~(bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#define SDK_ATOMIC_LOCAL_TOGGLE(addr, bits) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) ^= (bits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#define SDK_ATOMIC_LOCAL_CLEAR_AND_SET(addr, clearBits, setBits) \
do \
{ \
uint32_t s_atomicOldInt; \
s_atomicOldInt = DisableGlobalIRQ(); \
*(addr) = (*(addr) & ~(clearBits)) | (setBits); \
EnableGlobalIRQ(s_atomicOldInt); \
} while (false)
#endif
/*! @} */
/*! @name Timer utilities */
/*! @{ */
/*! Macro to convert a microsecond period to raw count value */
#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)(((uint64_t)(us) * (clockFreqInHz)) / 1000000U)
/*! Macro to convert a raw count value to microsecond */
#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count)*1000000U / (clockFreqInHz))
/*! Macro to convert a millisecond period to raw count value */
#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)(ms) * (clockFreqInHz) / 1000U)
/*! Macro to convert a raw count value to millisecond */
#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)(count)*1000U / (clockFreqInHz))
/*! @} */
/*! @name ISR exit barrier
* @{
*
* ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
* exception return operation might vector to incorrect interrupt.
* For Cortex-M7, if core speed much faster than peripheral register write speed,
* the peripheral interrupt flags may be still set after exiting ISR, this results to
* the same error similar with errata 83869.
*/
#if (defined __CORTEX_M) && ((__CORTEX_M == 4U) || (__CORTEX_M == 7U))
#define SDK_ISR_EXIT_BARRIER __DSB()
#else
#define SDK_ISR_EXIT_BARRIER
#endif
/*! @} */
/*! @name Alignment variable definition macros */
/*! @{ */
#if (defined(__ICCARM__))
/*
* Workaround to disable MISRA C message suppress warnings for IAR compiler.
* http:/ /supp.iar.com/Support/?note=24725
*/
_Pragma("diag_suppress=Pm120")
#define SDK_PRAGMA(x) _Pragma(#x)
_Pragma("diag_error=Pm120")
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) __attribute__((aligned(alignbytes))) var
#elif defined(__GNUC__) || defined(DOXYGEN_OUTPUT)
/*! Macro to define a variable with alignbytes alignment */
#define SDK_ALIGN(var, alignbytes) var __attribute__((aligned(alignbytes)))
#else
#error Toolchain not supported
#endif
/*! Macro to define a variable with L1 d-cache line size alignment */
#if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#define SDK_L1DCACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)
#endif
/*! Macro to define a variable with L2 cache line size alignment */
#if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#define SDK_L2CACHE_ALIGN(var) SDK_ALIGN(var, FSL_FEATURE_L2CACHE_LINESIZE_BYTE)
#endif
/*! Macro to change a value to a given size aligned value */
#define SDK_SIZEALIGN(var, alignbytes) \
((unsigned int)((var) + ((alignbytes)-1U)) & (unsigned int)(~(unsigned int)((alignbytes)-1U)))
/*! @} */
/*!
* @name Non-cacheable region definition macros
*
* For initialized non-zero non-cacheable variables, please use "AT_NONCACHEABLE_SECTION_INIT(var) ={xx};" or
* "AT_NONCACHEABLE_SECTION_ALIGN_INIT(var) ={xx};" in your projects to define them. For zero-inited non-cacheable
* variables, please use "AT_NONCACHEABLE_SECTION(var);" or "AT_NONCACHEABLE_SECTION_ALIGN(var);" to define them,
* these zero-inited variables will be initialized to zero in system startup.
*
* @note For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA"
* in your projects to make sure the non-cacheable section variables will be initialized in system startup.
*
* @{
*/
/*!
* @def AT_NONCACHEABLE_SECTION(var)
* Define a variable \a var, and place it in non-cacheable section.
*
* @def AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes)
* Define a variable \a var, and place it in non-cacheable section, the start address
* of the variable is aligned to \a alignbytes.
*
* @def AT_NONCACHEABLE_SECTION_INIT(var)
* Define a variable \a var with initial value, and place it in non-cacheable section.
*
* @def AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes)
* Define a variable \a var with initial value, and place it in non-cacheable section,
* the start address of the variable is aligned to \a alignbytes.
*/
#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && \
defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
#if (defined(__ICCARM__))
#define AT_NONCACHEABLE_SECTION(var) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable"
#define AT_NONCACHEABLE_SECTION_INIT(var) var @"NonCacheable.init"
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init"
#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) __attribute__((aligned(alignbytes))) var
#if (defined(__CC_ARM))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable"), zero_init)) __attribute__((aligned(alignbytes))) var
#else
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section(".bss.NonCacheable"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section(".bss.NonCacheable"))) __attribute__((aligned(alignbytes))) var
#endif
#elif (defined(__GNUC__)) || defined(DOXYGEN_OUTPUT)
/* For GCC, when the non-cacheable section is required, please define "__STARTUP_INITIALIZE_NONCACHEDATA"
* in your projects to make sure the non-cacheable section variables will be initialized in system startup.
*/
#define AT_NONCACHEABLE_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) \
__attribute__((section("NonCacheable.init"))) var __attribute__((aligned(alignbytes)))
#define AT_NONCACHEABLE_SECTION(var) __attribute__((section("NonCacheable,\"aw\",%nobits @"))) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) \
__attribute__((section("NonCacheable,\"aw\",%nobits @"))) var __attribute__((aligned(alignbytes)))
#else
#error Toolchain not supported.
#endif
#else
#define AT_NONCACHEABLE_SECTION(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN(var, alignbytes) SDK_ALIGN(var, alignbytes)
#define AT_NONCACHEABLE_SECTION_INIT(var) var
#define AT_NONCACHEABLE_SECTION_ALIGN_INIT(var, alignbytes) SDK_ALIGN(var, alignbytes)
#endif
/*! @} */
/*!
* @name Time sensitive region
* @{
*/
/*!
* @def AT_QUICKACCESS_SECTION_CODE(func)
* Place function in a section which can be accessed quickly by core.
*
* @def AT_QUICKACCESS_SECTION_DATA(var)
* Place data in a section which can be accessed quickly by core.
*
* @def AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes)
* Place data in a section which can be accessed quickly by core, and the variable
* address is set to align with \a alignbytes.
*/
#if (defined(__ICCARM__))
#define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
#define AT_QUICKACCESS_SECTION_DATA(var) var @"DataQuickAccess"
#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
SDK_PRAGMA(data_alignment = alignbytes) var @"DataQuickAccess"
#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
#define AT_QUICKACCESS_SECTION_DATA(var) __attribute__((section("DataQuickAccess"))) var
#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
__attribute__((section("DataQuickAccess"))) __attribute__((aligned(alignbytes))) var
#elif (defined(__GNUC__)) || defined(DOXYGEN_OUTPUT)
#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
#define AT_QUICKACCESS_SECTION_DATA(var) __attribute__((section("DataQuickAccess"))) var
#define AT_QUICKACCESS_SECTION_DATA_ALIGN(var, alignbytes) \
__attribute__((section("DataQuickAccess"))) var __attribute__((aligned(alignbytes)))
#else
#error Toolchain not supported.
#endif /* defined(__ICCARM__) */
/*! @} */
/*!
* @name Ram Function
* @{
*
* @def RAMFUNCTION_SECTION_CODE(func)
* Place function in ram.
*/
#if (defined(__ICCARM__))
#define RAMFUNCTION_SECTION_CODE(func) func @"RamFunction"
#elif (defined(__CC_ARM) || defined(__ARMCC_VERSION))
#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
#elif (defined(__GNUC__)) || defined(DOXYGEN_OUTPUT)
#define RAMFUNCTION_SECTION_CODE(func) __attribute__((section("RamFunction"))) func
#else
#error Toolchain not supported.
#endif /* defined(__ICCARM__) */
/*! @} */
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
void DefaultISR(void);
#endif
/*
* The fsl_clock.h is included here because it needs MAKE_VERSION/MAKE_STATUS/status_t
* defined in previous of this file.
*/
#include "fsl_clock.h"
/*
* Chip level peripheral reset API, for MCUs that implement peripheral reset control external to a peripheral
*/
#if ((defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) || \
(defined(FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT) && (FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT > 0)))
#include "fsl_reset.h"
#endif
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus*/
/*!
* @brief Enable specific interrupt.
*
* Enable LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only enables the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ number.
* @retval kStatus_Success Interrupt enabled successfully
* @retval kStatus_Fail Failed to enable the interrupt
*/
static inline status_t EnableIRQ(IRQn_Type interrupt)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_EnableIRQ(interrupt);
#else
NVIC_EnableIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Disable specific interrupt.
*
* Disable LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only disables the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ number.
* @retval kStatus_Success Interrupt disabled successfully
* @retval kStatus_Fail Failed to disable the interrupt
*/
static inline status_t DisableIRQ(IRQn_Type interrupt)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_DisableIRQ(interrupt);
#else
NVIC_DisableIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Enable the IRQ, and also set the interrupt priority.
*
* Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ to Enable.
* @param priNum Priority number set to interrupt controller register.
* @retval kStatus_Success Interrupt priority set successfully
* @retval kStatus_Fail Failed to set the interrupt priority.
*/
static inline status_t EnableIRQWithPriority(IRQn_Type interrupt, uint8_t priNum)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_SetPriority(interrupt, priNum);
GIC_EnableIRQ(interrupt);
#else
NVIC_SetPriority(interrupt, priNum);
NVIC_EnableIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Set the IRQ priority.
*
* Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The IRQ to set.
* @param priNum Priority number set to interrupt controller register.
*
* @retval kStatus_Success Interrupt priority set successfully
* @retval kStatus_Fail Failed to set the interrupt priority.
*/
static inline status_t IRQ_SetPriority(IRQn_Type interrupt, uint8_t priNum)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_SetPriority(interrupt, priNum);
#else
NVIC_SetPriority(interrupt, priNum);
#endif
}
return status;
}
/*!
* @brief Clear the pending IRQ flag.
*
* Only handle LEVEL1 interrupt. For some devices, there might be multiple interrupt
* levels. For example, there are NVIC and intmux. Here the interrupts connected
* to NVIC are the LEVEL1 interrupts, because they are routed to the core directly.
* The interrupts connected to intmux are the LEVEL2 interrupts, they are routed
* to NVIC first then routed to core.
*
* This function only handles the LEVEL1 interrupts. The number of LEVEL1 interrupts
* is indicated by the feature macro FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS.
*
* @param interrupt The flag which IRQ to clear.
*
* @retval kStatus_Success Interrupt priority set successfully
* @retval kStatus_Fail Failed to set the interrupt priority.
*/
static inline status_t IRQ_ClearPendingIRQ(IRQn_Type interrupt)
{
status_t status = kStatus_Success;
if (NotAvail_IRQn == interrupt)
{
status = kStatus_Fail;
}
#if defined(FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS) && (FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS > 0)
else if ((int32_t)interrupt >= (int32_t)FSL_FEATURE_NUMBER_OF_LEVEL1_INT_VECTORS)
{
status = kStatus_Fail;
}
#endif
else
{
#if defined(__GIC_PRIO_BITS)
GIC_ClearPendingIRQ(interrupt);
#else
NVIC_ClearPendingIRQ(interrupt);
#endif
}
return status;
}
/*!
* @brief Disable the global IRQ
*
* Disable the global interrupt and return the current primask register. User is required to provided the primask
* register for the EnableGlobalIRQ().
*
* @return Current primask value.
*/
static inline uint32_t DisableGlobalIRQ(void)
{
uint32_t mask;
#if defined(CPSR_I_Msk)
mask = __get_CPSR() & CPSR_I_Msk;
#elif defined(DAIF_I_BIT)
mask = __get_DAIF() & DAIF_I_BIT;
#else
mask = __get_PRIMASK();
#endif
__disable_irq();
return mask;
}
/*!
* @brief Enable the global IRQ
*
* Set the primask register with the provided primask value but not just enable the primask. The idea is for the
* convenience of integration of RTOS. some RTOS get its own management mechanism of primask. User is required to
* use the EnableGlobalIRQ() and DisableGlobalIRQ() in pair.
*
* @param primask value of primask register to be restored. The primask value is supposed to be provided by the
* DisableGlobalIRQ().
*/
static inline void EnableGlobalIRQ(uint32_t primask)
{
#if defined(CPSR_I_Msk)
__set_CPSR((__get_CPSR() & ~CPSR_I_Msk) | primask);
#elif defined(DAIF_I_BIT)
if (0UL == primask)
{
__enable_irq();
}
#else
__set_PRIMASK(primask);
#endif
}
#if defined(ENABLE_RAM_VECTOR_TABLE)
/*!
* @brief install IRQ handler
*
* @param irq IRQ number
* @param irqHandler IRQ handler address
* @return The old IRQ handler address
*/
uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler);
#endif /* ENABLE_RAM_VECTOR_TABLE. */
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
/*
* When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
* powerlib should be used instead of these functions.
*/
#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
/*!
* @brief Enable specific interrupt for wake-up from deep-sleep mode.
*
* Enable the interrupt for wake-up from deep sleep mode.
* Some interrupts are typically used in sleep mode only and will not occur during
* deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
* those clocks (significantly increasing power consumption in the reduced power mode),
* making these wake-ups possible.
*
* @note This function also enables the interrupt in the NVIC (EnableIRQ() is called internaly).
*
* @param interrupt The IRQ number.
*/
void EnableDeepSleepIRQ(IRQn_Type interrupt);
/*!
* @brief Disable specific interrupt for wake-up from deep-sleep mode.
*
* Disable the interrupt for wake-up from deep sleep mode.
* Some interrupts are typically used in sleep mode only and will not occur during
* deep-sleep mode because relevant clocks are stopped. However, it is possible to enable
* those clocks (significantly increasing power consumption in the reduced power mode),
* making these wake-ups possible.
*
* @note This function also disables the interrupt in the NVIC (DisableIRQ() is called internaly).
*
* @param interrupt The IRQ number.
*/
void DisableDeepSleepIRQ(IRQn_Type interrupt);
#endif /* FSL_FEATURE_POWERLIB_EXTEND */
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
#if defined(DWT)
/*!
* @brief Enable the counter to get CPU cycles.
*/
void MSDK_EnableCpuCycleCounter(void);
/*!
* @brief Get the current CPU cycle count.
*
* @return Current CPU cycle count.
*/
uint32_t MSDK_GetCpuCycleCount(void);
#endif
#if defined(__cplusplus)
}
#endif /* __cplusplus*/
/*! @} */
#endif /* FSL_COMMON_ARM_H_ */