From fe275317313fb34425f2f8f6bc4a73fd5c33b8f0 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 4 Aug 2019 09:03:09 +0300 Subject: [PATCH] fix docs+examples, work without reset --- CHANGELOG.md | 10 ++++++-- src/generate/generic.rs | 55 ++++++++++++++++++++++++++++++++++++---- src/generate/register.rs | 32 ++++++++++++----------- src/lib.rs | 52 ++++++++++++++++++++++--------------- 4 files changed, 107 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8d4af1b..54e80295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `variant()` method for field reader and `Variant` enum for fields with reserved values +- Update documentation, add examples for register access methods + +- Add `write_with_zero` method for registers without reset value + ### Changed - - Field readers and writers use one enum where it is possible +- Field readers and writers use one enum where it is possible + +- Replace register and its reader/writer by generic types - - Replace register and its reader/writer by generic types +- Restore `unsafe` marker on register writer `bits()` method ## [v0.15.2] - 2019-07-29 diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 331ee56b..657ccaea 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -42,7 +42,16 @@ where { ///Reads the contents of `Readable` register /// - ///See [reading](https://rust-embedded.github.io/book/start/registers.html#reading) in book. + ///You can read the contents of a register in such way: + ///```ignore + ///let bits = periph.reg.read().bits(); + ///``` + ///or get the content of a particular field of a register. + ///```ignore + ///let reader = periph.reg.read(); + ///let bits = reader.field1().bits(); + ///let flag = reader.field2().bit_is_set(); + ///``` #[inline(always)] pub fn read(&self) -> R { R {bits: self.register.get(), _reg: marker::PhantomData} @@ -55,6 +64,8 @@ where U: Copy, { ///Writes the reset value to `Writable` register + /// + ///Resets the register to its initial state #[inline(always)] pub fn reset(&self) { self.register.set(Self::reset_value()) @@ -68,7 +79,19 @@ where { ///Writes bits to `Writable` register /// - ///See [writing](https://rust-embedded.github.io/book/start/registers.html#writing) in book. + ///You can write raw bits into a register: + ///```ignore + ///periph.reg.write(|w| unsafe { w.bits(rawbits) }); + ///``` + ///or write only the fields you need: + ///```ignore + ///periph.reg.write(|w| w + /// .field1().bits(newfield1bits) + /// .field2().set_bit() + /// .field3().variant(VARIANT) + ///); + ///``` + ///Other fields will have reset value. #[inline(always)] pub fn write(&self, f: F) where @@ -84,6 +107,8 @@ where U: Copy + Default { ///Writes Zero to `Writable` register + /// + ///Similar to `write`, but unused bits will contain 0. #[inline(always)] pub fn write_with_zero(&self, f: F) where @@ -100,7 +125,21 @@ where { ///Modifies the contents of the register /// - ///See [modifying](https://rust-embedded.github.io/book/start/registers.html#modifying) in book. + ///E.g. to do a read-modify-write sequence to change parts of a register: + ///```ignore + ///periph.reg.modify(|r, w| unsafe { w.bits( + /// r.bits() | 3 + ///) }); + ///``` + ///or + ///```ignore + ///periph.reg.modify(|_, w| w + /// .field1().bits(newfield1bits) + /// .field2().set_bit() + /// .field3().variant(VARIANT) + ///); + ///``` + ///Other fields will have value they had before call `modify`. #[inline(always)] pub fn modify(&self, f: F) where @@ -112,6 +151,9 @@ where } ///Register/field reader +/// +///Result of the [`read`](Reg::read) method of a register. +///Also it can be used in the [`modify`](Reg::read) method pub struct R { pub(crate) bits: U, _reg: marker::PhantomData, @@ -141,6 +183,7 @@ where U: PartialEq, FI: ToBits { + #[inline(always)] fn eq(&self, other: &FI) -> bool { self.bits.eq(&other._bits()) } @@ -165,16 +208,18 @@ impl R { } ///Register writer +/// +///Used as an argument to the closures in the [`write`](Reg::write) and [`modify`](Reg::modify) methods of the register pub struct W { ///Writable bits - pub bits: U, + pub(crate) bits: U, _reg: marker::PhantomData, } impl W { ///Writes raw bits to the register #[inline(always)] - pub fn bits(&mut self, bits: U) -> &mut Self { + pub unsafe fn bits(&mut self, bits: U) -> &mut Self { self.bits = bits; self } diff --git a/src/generate/register.rs b/src/generate/register.rs index 02b97961..42ccd0a0 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -54,26 +54,28 @@ pub fn render( } if can_write { - let rv = register - .reset_value - .or(defs.reset_value) - .map(|v| util::hex(v as u64)) - .ok_or_else(|| format!("Register {} has no reset value", register.name))?; - let desc = format!("Writer for register {}", register.name); - let doc = format!("Register {} `reset()`'s with value {}", register.name, &rv); mod_items.push(quote! { #[doc = #desc] pub type W = crate::W<#rty, super::#name_pc>; - #[doc = #doc] - impl crate::ResetValue for super::#name_pc { - type Type = #rty; - #[inline(always)] - fn reset_value() -> Self::Type { #rv } - } }); - methods.push("reset"); - methods.push("write"); + let res_val = register + .reset_value + .or(defs.reset_value) + .map(|v| util::hex(v as u64)); + if let Some(rv) = res_val { + let doc = format!("Register {} `reset()`'s with value {}", register.name, &rv); + mod_items.push(quote! { + #[doc = #doc] + impl crate::ResetValue for super::#name_pc { + type Type = #rty; + #[inline(always)] + fn reset_value() -> Self::Type { #rv } + } + }); + methods.push("reset"); + methods.push("write"); + } methods.push("write_with_zero"); } diff --git a/src/lib.rs b/src/lib.rs index 7445dc72..ba3cf142 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -226,8 +226,14 @@ //! .. //! } //! } +//! impl crate::ResetValue for CR2 { +//! type Type = u32; +//! fn reset_value() -> Self::Type { 0 } +//! } //! ``` //! +//! ## `read` +//! //! The `read` method "reads" the register using a **single**, volatile `LDR` instruction and //! returns a proxy `R` struct that allows access to only the readable bits (i.e. not to the //! reserved or write-only bits) of the `CR2` register: @@ -236,10 +242,10 @@ //! /// Value read from the register //! impl R { //! /// Bit 0 - Slave address bit 0 (master mode) -//! pub fn sadd0(&self) -> SADD0R { .. } +//! pub fn sadd0(&self) -> SADD0_R { .. } //! //! /// Bits 1:7 - Slave address bit 7:1 (master mode) -//! pub fn sadd1(&self) -> SADD1R { .. } +//! pub fn sadd1(&self) -> SADD1_R { .. } //! //! (..) //! } @@ -256,26 +262,30 @@ //! } //! ``` //! +//! ## `reset` +//! +//! The `ResetValue` trait provides `reset_value` which returns the value of the `CR2` +//! register after a reset. This value can be used to modify the +//! writable bitfields of the `CR2` register or reset it to its initial state. +//! Usage looks like this: +//! +//! ```ignore +//! if i2c1.c2r.write().reset() +//! ``` +//! +//! ## `write` +//! //! On the other hand, the `write` method writes some value to the register using a **single**, //! volatile `STR` instruction. This method involves a `W` struct that only allows constructing //! valid states of the `CR2` register. //! -//! The only constructor that `W` provides is `reset_value` which returns the value of the `CR2` -//! register after a reset. The rest of `W` methods are "builder-like" and can be used to modify the -//! writable bitfields of the `CR2` register. -//! //! ```ignore -//! impl CR2W { -//! /// Reset value -//! pub fn reset_value() -> Self { -//! CR2W { bits: 0 } -//! } -//! +//! impl W { //! /// Bits 1:7 - Slave address bit 7:1 (master mode) -//! pub fn sadd1(&mut self) -> _SADD1W { .. } +//! pub fn sadd1(&mut self) -> SADD1_W { .. } //! //! /// Bit 0 - Slave address bit 0 (master mode) -//! pub fn sadd0(&mut self) -> SADD0R { .. } +//! pub fn sadd0(&mut self) -> SADD0_W { .. } //! } //! ``` //! @@ -300,6 +310,8 @@ //! // field; instead, `6 & 3` (i.e. `2`) will be written to the bitfield. //! ``` //! +//! ## `modify` +//! //! Finally, the `modify` method performs a **single** read-modify-write //! operation that involves **one** read (`LDR`) to the register, modifying the //! value and then a **single** write (`STR`) of the modified value to the @@ -327,16 +339,16 @@ //! The new `read` API returns an enum that you can match: //! //! ```ignore -//! match gpioa.dir.read().pin0() { -//! gpioa::dir::PIN0R::Input => { .. }, -//! gpioa::dir::PIN0R::Output => { .. }, +//! match gpioa.dir.read().pin0().variant() { +//! gpioa::dir::PIN0_A::Input => { .. }, +//! gpioa::dir::PIN0_A::Output => { .. }, //! } //! ``` //! //! or test for equality //! //! ```ignore -//! if gpioa.dir.read().pin0() == gpio::dir::PIN0R::Input { +//! if gpioa.dir.read().pin0().variant() == gpio::dir::PIN0_A::Input { //! .. //! } //! ``` @@ -366,8 +378,8 @@ //! write from an `enum`eration of the possible ones: //! //! ```ignore -//! // enum DIRW { Input, Output } -//! gpioa.dir.write(|w| w.pin0().variant(gpio::dir::PIN0W::Output)); +//! // enum PIN0_A { Input, Output } +//! gpioa.dir.write(|w| w.pin0().variant(gpio::dir::PIN0_A::Output)); //! ``` //! //! There are convenience methods to pick one of the variants without having to