Module drone_core::reg[][src]

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 tokens. (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 WidthField ModeRegister Mode
into_unsync
into_sync
into_copy
as_sync
load_valreadread
default_valwritewrite-only
store_valwritewrite-only
storewritewrite-only
readone-bitreadread
read_bitone-bitreadread
setone-bitwritewrite
clearone-bitwritewrite
toggleone-bitwritewrite
set_bitone-bitwritewrite-only
clear_bitone-bitwritewrite-only
toggle_bitone-bitwritewrite-only
readmulti-bitreadread
read_bitsmulti-bitreadread
writemulti-bitwritewrite
write_bitsmulti-bitwritewrite-only

Register Token

ModeTag
into_unsync
into_sync
into_copy
as_sync
default_val
default
hold
loadread
load_valread
load_bitsread
as_ptrread
as_mut_ptrwrite
storewriteUrt
storewriteSrt, Crt
store_regwriteUrt
store_regwriteSrt, Crt
store_valwriteUrt
store_valwriteSrt, Crt
store_bitswriteUrt
store_bitswriteSrt, Crt
resetwriteUrt
resetwriteSrt, Crt
modifyread-writeUrt
modify_regread-writeUrt

Register Value

Autogenerated field methods for RegHold (foo as an example field name):

Field WidthMode
foo() (read)one-bitread
foo() (read)multi-bitread
set_foo() (set)one-bitwrite
clear_foo() (clear)one-bitwrite
toggle_foo() (toggle)one-bitwrite
write_foo(bits) (write)multi-bitwrite

Tags

Each register or field token can have one of three flavors. They are encoded by tags in their types. For example Reg<Urt>, or RegField<Srt>.

Here are available tags and their properties:

AtomicAffine
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 \ toUrtSrtCrt
Urt+++
Srt+++
Crt--+

And here is the conversion matrix for field tokens:

from \ toUrtSrtCrt
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! {
    // This macro will expand to a module: `pub mod stk_ctrl { ... }`.
    /// SysTick control and status register.
    pub STK CTRL => {
        address => 0xE000_E010; // the register address in memory
        size => 0x20;           // size of the register in bits
        reset => 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
        traits => { RReg WReg };

        // Register fields.
        fields => {
            /// Counter enable.
            ENABLE => {
                offset => 0; // offset of the field
                width => 1;  // 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
                traits => { 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.
    index => pub 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(&reg), 0);
    assert_eq!(size_of_val(&reg.stk_ctrl), 0);
    assert_eq!(size_of_val(&reg.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

assert_taken

Assert exclusive ownership of the register.

tokens

A macro to define a macro to define a set of register tokens.

Traits

RReg

Readable register.

Reg

The base trait for a memory-mapped register token.

RegHold

Exposed storage for register values.

RegRef

Connects Reg with RegHold.

RoReg

Read-only register.

RwRegUnsync

Non-atomic operations for read-write register.

WReg

Writable register.

WRegAtomic

Atomic operations for writable register.

WRegUnsync

Non-atomic operations for writable register.

WoReg

Write-only register.