update documentation

pull/1/head
Clyne 2 years ago
parent 86c4b3b5ce
commit a35ded8145

@ -10,12 +10,12 @@ For an 8-bit register at memory address `0x0021`, you would write:
using PORTA_OUT = fr::MemRegister<uint8_t, 0x0021>; using PORTA_OUT = fr::MemRegister<uint8_t, 0x0021>;
``` ```
`fr::MemRegister` is an `fr::Register` that uses `MemoryIO` access. Registers `MemRegister` is an `Register` that uses `MemoryIO` access. Registers
have static functions for interacting with their contents; for example, we have static functions for interacting with their contents; for example, we
could now do `PORTA_OUT::write(0x10)` or `auto state = PORTA::read()`. could now do `PORTA_OUT::write(0x10)` or `auto state = PORTA::read()`.
A lot more can be done with registers once we define some register masks. A A lot more can be done with registers once we define some register masks. A
`fr::RegisterMask` lets us name one or more bits within a register. `RegisterMask` lets us name one or more bits within a register.
To name our two LEDs, which are only controlled by single bits, we write: To name our two LEDs, which are only controlled by single bits, we write:
@ -40,15 +40,16 @@ These calls can also be made through the register using template parameters:
PORTA_OUT::set<LED_2>(); PORTA_OUT::set<LED_2>();
``` ```
Registers can take multiple masks at once: Registers can take multiple masks at once too. The masks will be merged so that
the register is only read and written once:
```cpp ```cpp
PORTA_OUT::toggle<LED_1, LED_2>(); PORTA_OUT::toggle<LED_1, LED_2>();
``` ```
They also support a `modify` function, which takes a list of mask operations as A `modify` function is also supported, which takes a list of mask operations as
shown below. Through `modify`, the register is only read and written once, shown below. This allows the different operations to be carried out together,
minimizing I/O. still keeping to a single register read and write:
```cpp ```cpp
PORTA_OUT::modify<LED_1::set, LED_2::clear>(); // Only have LED_1 turned on PORTA_OUT::modify<LED_1::set, LED_2::clear>(); // Only have LED_1 turned on
@ -57,7 +58,7 @@ PORTA_OUT::modify<LED_1::set, LED_2::clear>(); // Only have LED_1 turned on
What if we need to add a third LED? And what if that LED is on a different What if we need to add a third LED? And what if that LED is on a different
register, PORTB? register, PORTB?
This is what you could do: This is where `RegisterGroup` comes in handy:
```cpp ```cpp
using PORTB_OUT = fr::MemRegister<uint8_t, 0x0041>; using PORTB_OUT = fr::MemRegister<uint8_t, 0x0041>;
@ -68,10 +69,9 @@ using LED_3 = fr::RegisterMask<PORTB_OUT, (1 << 5)>;
using LEDS = fr::RegisterGroup<PORTA_OUT, PORTB_OUT>; using LEDS = fr::RegisterGroup<PORTA_OUT, PORTB_OUT>;
``` ```
By defining a `RegisterGroup`, we can make the same calls to modify the LEDs as By grouping the two registers, we can carry out our modification calls without
we would with the single register. `RegisterGroup` will direct masks to their worrying about which mask is for what register. The `RegisterGroup` will take
appropriate registers, while merging operations on the same register to of that, while still merging operations when possible to maintain minimal I/O:
maintain that minimal I/O:
```cpp ```cpp
LEDS::clear<LED_1, LED_2, LED_3>(); LEDS::clear<LED_1, LED_2, LED_3>();
@ -98,8 +98,8 @@ CLOCK_DIV::write<0x03>();
``` ```
This will read the register's current value, clear all bits selected by the This will read the register's current value, clear all bits selected by the
mask, bitwise-OR the value `0x03` to the mask's location, then write the new mask, set the new value `0x03` in the mask's location, then update the
value to the register. register.
`write` can also be included in `modify` chains: `write` can also be included in `modify` chains:
@ -107,13 +107,13 @@ value to the register.
CLOCK_CONTROL::modify<CLOCK_DIV::write<0x03>, CLOCK_ENABLE::set>(); CLOCK_CONTROL::modify<CLOCK_DIV::write<0x03>, CLOCK_ENABLE::set>();
``` ```
You may also define a `RegisterMaskValue` to name a specific value: A `RegisterMaskValue` can also be defined to identify specific values:
```cpp ```cpp
using CLOCK_DIV4 = fr::RegisterMaskValue<CLOCK_DIV, 0x03>; using CLOCK_DIV4 = fr::RegisterMaskValue<CLOCK_DIV, 0x03>;
``` ```
Three functions are supported for `RegisterMaskValue`: `set`, which would call `RegisterMaskValue` supports three functions: `set`, which would call
`CLOCK_DIV::write<0x03>()`; `clear`, which clears the masked bits; and `test`, `CLOCK_DIV::write<0x03>()`; `clear`, which clears the masked bits; and `test`,
which would confirm that the register contains the value `0x03` in the masked which would confirm that the register contains the value `0x03` in the masked
bits' location. bits' location.
@ -122,7 +122,7 @@ bits' location.
"External" registers are registers that are not memory-mapped. These are also "External" registers are registers that are not memory-mapped. These are also
supported in *funreg*, and can even be placed in `RegisterGroup`s with supported in *funreg*, and can even be placed in `RegisterGroup`s with
memory-mapped or other register types. other register types.
An "access type" must be defined to specify how the register is accessed. Here An "access type" must be defined to specify how the register is accessed. Here
is the definition of `MemoryIO`, which is used for memory-mapped registers: is the definition of `MemoryIO`, which is used for memory-mapped registers:

@ -1,16 +1,34 @@
# funreg: Functional Memory-mapped Register I/O # funreg: Functional Register I/O using modern C++
*funreg* provides a functional approach to operating on memory-mapped registers *funreg* provides a functional approach to interacting with registers.
with zero overhead. This library primarily targets embedded firmware, where The library includes support for memory-mapped registers; however, other types
these types of operations are frequently encountered. of registers can be supported through creating a simple access interface.
What makes this library unique is its ability to carry out multiple register A unique feature of this library is its ability to handle multiple register
operations with a single function call, reducing this to a single register read operations with a single function call; these operations will be merged
and write. Further, registers can be organized into "groups": these groups can together so that the register is only read and written once.
receive a list of operations for any of the contained registers, and will
optimize down to a single read and write for each register.
A tutorial or guide will be added soon. Registers may also be organized into groups. These groups can similarly receive
a list of operations, which will be directed the to the appropriate registers
for the same single-read-single-write process.
For example, LEDs can be controlled by a microcontroller with a single call:
```cpp
LEDS::modify<LED1::set, LED2::clear, LED3::set>();
```
...no matter if the LEDs use different registers, or if any of them are
controlled by an external circuit rather than a built-in IO peripheral.
See `GUIDE.md` for a walk-through of the available functionality.
## Feature overview
* Define registers of any size, at any address, with optional custom access interface
* Define register masks to name the bits of registers
* Define register groups so ease programming (e.g. define an `RTC` group to work with all real-time clock registers at once)
* Make modifications through groups, masks, or the registers directly
## Requirements ## Requirements

Loading…
Cancel
Save