/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */#ifndef_HARDWARE_ADDRESS_MAPPED_H#define_HARDWARE_ADDRESS_MAPPED_H#include"pico.h"#include"hardware/regs/addressmap.h"/** \file address_mapped.h * \defgroup hardware_base hardware_base * * \brief Low-level types and (atomic) accessors for memory-mapped hardware registers * * `hardware_base` defines the low level types and access functions for memory mapped hardware registers. It is included * by default by all other hardware libraries. * * The following register access typedefs codify the access type (read/write) and the bus size (8/16/32) of the hardware register. * The register type names are formed by concatenating one from each of the 3 parts A, B, C * A | B | C | Meaning * ------|---|---|-------- * io_ | | | A Memory mapped IO register * |ro_| | read-only access * |rw_| | read-write access * |wo_| | write-only access (can't actually be enforced via C API) * | | 8| 8-bit wide access * | | 16| 16-bit wide access * | | 32| 32-bit wide access * * When dealing with these types, you will always use a pointer, i.e. `io_rw_32 *some_reg` is a pointer to a read/write * 32 bit register that you can write with `*some_reg = value`, or read with `value = *some_reg`. * * RP-series hardware is also aliased to provide atomic setting, clear or flipping of a subset of the bits within * a hardware register so that concurrent access by two cores is always consistent with one atomic operation * being performed first, followed by the second. * * See hw_set_bits(), hw_clear_bits() and hw_xor_bits() provide for atomic access via a pointer to a 32 bit register * * Additionally given a pointer to a structure representing a piece of hardware (e.g. `dma_hw_t *dma_hw` for the DMA controller), you can * get an alias to the entire structure such that writing any member (register) within the structure is equivalent * to an atomic operation via hw_set_alias(), hw_clear_alias() or hw_xor_alias()... * * For example `hw_set_alias(dma_hw)->inte1 = 0x80;` will set bit 7 of the INTE1 register of the DMA controller, * leaving the other bits unchanged. *//* ... */#ifdef__cplusplusextern"C"{#endif#definecheck_hw_layout(type,member,offset)static_assert(offsetof(type,member)==(offset),"hw offset mismatch")#definecheck_hw_size(type,size)static_assert(sizeof(type)==(size),"hw size mismatch")// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS, Enable/disable assertions in memory address aliasing macros, type=bool, default=0, group=hardware_base#ifndefPARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS#definePARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS0#endiftypedefvolatileuint64_tio_rw_64;typedefconstvolatileuint64_tio_ro_64;typedefvolatileuint64_tio_wo_64;typedefvolatileuint32_tio_rw_32;typedefconstvolatileuint32_tio_ro_32;typedefvolatileuint32_tio_wo_32;typedefvolatileuint16_tio_rw_16;typedefconstvolatileuint16_tio_ro_16;typedefvolatileuint16_tio_wo_16;typedefvolatileuint8_tio_rw_8;typedefconstvolatileuint8_tio_ro_8;typedefvolatileuint8_tio_wo_8;typedefvolatileuint8_t*constioptr;typedefioptrconstconst_ioptr;// A non-functional (empty) helper macro to help IDEs follow links from the autogenerated// hardware struct headers in hardware/structs/xxx.h to the raw register definitions// in hardware/regs/xxx.h. A preprocessor define such as TIMER_TIMEHW_OFFSET (a timer register offset)// is not generally clickable (in an IDE) if placed in a C comment, so _REG_(TIMER_TIMEHW_OFFSET) is// included outside of a comment instead#define_REG_(x)// Helper method used by hw_alias macros to optionally check input validity#definehw_alias_check_addr(addr)((uintptr_t)(addr))// can't use the following impl as it breaks existing static declarations using hw_alias, so would be a backwards incompatibility//static __force_inline uint32_t hw_alias_check_addr(volatile void *addr) {// uint32_t rc = (uintptr_t)addr;// invalid_params_if(ADDRESS_ALIAS, rc < 0x40000000); // catch likely non HW pointer types// return rc;//}#ifPICO_RP2040// Helper method used by xip_alias macros to optionally check input validity__force_inlinestaticuint32_txip_alias_check_addr(constvoid*addr){uint32_trc=(uintptr_t)addr;valid_params_if(ADDRESS_ALIAS,rc>=XIP_MAIN_BASE&&rc<XIP_NOALLOC_BASE);returnrc;}xip_alias_check_addr (const void *addr) { ... }/* ... */#else//static __force_inline uint32_t xip_alias_check_addr(const void *addr) {// uint32_t rc = (uintptr_t)addr;// valid_params_if(ADDRESS_ALIAS, rc >= XIP_BASE && rc < XIP_END);// return rc;//}/* ... */#endif// Untyped conversion alias pointer generation macros#definehw_set_alias_untyped(addr)((void*)(REG_ALIAS_SET_BITS+hw_alias_check_addr(addr)))#definehw_clear_alias_untyped(addr)((void*)(REG_ALIAS_CLR_BITS+hw_alias_check_addr(addr)))#definehw_xor_alias_untyped(addr)((void*)(REG_ALIAS_XOR_BITS+hw_alias_check_addr(addr)))#ifPICO_RP2040#definexip_noalloc_alias_untyped(addr)((void*)(XIP_NOALLOC_BASE|xip_alias_check_addr(addr)))#definexip_nocache_alias_untyped(addr)((void*)(XIP_NOCACHE_BASE|xip_alias_check_addr(addr)))#definexip_nocache_noalloc_alias_untyped(addr)((void*)(XIP_NOCACHE_NOALLOC_BASE|xip_alias_check_addr(addr)))/* ... */#endif// Typed conversion alias pointer generation macros#definehw_set_alias(p)((typeof(p))hw_set_alias_untyped(p))#definehw_clear_alias(p)((typeof(p))hw_clear_alias_untyped(p))#definehw_xor_alias(p)((typeof(p))hw_xor_alias_untyped(p))#definexip_noalloc_alias(p)((typeof(p))xip_noalloc_alias_untyped(p))#definexip_nocache_alias(p)((typeof(p))xip_nocache_alias_untyped(p))#definexip_nocache_noalloc_alias(p)((typeof(p))xip_nocache_noalloc_alias_untyped(p))6 defines/*! \brief Atomically set the specified bits to 1 in a HW register * \ingroup hardware_base * * \param addr Address of writable register * \param mask Bit-mask specifying bits to set *//* ... */__force_inlinestaticvoidhw_set_bits(io_rw_32*addr,uint32_tmask){*(io_rw_32*)hw_set_alias_untyped((volatilevoid*)addr)=mask;}{ ... }/*! \brief Atomically clear the specified bits to 0 in a HW register * \ingroup hardware_base * * \param addr Address of writable register * \param mask Bit-mask specifying bits to clear *//* ... */__force_inlinestaticvoidhw_clear_bits(io_rw_32*addr,uint32_tmask){*(io_rw_32*)hw_clear_alias_untyped((volatilevoid*)addr)=mask;}{ ... }/*! \brief Atomically flip the specified bits in a HW register * \ingroup hardware_base * * \param addr Address of writable register * \param mask Bit-mask specifying bits to invert *//* ... */__force_inlinestaticvoidhw_xor_bits(io_rw_32*addr,uint32_tmask){*(io_rw_32*)hw_xor_alias_untyped((volatilevoid*)addr)=mask;}{ ... }/*! \brief Set new values for a sub-set of the bits in a HW register * \ingroup hardware_base * * Sets destination bits to values specified in \p values, if and only if corresponding bit in \p write_mask is set * * Note: this method allows safe concurrent modification of *different* bits of * a register, but multiple concurrent access to the same bits is still unsafe. * * \param addr Address of writable register * \param values Bits values * \param write_mask Mask of bits to change *//* ... */__force_inlinestaticvoidhw_write_masked(io_rw_32*addr,uint32_tvalues,uint32_twrite_mask){hw_xor_bits(addr,(*addr^values)&write_mask);}{ ... }#if!PICO_RP2040// include this here to avoid the check in every other hardware/structs header that needs it#include"hardware/structs/accessctrl.h"/* ... */#endif#ifdef__cplusplus}extern "C" { ... }#endif/* ... */#endif
Details
Show: from
Types: Columns:
All items filtered out
All items filtered out
This file uses the notable symbols shown below. Click anywhere in the file to view more details.