diff --git a/cpu/cortexm_common/include/bit.h b/cpu/cortexm_common/include/bit.h new file mode 100644 index 0000000000..a4c34ac7d9 --- /dev/null +++ b/cpu/cortexm_common/include/bit.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2017 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_cortexm_common + * @{ + * + * @file + * @brief Bit access macros for Cortex-M based CPUs + * + * @author Joakim NohlgÄrd + */ + +#ifndef BIT_H +#define BIT_H + +#include +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define BITBAND_FUNCTIONS_PROVIDED 1 if the CPU provides its own + * implementations for bit manipulation */ +#if !BITBAND_FUNCTIONS_PROVIDED + +#if DOXYGEN +/** @brief Flag for telling if the CPU has hardware bit band support */ +#define CPU_HAS_BITBAND 1 || 0 (1 for Cortex-M3 and up, 0 for Cortex-M0) +#endif + +#ifndef CPU_HAS_BITBAND +#if (__CORTEX_M >= 3) +#define CPU_HAS_BITBAND 1 +#else +#define CPU_HAS_BITBAND 0 +#endif +#endif + +#if CPU_HAS_BITBAND || DOXYGEN +/* Cortex-M3 and higher provide a bitband address space for atomically accessing + * single bits of peripheral registers, and sometimes for RAM as well */ +/** + * @name Bit manipulation functions + * @{ + */ +/* Generic bit band conversion routine */ +/** + * @brief Convert bit band region address and bit number to bit band alias address + * + * @param[in] ptr base address in non bit banded memory + * @param[in] bit bit number within the word + * + * @return Address of the bit within the bit band memory region + */ +static inline volatile void *bitband_addr(volatile void *ptr, uintptr_t bit) +{ + return (volatile void *)((((uintptr_t)ptr) & 0xF0000000ul) + 0x2000000ul + + ((((uintptr_t)ptr) & 0xFFFFFul) << 5) + (bit << 2)); +} + +/** + * @brief Set a single bit in the 32 bit word pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr |= (1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target word + * @param[in] bit bit number within the word + */ +static inline void bit_set32(volatile uint32_t *ptr, uint8_t bit) +{ + *((volatile uint32_t *)bitband_addr(ptr, bit)) = 1; +} + +/** + * @brief Set a single bit in the 16 bit word pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr |= (1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target word + * @param[in] bit bit number within the word + */ +static inline void bit_set16(volatile uint16_t *ptr, uint8_t bit) +{ + *((volatile uint16_t *)bitband_addr(ptr, bit)) = 1; +} + +/** + * @brief Set a single bit in the 8 bit byte pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr |= (1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target byte + * @param[in] bit bit number within the byte + */ +static inline void bit_set8(volatile uint8_t *ptr, uint8_t bit) +{ + *((volatile uint8_t *)bitband_addr(ptr, bit)) = 1; +} + +/** + * @brief Clear a single bit in the 32 bit word pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr &= ~(1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target word + * @param[in] bit bit number within the word + */ +static inline void bit_clear32(volatile uint32_t *ptr, uint8_t bit) +{ + *((volatile uint32_t *)bitband_addr(ptr, bit)) = 0; +} + +/** + * @brief Clear a single bit in the 16 bit word pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr &= ~(1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target word + * @param[in] bit bit number within the word + */ +static inline void bit_clear16(volatile uint16_t *ptr, uint8_t bit) +{ + *((volatile uint16_t *)bitband_addr(ptr, bit)) = 0; +} + +/** + * @brief Clear a single bit in the 8 bit byte pointed to by @p ptr + * + * The effect is the same as for the following snippet: + * + * @code{c} + * *ptr &= ~(1 << bit); + * @endcode + * + * There is a read-modify-write cycle occurring within the core, but this cycle + * is atomic and can not be disrupted by IRQs + * + * @param[in] ptr pointer to target byte + * @param[in] bit bit number within the byte + */ +static inline void bit_clear8(volatile uint8_t *ptr, uint8_t bit) +{ + *((volatile uint8_t *)bitband_addr(ptr, bit)) = 0; +} + +/** @} */ + +#else /* CPU_HAS_BITBAND */ +/* CPU does not have bitbanding, fall back to plain C */ +static inline void bit_set32(volatile uint32_t *ptr, uint8_t bit) +{ + *ptr |= (1 << (bit)); +} + +static inline void bit_set16(volatile uint16_t *ptr, uint8_t bit) +{ + *ptr |= (1 << (bit)); +} + +static inline void bit_set8(volatile uint8_t *ptr, uint8_t bit) +{ + *ptr |= (1 << (bit)); +} + +static inline void bit_clear32(volatile uint32_t *ptr, uint8_t bit) +{ + *ptr &= ~(1 << (bit)); +} + +static inline void bit_clear16(volatile uint16_t *ptr, uint8_t bit) +{ + *ptr &= ~(1 << (bit)); +} + +static inline void bit_clear8(volatile uint8_t *ptr, uint8_t bit) +{ + *ptr &= ~(1 << (bit)); +} + +#endif /* CPU_HAS_BITBAND */ + +#endif /* !BITBAND_FUNCTIONS_PROVIDED */ + +#ifdef __cplusplus +} +#endif + +#endif /* BIT_H */ +/** @} */