summaryrefslogtreecommitdiffstats
path: root/libopencm3/include/libopencm3/cm3/cortex.h
diff options
context:
space:
mode:
Diffstat (limited to 'libopencm3/include/libopencm3/cm3/cortex.h')
-rw-r--r--libopencm3/include/libopencm3/cm3/cortex.h278
1 files changed, 278 insertions, 0 deletions
diff --git a/libopencm3/include/libopencm3/cm3/cortex.h b/libopencm3/include/libopencm3/cm3/cortex.h
new file mode 100644
index 0000000..eb9cb09
--- /dev/null
+++ b/libopencm3/include/libopencm3/cm3/cortex.h
@@ -0,0 +1,278 @@
+/** @defgroup CM3_cortex_defines Cortex Core Defines
+ *
+ * @brief <b>libopencm3 Defined Constants and Types for the Cortex Core </b>
+ *
+ * @ingroup CM3_defines
+ *
+ * @version 1.0.0
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Ben Gamari <bgamari@gmail.com>
+ * Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBOPENCM3_CORTEX_H
+#define LIBOPENCM3_CORTEX_H
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Enable interrupts
+ *
+ * Disable the interrupt mask and enable interrupts globally
+ */
+static inline void cm_enable_interrupts(void)
+{
+ __asm__("CPSIE I\n");
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Disable interrupts
+ *
+ * Mask all interrupts globally
+ */
+static inline void cm_disable_interrupts(void)
+{
+ __asm__("CPSID I\n");
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Enable faults
+ *
+ * Disable the HardFault mask and enable fault interrupt globally
+ */
+static inline void cm_enable_faults(void)
+{
+ __asm__("CPSIE F\n");
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Disable faults
+ *
+ * Mask the HardFault interrupt globally
+ */
+static inline void cm_disable_faults(void)
+{
+ __asm__("CPSID F\n");
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Check if interrupts are masked
+ *
+ * Checks, if interrupts are masked (disabled).
+ *
+ * @returns true, if interrupts are disabled.
+ */
+__attribute__((always_inline))
+static inline bool cm_is_masked_interrupts(void)
+{
+ register uint32_t result;
+ __asm__ ("MRS %0, PRIMASK" : "=r" (result));
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Check if Fault interrupt is masked
+ *
+ * Checks, if HardFault interrupt is masked (disabled).
+ *
+ * @returns bool true, if HardFault interrupt is disabled.
+ */
+__attribute__((always_inline))
+static inline bool cm_is_masked_faults(void)
+{
+ register uint32_t result;
+ __asm__ ("MRS %0, FAULTMASK" : "=r" (result));
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Mask interrupts
+ *
+ * This function switches the mask of the interrupts. If mask is true, the
+ * interrupts will be disabled. The result of this function can be used for
+ * restoring previous state of the mask.
+ *
+ * @param[in] mask bool New state of the interrupt mask
+ * @returns bool old state of the interrupt mask
+ */
+__attribute__((always_inline))
+static inline bool cm_mask_interrupts(bool mask)
+{
+ register bool old;
+ __asm__ __volatile__("MRS %0, PRIMASK" : "=r" (old));
+ __asm__ __volatile__("" : : : "memory");
+ __asm__ __volatile__("MSR PRIMASK, %0" : : "r" (mask));
+ return old;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Mask HardFault interrupt
+ *
+ * This function switches the mask of the HardFault interrupt. If mask is true,
+ * the HardFault interrupt will be disabled. The result of this function can be
+ * used for restoring previous state of the mask.
+ *
+ * @param[in] mask bool New state of the HardFault interrupt mask
+ * @returns bool old state of the HardFault interrupt mask
+ */
+__attribute__((always_inline))
+static inline bool cm_mask_faults(bool mask)
+{
+ register bool old;
+ __asm__ __volatile__ ("MRS %0, FAULTMASK" : "=r" (old));
+ __asm__ __volatile__ ("" : : : "memory");
+ __asm__ __volatile__ ("MSR FAULTMASK, %0" : : "r" (mask));
+ return old;
+}
+
+/**@}*/
+
+/*===========================================================================*/
+/** @defgroup CM3_cortex_atomic_defines Cortex Core Atomic support Defines
+ *
+ * @brief Atomic operation support
+ *
+ * @ingroup CM3_cortex_defines
+ */
+/**@{*/
+
+#if !defined(__DOXYGEN__)
+/* Do not populate this definition outside */
+static inline bool __cm_atomic_set(bool *val)
+{
+ return cm_mask_interrupts(*val);
+}
+
+#define __CM_SAVER(state) \
+ __val = state, \
+ __save __attribute__((__cleanup__(__cm_atomic_set))) = \
+ __cm_atomic_set(&__val)
+
+#endif /* !defined(__DOXYGEN) */
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Atomic Declare block
+ *
+ * This macro disables interrupts for the next command or block of code. The
+ * interrupt mask is automatically restored after exit of the boundary of the
+ * code block. Therefore restore of interrupt is done automatically after call
+ * of return or goto control sentence jumping outside of the block.
+ *
+ * @warning The usage of sentences break or continue is prohibited in the block
+ * due to implementation of this macro!
+ *
+ * @note It is safe to use this block inside normal code and in interrupt
+ * routine.
+ *
+ * @example 1: Basic usage of atomic block
+ *
+ * @code
+ * uint64_t value; // This value is used somewhere in interrupt
+ *
+ * ...
+ *
+ * CM_ATOMIC_BLOCK() { // interrupts are masked in this block
+ * value = value * 1024 + 651; // access value as atomic
+ * } // interrupts is restored automatically
+ * @endcode
+ *
+ * @example 2: Use of return inside block:
+ *
+ * @code
+ * uint64_t value; // This value is used somewhere in interrupt
+ *
+ * ...
+ *
+ * uint64_t allocval(void)
+ * {
+ * CM_ATOMIC_BLOCK() { // interrupts are masked in this block
+ * value = value * 1024 + 651; // do long atomic operation
+ * return value; // interrupts is restored automatically
+ * }
+ * }
+ * @endcode
+ */
+#if defined(__DOXYGEN__)
+#define CM_ATOMIC_BLOCK()
+#else /* defined(__DOXYGEN__) */
+#define CM_ATOMIC_BLOCK() \
+ for (bool ___CM_SAVER(true), __my = true; __my; __my = false)
+#endif /* defined(__DOXYGEN__) */
+
+/*---------------------------------------------------------------------------*/
+/** @brief Cortex M Atomic Declare context
+ *
+ * This macro disables interrupts in the current block of code from the place
+ * where it is defined to the end of the block. The interrupt mask is
+ * automatically restored after exit of the boundary of the code block.
+ * Therefore restore of interrupt is done automatically after call of return,
+ * continue, break, or goto control sentence jumping outside of the block.
+ *
+ * @note This function is intended for use in for- cycles to enable the use of
+ * break and contine sentences inside the block, and for securing the atomic
+ * reader-like functions.
+ *
+ * @note It is safe to use this block inside normal code and in interrupt
+ * routine.
+ *
+ * @example 1: Basic usage of atomic context
+ *
+ * @code
+ * uint64_t value; // This value is used somewhere in interrupt
+ *
+ * ...
+ *
+ * for (int i=0;i < 100; i++) {
+ * CM_ATOMIC_CONTEXT(); // interrupts are masked in this block
+ * value += 100; // access value as atomic
+ * if ((value % 16) == 0) {
+ * break; // restore interrupts and break cycle
+ * }
+ * } // interrupts is restored automatically
+ * @endcode
+ *
+ * @example 2: Usage of atomic context inside atomic reader fcn.
+ *
+ * @code
+ * uint64_t value; // This value is used somewhere in interrupt
+ *
+ * ...
+ *
+ * uint64_t getnextval(void)
+ * {
+ * CM_ATOMIC_CONTEXT(); // interrupts are masked in this block
+ * value = value + 3; // do long atomic operation
+ * return value; // interrupts is restored automatically
+ * }
+ * @endcode
+ */
+#if defined(__DOXYGEN__)
+#define CM_ATOMIC_CONTEXT()
+#else /* defined(__DOXYGEN__) */
+#define CM_ATOMIC_CONTEXT() bool __CM_SAVER(true)
+#endif /* defined(__DOXYGEN__) */
+
+/**@}*/
+
+
+
+#endif