[−][src]Module drone_cortex_m::reg
The Memory-Mapped Registers module.
NOTE A Drone platform crate may re-export this module with its own additions under the same name, in which case it should be used instead.
A memory-mapped register is a special location in memory. Reads and writes
from/to this location produce side-effects. For example writing 1
or 0
to such location may set the related GPIO output pin to the high or low
logical level. In the same way reading from such location may return 1
or
0
depending on the input level of the related GPIO input pin. The most
basic way to deal with this memory is to use [core::ptr::read_volatile
]
and [core::ptr::write_volatile
]. Here is an example:
use core::ptr::{read_volatile, write_volatile}; // The address of GPIOA_CRL register. const GPIOA_CRL: usize = 0x4001_0800; // The offset for MODE2 field of GPIOA_CRL register. const GPIOA_CRL_MODE2_OFFSET: usize = 8; // The mask for MODE2 field of GPIOA_CRL register. const GPIOA_CRL_MODE2_MASK: u32 = 0x0000_0300; // Read the state of GPIOA_CRL register. The function is unsafe because it // can read from any location in memory. let mut gpioa_crl = unsafe { read_volatile(GPIOA_CRL as *const u32) }; // Do bit arithmetic to get the value of MODE2 field. let mut gpioa_crl_mode2 = (gpioa_crl & GPIOA_CRL_MODE2_MASK) >> GPIOA_CRL_MODE2_OFFSET; // Toggle some bits. gpioa_crl_mode2 ^= 0b10; // Do bit arithmetic to update the register value with the new field value. gpioa_crl = gpioa_crl & !GPIOA_CRL_MODE2_MASK | gpioa_crl_mode2 << GPIOA_CRL_MODE2_OFFSET; // Update the state of GPIOA_CRL register. The function is also unsafe // because it can write to any location in memory. unsafe { write_volatile(GPIOA_CRL as *mut u32, gpioa_crl) };
This way has numerous disadvantages: it's obscure, verbose, error-prone,
and requires unsafe
blocks. Also it has less obvious problems like lack of
thread-safety. This module provides safe and zero-cost abstractions to
this problem. As result the above example can be written like this:
gpioa_crl.modify(|r| r.write_mode2(r.mode2() ^ 0b10));
We abstract this type of memory with zero-sized [token
]s. (Familiarity
with [token
] module is required.) Only the code that have the token
instance for a particular memory-mapped register can manipulate it safely.
At the very base there is Register Field Token (like MODE2
in the above
example.) Register Field Tokens for a particular register grouped in
Register Token (like GPIO_CRL
in the above example.) And all available
Register Tokens are grouped in one Register Tokens Index.
API
The memory-mapped registers API is scattered across numerous traits.
Therefore it is recommended to use [reg::prelude
]:
use drone_core::reg::prelude::*;
Field Token
Field Width | Field Mode | Register Mode | |
---|---|---|---|
into_unsync | |||
into_sync | |||
into_copy | |||
as_sync | |||
load_val | read | read | |
default_val | write | write-only | |
store_val | write | write-only | |
store | write | write-only | |
read | one-bit | read | read |
read_bit | one-bit | read | read |
set | one-bit | write | write |
clear | one-bit | write | write |
toggle | one-bit | write | write |
set_bit | one-bit | write | write-only |
clear_bit | one-bit | write | write-only |
toggle_bit | one-bit | write | write-only |
read | multi-bit | read | read |
read_bits | multi-bit | read | read |
write | multi-bit | write | write |
write_bits | multi-bit | write | write-only |
Register Token
Mode | Tag | |
---|---|---|
into_unsync | ||
into_sync | ||
into_copy | ||
as_sync | ||
default_val | ||
default | ||
hold | ||
load_val | read | |
load | read | |
as_ptr | read | |
as_mut_ptr | write | |
store | write | Urt |
store | write | Srt, Crt |
store_val | write | Urt |
store_val | write | Srt, Crt |
reset | write | Urt |
reset | write | Srt, Crt |
modify | read-write | Urt |
Register Value
Autogenerated field methods for RegHold
(foo
as an
example field name):
Field Width | Mode | |
---|---|---|
foo() (read ) | one-bit | read |
foo() (read ) | multi-bit | read |
set_foo() (set ) | one-bit | write |
clear_foo() (clear ) | one-bit | write |
toggle_foo() (toggle ) | one-bit | write |
write_foo(bits) (write ) | multi-bit | write |
Tags
Each register or field token can have one of three flavors. They are encoded
by tag
s in their types. For example Reg<Urt>
, or
RegField<Srt>
.
Here are available tags and their properties:
Atomic | Affine | |
---|---|---|
Urt (Unsynchronized) | - | + |
Srt (Synchronized) | + | + |
Crt (Copyable) | + | - |
Atomic means the token uses more costly atomic operations, but could be shared between threads.
Non-atomic means the token uses less costly non-atomic operations, but couldn't be shared between threads.
Affine means the token can't be cloned or copied and uses move-semantics.
Non-affine means the token could be freely copied.
Tokens of some tags can be converted to the same tokens of other tags using
.into_unsync()
, .into_sync()
, .into_copy()
. Here is the conversion
matrix for register tokens:
from \ to | Urt | Srt | Crt |
---|---|---|---|
Urt | + | + | + |
Srt | + | + | + |
Crt | - | - | + |
And here is the conversion matrix for field tokens:
from \ to | Urt | Srt | Crt |
---|---|---|---|
Urt | + | - | - |
Srt | - | + | + |
Crt | - | - | + |
Mappings
We define concrete register mappings in platform crates. Usually the user doesn't need to map registers themselves. But lets have a look to an example of how it could be organized for STM32 platform:
use core::mem::size_of_val; use drone_core::{reg::prelude::*, token::Token}; use drone_core::reg; // ----- this is drone_cortex_m crate ----- // Registers belong to blocks. Here we declare CTRL register in STK block. reg! { // The output of this macro is `pub mod stk_ctrl { ... }`. /// SysTick control and status register. pub mod STK CTRL; 0xE000_E010 // the register address in memory 0x20 // size of the register in bits 0x0000_0000 // reset value of the register // Traits to implement for the register token. The most common sets are: // RReg RoReg - read-only register // RReg WReg - read-write register // WReg WoReg - write-only register RReg WReg; // Here we define register fields. /// Counter enable. ENABLE { 0 // the offset of the field 1 // the width of the field // Traits to implement for the field token. The most common sets are: // RRRegField RoRRegField - read-only field // RRRegField WWRegField - read-write field // WWRegField WoWRegField - read-write field RRRegField WWRegField } } // Here we define the register tokens index. Actually the result of this macro // is another macro, which can be used to define the final register token index // or to extend with another registers in downstream crates. It will become // clearer below. reg::tokens! { // The result of this macro is // `macro_rules! cortex_m_reg_tokens { ... }`. /// Defines an index of core ARM Cortex-M register tokens. pub macro cortex_m_reg_tokens; // Path prefix to reach registers. crate; // Absolute path to the current module. crate; // Here we declare all register blocks. This produces `pub mod stk { ... }` /// SysTick timer. pub mod STK { // Declare all registers for this block. This produces: // pub mod stk { // pub use crate::stk_ctrl as ctrl; // } CTRL; } } // ----- this is drone_stm32 crate ----- // This crate parses SVD files provided by the manufacturer and generates more // registers. // Same as above, except it will reuse the upstream macro, resulting in a // combined register tokens index. Note `use macro cortex_m_reg_tokens`. reg::tokens! { /// Defines an index of STM32F103 register tokens. pub macro stm32_reg_tokens; use macro cortex_m_reg_tokens; crate; crate; } // ----- this is an application crate ----- // This macro defines the concrete register tokens index for STM32 MCU. The // index is a sum of `drone_cortex_m` and `drone_stm32` registers. The result // of this macro is `pub struct Regs { ... }`. stm32_reg_tokens! { /// Register tokens. pub struct Regs; } // Your entry point. fn main() { // It's unsafe because we can accidentally create more than one instance // of the index. let reg = unsafe { Regs::take() }; // The index doesn't really exist in memory. assert_eq!(size_of_val(®), 0); assert_eq!(size_of_val(®.stk_ctrl), 0); assert_eq!(size_of_val(®.stk_ctrl.enable), 0); // Pass the index to your safe entry point. trunk(reg); } fn trunk(reg: Regs) {}
Modules
field | Memory-mapped register fields module. |
marker | Marker traits representing properties of memory-mapped registers. |
prelude | The Memory-Mapped Registers prelude. |
tag | Register token tags and their traits. |
Macros
tokens |