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.