The layer closest to the hardware is named HRI. This layer is a simple
interface with very little logic that do register data content manipulation with a set
of defined functions calls. The data manipulation operations can be performed on a bit,
bit field, and complete register level.
Figure 1. HRI Example Data Manipulation of
Bit and Bit Field Contents
This layer also abstracts special register access properties like data
synchronization between clock domains. It also ensures that data integrity is kept
within an interruptible system by inserting critical sections when it is not possible to
do data manipulation atomically.
Using the HRI interfaces as access interface to the peripheral registers
helps the compiler optimize the code towards targets like low code size or faster code.
When targeting fast code, the compiler can choose to inline the function to be able to
optimize the code in context and avoid call conventions. For low code size, the compiler
can avoid in-lining the function and reuse the same copy of the function multiple
times.
All functions in the HRI are defined as static inline. This gives the
compiler the possibility to optimize the code within the context of where it is used.
Using functions instead of pre-processor macros keeps the possibility to use the
compiler for type checking and makes the code a bit safer compared to pre-processor
macros.
There are three main categories of access functions; single-bit access
functions (accesses one bit at the time), bit field access functions (accesses multiple
bits with a common purpose), and register access functions (access the content of a full
register).
Different operation types available for the access functions
- get - Returns the value of the
bit, bit field, or register (bit fields and registers are anded with a
mask)
- set - Sets the value to a high
state (bit fields and registers are anded with a mask value)
- clear - Sets the value to a low
state (bit fields and registers are anded with a mask value)
- toggle - Value is changed to the opposite (bit fields and registers are anded
with a mask value)
- write - Copy all bit states from the input data to the bit field or
register
- read - Copy all bit states from the register and return it to the
application
Note: If shadow registers are
detected for set, toggle, and clear they will be used instead of normal
access.
These operations are available for single bit access
- get - read state of bit
- set - set bit state to high
- clear - set bit state to low
- toggle - change bit state to the opposite
- write - change the state of the
bit based on input, independent of the previous state
Note: Access to some registers, such as
status and INTFLAG registers, only have get and clear access functions.
These operations are available for bit field access
- get (read the state of bits defined by a mask)
- set (set bit states to high for bits defined by a mask)
- clear (set bit states to low for bits defined by a mask)
- toggle (change bit states to opposite for bits defined by a mask)
- write (set states of all bits to the state defined in the input data)
- read (read the state of all bits)
These operations are available for register access
- get (read the state of bits defined by a mask)
- set (set bit states to high for bits defined by a mask)
- clear (set bit states to low for bits defined by a mask)
- toggle (change bit states to
opposite for bits defined by a mask)
- read (read the state of all bits in the register)
- write (set the state of all bits in the register based on input data)
These operations are available for write-only register access
Note: The bit and bitfield operations are
not available for write-only register since they are based on the latest value in
the register.
These operations are available for read-only register access
- read/get register
- read/get bit field
- get bit
Shadow register access
The shadow registers are grouped registers that share data of named or
virtual register value. They offer some atomic way to change this shared data value.
As an example, in SAM D20 there is a register group of OUT, OUTCLR, OUTSET, and
OUTTGL in PORT peripheral for port outputs. Writing to OUTCLR, OUTSET, and OUTTGL
actually modifies the value in OUT register. In SAM V71, there is a similar register
group of ODSR, CODR, and SODR in PIO peripheral for I/O outputs, where writing to
CODR and SODR causes changes in ODSR and applies to the actual output pin
levels.
Shadow registers have all possible operations for register, bit, and bit
field access. The operations target the actual named or virtual register: There is
register, bit, and bit field operations to access OUT register, but no operation to
access OUTCLR, OUTSET, and OUTTGL.
Naming scheme
- module name - The acronym used in
the data sheet in lower case letters (e.g. adc) function
- get, set, clear, toggle, write,
read bit name - The register position name as written in the data sheet in upper
case letters
- bit field name – The register
position name (multiple bits) as written in the data sheet in upper case letters
register name - The register name as written in the data sheet in upper case
letters
Single bit access
hri_[module name]_[function]_[REGISTER NAME]_[BIT NAME]
eg. adc_set_CTRLA_ENABLE(hw);
Bit field access
hri_[module name]_[function]_[REGISTER NAME]__[BIT FIELD NAME]
eg. adc_set_AVGCTRL_SAMPLENUM(hw, mask);
Register access
hri_[module name]_[function]_[REGISTER NAME]
eg. adc_set_CTRLA(hw, mask);
Note: Special naming rule for single bit
access to an interrupt flag register. This applies only to interrupt status
registers, not interrupt related registers for enabling, disabling, clearing,
etc.
[module name]_[function]_interrupt_[BIT NAME]