diff --git a/cpu/kinetis/include/bme.h b/cpu/kinetis/include/bme.h new file mode 100644 index 0000000000000000000000000000000000000000..5f445821a9150510b78098335c1a582bd3186f97 --- /dev/null +++ b/cpu/kinetis/include/bme.h @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/** + * @defgroup cpu_kinetis_bme Kinetis Bit Manipulation Engine (BME) + * @ingroup cpu_kinetis + * @brief Macros for using decorated memory accesses with the Bit + * Manipulation Engine available in Kinetis Cortex-M0+ devices + * + * @{ + * @file + * @brief Macro definitions for the Kinetis Bit Manipulation Engine (BME) + * + * @author Joakim Nohlgård <joakim.nohlgard@eistec.se> + */ + +#ifndef BME_H +#define BME_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Tell bit.h that we provide CPU specific bit manipulation functions + */ +#define BITBAND_FUNCTIONS_PROVIDED 1 + +#define BME_AND_MASK (1 << 26) /**< AND decoration bitmask */ +#define BME_OR_MASK (1 << 27) /**< OR decoration bitmask */ +#define BME_XOR_MASK (3 << 26) /**< XOR decoration bitmask */ +#define BME_LAC1_MASK(BIT) ((1 << 27) | ((BIT) << 21)) /**< Load-and-clear 1 bit */ +#define BME_LAS1_MASK(BIT) ((3 << 26) | ((BIT) << 21)) /**< Load-and-set 1 bit */ + +/** + * @brief Bit field extraction bitmask + * + * @param bit LSB of the bitfield within the word/halfword/byte + * @param width Number of bits to extract + */ +#define BME_BF_MASK(bit, width) ((1 << 28) | ((bit) << 23) | (((width) - 1 ) << 19)) + +/** + * @brief Bit field address macro + * + * @pre The target address must lie within a part of the peripheral address + * space 0x40000000 - 0x40070000 + * + * @param[in] ptr Pointer to target register + * @param[in] bit Location of the LSB of the bitfield within the register + * @param[in] width Width of the the bitfield, in bits + * + * @return bitfield address as an uintptr_t + */ +static inline volatile void *bme_bf_addr(volatile void *ptr, uintptr_t bit, uintptr_t width) +{ + return (volatile void *)(((uintptr_t)ptr) | BME_BF_MASK(bit, width)); +} + +/** + * @brief Access a bitfield (32 bit load/store) + * + * This macro can be used both for store `(*bme_bitfield32(xxx) = y)` and + * load `(y = *bme_bitfield32(ptr, bit))` + * + * @pre The target address must lie within a part of the peripheral address + * space 0x40000000 - 0x40070000 + * + * @param[in] ptr Pointer to target register + * @param[in] bit Location of the LSB of the bitfield within the register + * @param[in] width Width of the the bitfield, in bits + * + * @return bitfield extracted as a (modifiable) lvalue + */ +static inline volatile uint32_t *bme_bitfield32(volatile uint32_t *ptr, uint8_t bit, uint8_t width) +{ + return (volatile uint32_t *)(bme_bf_addr(ptr, bit, width)); +} + +/** + * @brief Access a bitfield (16 bit load/store) + * + * This macro can be used both for store `(*bme_bitfield16(xxx) = y)` and + * load `(y = *bme_bitfield16(ptr, bit))` + * + * @pre The target address must lie within a part of the peripheral address + * space 0x40000000 - 0x40070000 + * + * @param[in] ptr Pointer to target register + * @param[in] bit Location of the LSB of the bitfield within the register + * @param[in] width Width of the the bitfield, in bits + * + * @return bitfield extracted as a (modifiable) lvalue + */ +static inline volatile uint16_t *bme_bitfield16(volatile uint16_t *ptr, uint8_t bit, uint8_t width) +{ + return (volatile uint16_t *)(bme_bf_addr(ptr, bit, width)); +} + +/** + * @brief Access a bitfield (8 bit load/store) + * + * This macro can be used both for store `(*bme_bitfield8(xxx) = y)` and + * load `(y = *bme_bitfield8(ptr, bit))` + * + * @pre The target address must lie within a part of the peripheral address + * space 0x40000000 - 0x40070000 + * + * @param[in] ptr Pointer to target register + * @param[in] bit Location of the LSB of the bitfield within the register + * @param[in] width Width of the the bitfield, in bits + * + * @return bitfield extracted as a (modifiable) lvalue + */ +static inline volatile uint8_t *bme_bitfield8(volatile uint8_t *ptr, uint8_t bit, uint8_t width) +{ + return (volatile uint8_t *)(bme_bf_addr(ptr, bit, width)); +} + +/* For compatibility with the M3/M4 bitbanding macros: */ + +/** + * @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 *)(((uintptr_t)ptr) | BME_OR_MASK)) = (uint32_t)((1ul << bit)); +} + +/** + * @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 *)(((uintptr_t)ptr) | BME_OR_MASK)) = (uint16_t)((1ul << bit)); +} + +/** + * @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 *)(((uintptr_t)ptr) | BME_OR_MASK)) = (uint8_t)((1ul << bit)); +} + +/** + * @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 *)(((uintptr_t)ptr) | BME_AND_MASK)) = (uint32_t)(~(1ul << bit)); +} + +/** + * @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 *)(((uintptr_t)ptr) | BME_AND_MASK)) = (uint16_t)(~(1ul << bit)); +} + +/** + * @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 *)(((uintptr_t)ptr) | BME_AND_MASK)) = (uint8_t)(~(1ul << bit)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* BME_H */ + +/** @} */ diff --git a/cpu/kinetis/include/cpu_conf_kinetis.h b/cpu/kinetis/include/cpu_conf_kinetis.h index 22c01eac583438c273ddae10ec7513aa676b2551..cd5101d692a2e0ddc94412f5785f53262a84e69d 100644 --- a/cpu/kinetis/include/cpu_conf_kinetis.h +++ b/cpu/kinetis/include/cpu_conf_kinetis.h @@ -21,6 +21,15 @@ #include "cpu_conf_common.h" +#if (__CORTEX_M < 3) +/* + * Kinetis Cortex-M0+ devices have bit manipulation engine (BME) which provides + * the same functionality (and some more) as the bitband aliased memory found in + * Cortex-M3 and up + */ +#include "bme.h" +#endif + #ifdef __cplusplus extern "C" {