7.4.1 SFR Register Definitions
In this section we describe the conventions of the SFR interface. In what follows we use the WDT (watchdog timer) component as an example. Always consult the device data sheet and device-specific header files to confirm the specific capabilities and names for your device.
The SFRs within each component are accessed through a base pointer,
defined in the header as a macro, for example, _WDT_REGS
. This is used as
a pointer to a structure of type _wdt_registers_t
containing all SFRs of
that component by name, e.g., _WDT_REGS->WDT_CR
. The fields of this
structure are typed to reflect whether each register is read-only, write-only, or
read-write; however, the device data sheet should always be consulted for details on the
read/write properties of SFRs.
Each SFR field is, itself, a structure of the type allowing access to the
SFR data as a whole, e.g., WDT_CR.w
, or access to individual bits or
fields, e.g., WDR_CR.KEY
. Any reserved bits in an SFR are not individually
accessible in this way. For example,
/* get entire WDT CR contents */
uint32_t _wdt_cr = _WDT_REGS->WDT_CR.w;
/* Set KEY field of CR (8 bits) */
_WDT_REGS->_WDT_CR.KEY = 0x1F;
/* Read LOCKMR bit of CR */
uint32_t lock = _WDT_REGS->WDT_CR.LOCKMR;
/* Set entire WDT_CR - including reserved bits */
_WDT_REGS->WDT_CR.w = 0xDEADBEEFu;
Note that this and subsequent examples are intended to demonstrate the language interface only and do not demonstrate any usage of the particular SFRs.
For each field of an SFR, macros are also provided to facilitate access to
that field using bit operations. For example, WDR_CR_KEY_Pos
is defined to
the least-significant bit position of the KEY
field, and
WDT_CR_KEY_Msk
is defined to an integer mask of the same width as the
SFR, with all bits of the field set, and all other bits 0. Thus, one can, for example,
extract the KEY
field as:
/* Read KEY field by reading entire register and extracting
bits by mask/shift operations */
uint32_t wdt = _WDT_REGS->WDT_CR.w;
uint32_t key = (wdt & WDT_CR_KEY_Msk) >> WDT_CR_KEY_Pos;
/* Update KEY field by masking/inserting bits */
wdt = (wdt & ~WDT_CR_KEY_Msk) | (0x1F << WDT_CR_KEY_Pos);
/* Set WDRSTT bit by bit operations */
wdt = wdt | (1u << WDT_CR_WDRSTT_Pos);
/* Write back updated register contents */
_WDT_REGS->WDR_CR.w = wdt;
In addition, the WDR_CR_KEY_Value
function-like macro is
defined to place a value in the proper bit position for the field, so that
WDR_CR_KEY_Value(0x3)
produces the same value as:
WDT_CR_KEY_Msk & ((0x3) << WDT_CR_KEY_Pos)
Both explicit bit operations using the mask and position macros and
bitfield operations may be freely mixed; however, the WDT_BASE_ADDRESS
pointer should only be accessed using the defined structures, rather than casting to an
integral type. Always ensure that you confirm the operation of peripheral modules from the
device data sheet.