Browse Source

cortexm_common: Introduce bitbanding macros

master
Joakim Nohlgård 6 years ago
parent
commit
dc3aa13e90
  1. 231
      cpu/cortexm_common/include/bit.h

231
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 <joakim.nohlgard@eistec.se>
*/
#ifndef BIT_H
#define BIT_H
#include <stdint.h>
#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 */
/** @} */
Loading…
Cancel
Save