Skip to content

Commit 0e9f50f

Browse files
authored
Merge pull request #165 from japaric/v12
v0.12.0
2 parents 92067f7 + 73dd3ca commit 0e9f50f

File tree

4 files changed

+138
-81
lines changed

4 files changed

+138
-81
lines changed

CHANGELOG.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
## [v0.12.0] - 2018-01-15
11+
12+
### Changed
13+
14+
- Functions are now marked as `#[inline]` instead of as `#[inline(always)]`.
15+
16+
- Registers specified as arrays in SVD files are now being translated into Rust array in simple
17+
cases.
18+
19+
- When CPU information is not declared in the SVD file assume that the CPU is an ARMv6-M CPU (the
20+
lowest common denominator). This only applies when the target is the Cortex-M architecture.
21+
22+
- [breaking-change] Peripherals are now exposed as scoped singletons, instead of as global
23+
singletons.
24+
1025
## [v0.11.4] - 2017-09-08
1126

1227
### Fixed
@@ -302,7 +317,8 @@ peripheral.register.write(|w| w.field().set());
302317

303318
- Initial version of the `svd2rust` tool
304319

305-
[Unreleased]: https://github.com/japaric/svd2rust/compare/v0.11.4...HEAD
320+
[Unreleased]: https://github.com/japaric/svd2rust/compare/v0.12.0...HEAD
321+
[v0.12.0]: https://github.com/japaric/svd2rust/compare/v0.11.4...v0.12.0
306322
[v0.11.4]: https://github.com/japaric/svd2rust/compare/v0.11.3...v0.11.4
307323
[v0.11.3]: https://github.com/japaric/svd2rust/compare/v0.11.2...v0.11.3
308324
[v0.11.2]: https://github.com/japaric/svd2rust/compare/v0.11.1...v0.11.2

ci/script.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ main() {
3535
# test crate
3636
cargo init --name foo $td
3737
echo 'bare-metal = "0.1.0"' >> $td/Cargo.toml
38-
echo 'cortex-m = { git = "https://github.com/japaric/cortex-m" }' >> $td/Cargo.toml
38+
echo 'cortex-m = "0.4.0"' >> $td/Cargo.toml
3939
echo 'cortex-m-rt = "0.3.0"' >> $td/Cargo.toml
4040
echo 'vcell = "0.1.0"' >> $td/Cargo.toml
4141

src/generate.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub fn device(d: &Device, target: &Target, items: &mut Vec<Tokens>) -> Result<()
8686
::generate::interrupt(d, target, &d.peripherals, items);
8787

8888
const CORE_PERIPHERALS: &[&str] = &[
89+
"CBP",
8990
"CPUID",
9091
"DCB",
9192
"DWT",
@@ -106,13 +107,19 @@ pub fn device(d: &Device, target: &Target, items: &mut Vec<Tokens>) -> Result<()
106107
pub use cortex_m::peripheral::Peripherals as CorePeripherals;
107108
});
108109

109-
for p in CORE_PERIPHERALS {
110-
let id = Ident::new(*p);
111-
112-
items.push(quote! {
113-
pub use cortex_m::peripheral::#id;
114-
});
115-
}
110+
// NOTE re-export only core peripherals available on *all* Cortex-M devices
111+
// (if we want to re-export all core peripherals available for the target then we are going
112+
// to need to replicate the `#[cfg]` stuff that cortex-m uses and that would require all
113+
// device crates to define the custom `#[cfg]`s that cortex-m uses in their build.rs ...)
114+
items.push(quote! {
115+
pub use cortex_m::peripheral::CPUID;
116+
pub use cortex_m::peripheral::DCB;
117+
pub use cortex_m::peripheral::DWT;
118+
pub use cortex_m::peripheral::MPU;
119+
pub use cortex_m::peripheral::NVIC;
120+
pub use cortex_m::peripheral::SCB;
121+
pub use cortex_m::peripheral::SYST;
122+
});
116123
}
117124

118125
for p in &d.peripherals {

src/lib.rs

Lines changed: 106 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,26 @@
3131
//! ```
3232
//! $ svd2rust -i STM32F30x.svd | rustfmt | tee src/lib.rs
3333
//! //! Peripheral access API for STM32F30X microcontrollers
34-
//! //! (generated using svd2rust v0.11.0)
34+
//! //! (generated using svd2rust v0.12.0)
3535
//!
3636
//! #![deny(missing_docs)]
3737
//! #![deny(warnings)]
3838
//! #![no_std]
3939
//!
40+
//! extern crate bare_metal;
4041
//! extern crate cortex_m;
42+
//! #[cfg(feature = "rt")]
4143
//! extern crate cortex_m_rt;
4244
//! extern crate vcell;
4345
//!
4446
//! use cortex_m::peripheral::Peripheral;
4547
//!
4648
//! /// Interrupts
4749
//! pub mod interrupt {
48-
//! ..
50+
//! // ..
4951
//! }
5052
//!
5153
//! /// General-purpose I/Os
52-
//! pub const GPIOA: Peripheral<GPIOA> = unsafe { Peripheral::new(1207959552) };
53-
//!
54-
//! /// General-purpose I/Os
5554
//! pub mod gpioa {
5655
//! pub struct RegisterBlock {
5756
//! /// GPIO port mode register
@@ -61,27 +60,25 @@
6160
//! ..
6261
//! }
6362
//!
64-
//! pub struct GPIOA {
65-
//! register_block: gpioa::RegisterBlock,
66-
//! }
67-
//!
6863
//! /// General-purpose I/Os
69-
//! pub const GPIOB: Peripheral<GPIOB> = unsafe { Peripheral::new(1207960576) };
64+
//! pub struct GPIOA { _marker: PhantomData<*const ()> }
7065
//!
71-
//! /// General-purpose I/Os
72-
//! pub mod gpiob {
73-
//! ..
74-
//! }
66+
//! unsafe impl Send for GPIOA {}
7567
//!
76-
//! pub struct GPIOB {
77-
//! register_block: gpiob::RegisterBlock,
68+
//! impl GPIOA {
69+
//! /// Returns a pointer to the register block
70+
//! pub fn ptr() -> *const gpioa::RegisterBlock {
71+
//! 0x4800_0000 as *const _
72+
//! }
7873
//! }
7974
//!
80-
//! /// GPIOC
81-
//! pub const GPIOC: Peripheral<GPIOC> = unsafe { Peripheral::new(1207961600) };
75+
//! impl core::ops::Deref for GPIOA {
76+
//! type Target = gpioa::RegisterBlock;
8277
//!
83-
//! /// Register block
84-
//! pub type GPIOC = GPIOB;
78+
//! fn deref(&self) -> &gpioa::RegisterBlock {
79+
//! unsafe { &*GPIOA::ptr() }
80+
//! }
81+
//! }
8582
//!
8683
//! // ..
8784
//! ```
@@ -92,9 +89,9 @@
9289
//!
9390
//! - [`bare-metal`](https://crates.io/crates/bare-metal) v0.1.x
9491
//! - [`vcell`](https://crates.io/crates/vcell) v0.1.x
95-
//! - [`cortex-m-rt`](https://crates.io/crates/cortex-m-rt) v0.3.x if targeting
92+
//! - [`cortex-m-rt`](https://crates.io/crates/cortex-m-rt) v0.4.x if targeting
9693
//! the Cortex-M architecture.
97-
//! - [`cortex-m`](https://crates.io/crates/cortex-m) v0.3.x if targeting the
94+
//! - [`cortex-m`](https://crates.io/crates/cortex-m) v0.4.x if targeting the
9895
//! Cortex-M architecture.
9996
//! - [`msp430`](https://crates.io/crates/msp430) v0.1.x if targeting the MSP430
10097
//! architecture.
@@ -103,17 +100,60 @@
103100
//!
104101
//! # Peripheral API
105102
//!
106-
//! In the root of the generated API, you'll find all the device peripherals as
107-
//! `const`ant `struct`s. You can access the register block behind the
108-
//! peripheral using either of these two methods:
103+
//! To use a peripheral first you must get an *instance* of the peripheral. All the device
104+
//! peripherals are modeled as singletons (there can only ever be, at most, one instance of any
105+
//! one of them) and the only way to get an instance of them is through the `Peripherals::take`
106+
//! method.
107+
//!
108+
//! ```
109+
//! fn main() {
110+
//! let mut peripherals = stm32f30x::Peripherals::take().unwrap();
111+
//! peripherals.GPIOA.odr.write(|w| w.bits(1));
112+
//! }
113+
//! ```
109114
//!
110-
//! - `get()` for `unsafe`, unsynchronized access to the peripheral, or
115+
//! This method can only be successfully called *once* -- that's why the method returns an `Option`.
116+
//! Subsequent calls to the method will result in a `None` value being returned.
111117
//!
112-
//! - `borrow()` which grants you exclusive access to the peripheral but can
113-
//! only be used within a critical section (`interrupt::free`).
118+
//! ```
119+
//! fn main() {
120+
//! let ok = stm32f30x::Peripherals::take().unwrap();
121+
//! let panics = stm32f30x::Peripherals::take().unwrap();
122+
//! }
123+
//! ```
124+
//!
125+
//! The singleton property can be *unsafely* bypassed using the `ptr` static method which is
126+
//! available on all the peripheral types. This method is a useful for implementing safe higher
127+
//! level abstractions.
128+
//!
129+
//! ```
130+
//! struct PA0 { _0: () }
131+
//! impl PA0 {
132+
//! fn is_high(&self) -> bool {
133+
//! // NOTE(unsafe) actually safe because this is an atomic read with no side effects
134+
//! unsafe { (*GPIOA::ptr()).idr.read().bits() & 1 != 0 }
135+
//! }
136+
//!
137+
//! fn is_low(&self) -> bool {
138+
//! !self.is_high()
139+
//! }
140+
//! }
141+
//! struct PA1 { _0: () }
142+
//! // ..
143+
//!
144+
//! fn configure(gpioa: GPIOA) -> (PA0, PA1, ..) {
145+
//! // configure all the PAx pins as inputs
146+
//! gpioa.moder.reset();
147+
//! // the GPIOA proxy is destroyed here now the GPIOA register block can't be modified
148+
//! // thus the configuration of the PAx pins is now frozen
149+
//! drop(gpioa);
150+
//! (PA0 { _0: () }, PA1 { _0: () }, ..)
151+
//! }
152+
//! ```
114153
//!
115-
//! The register block is basically a `struct` where each field represents a
116-
//! register.
154+
//! Each peripheral proxy `deref`s to a `RegisterBlock` struct that represents a piece of device
155+
//! memory. Each field in this `struct` represents one register in the register block associated to
156+
//! the peripheral.
117157
//!
118158
//! ```
119159
//! /// Inter-integrated circuit
@@ -148,10 +188,9 @@
148188
//!
149189
//! # `read` / `modify` / `write` API
150190
//!
151-
//! Each register in the register block, e.g. the `cr1` field in the `I2C`
152-
//! struct, exposes a combination of the `read`, `modify` and `write` methods.
153-
//! Which methods exposes each register depends on whether the register is
154-
//! read-only, read-write or write-only:
191+
//! Each register in the register block, e.g. the `cr1` field in the `I2C` struct, exposes a
192+
//! combination of the `read`, `modify` and `write` methods. Which methods exposes each register
193+
//! depends on whether the register is read-only, read-write or write-only:
155194
//!
156195
//! - read-only registers only expose the `read` method.
157196
//! - write-only registers only expose the `write` method.
@@ -165,7 +204,7 @@
165204
//! ``` rust
166205
//! impl CR2 {
167206
//! /// Modifies the contents of the register
168-
//! pub fn modify<F>(&mut self, f: F)
207+
//! pub fn modify<F>(&self, f: F)
169208
//! where
170209
//! for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W
171210
//! {
@@ -185,10 +224,9 @@
185224
//! }
186225
//! ```
187226
//!
188-
//! The `read` method "reads" the register using a **single**, volatile `LDR`
189-
//! instruction and returns a proxy `R` struct that allows access to only the
190-
//! readable bits (i.e. not to the reserved or write-only bits) of the `CR2`
191-
//! register:
227+
//! The `read` method "reads" the register using a **single**, volatile `LDR` instruction and
228+
//! returns a proxy `R` struct that allows access to only the readable bits (i.e. not to the
229+
//! reserved or write-only bits) of the `CR2` register:
192230
//!
193231
//! ``` rust
194232
//! /// Value read from the register
@@ -214,14 +252,13 @@
214252
//! }
215253
//! ```
216254
//!
217-
//! On the other hand, the `write` method writes some value to the register
218-
//! using a **single**, volatile `STR` instruction. This method involves a `W`
219-
//! struct that only allows constructing valid states of the `CR2` register.
255+
//! On the other hand, the `write` method writes some value to the register using a **single**,
256+
//! volatile `STR` instruction. This method involves a `W` struct that only allows constructing
257+
//! valid states of the `CR2` register.
220258
//!
221-
//! The only constructor that `W` provides is `reset_value` which returns the
222-
//! value of the `CR2` register after a reset. The rest of `W` methods are
223-
//! "builder-like" and can be used to modify the writable bitfields of the
224-
//! `CR2` register.
259+
//! The only constructor that `W` provides is `reset_value` which returns the value of the `CR2`
260+
//! register after a reset. The rest of `W` methods are "builder-like" and can be used to modify the
261+
//! writable bitfields of the `CR2` register.
225262
//!
226263
//! ``` rust
227264
//! impl CR2W {
@@ -238,10 +275,10 @@
238275
//! }
239276
//! ```
240277
//!
241-
//! The `write` method takes a closure with signature `(&mut W) -> &mut W`. If
242-
//! the "identity closure", `|w| w`, is passed then the `write` method will set
243-
//! the `CR2` register to its reset value. Otherwise, the closure specifies how
244-
//! the reset value will be modified *before* it's written to `CR2`.
278+
//! The `write` method takes a closure with signature `(&mut W) -> &mut W`. If the "identity
279+
//! closure", `|w| w`, is passed then the `write` method will set the `CR2` register to its reset
280+
//! value. Otherwise, the closure specifies how the reset value will be modified *before* it's
281+
//! written to `CR2`.
245282
//!
246283
//! Usage looks like this:
247284
//!
@@ -278,12 +315,10 @@
278315
//!
279316
//! # enumeratedValues
280317
//!
281-
//! If your SVD uses the `<enumeratedValues>` feature, then the API will be
282-
//! *extended* to provide even more type safety. This extension is backward
283-
//! compatible with the original version so you could "upgrade" your SVD by
284-
//! adding, yourself, `<enumeratedValues>` to it and then use `svd2rust` to
285-
//! re-generate a better API that doesn't break the existing code that uses
286-
//! that API.
318+
//! If your SVD uses the `<enumeratedValues>` feature, then the API will be *extended* to provide
319+
//! even more type safety. This extension is backward compatible with the original version so you
320+
//! could "upgrade" your SVD by adding, yourself, `<enumeratedValues>` to it and then use `svd2rust`
321+
//! to re-generate a better API that doesn't break the existing code that uses that API.
287322
//!
288323
//! The new `read` API returns an enum that you can match:
289324
//!
@@ -323,8 +358,8 @@
323358
//! }
324359
//! ```
325360
//!
326-
//! And the new `write` API provides similar additions as well: `variant` lets
327-
//! you pick the value to write from an `enum`eration of the possible ones:
361+
//! And the new `write` API provides similar additions as well: `variant` lets you pick the value to
362+
//! write from an `enum`eration of the possible ones:
328363
//!
329364
//! ```
330365
//! // enum DIRW { Input, Output }
@@ -348,31 +383,30 @@
348383
//!
349384
//! # Interrupt API
350385
//!
351-
//! SVD files also describe the device interrupts. svd2rust generated crates
352-
//! expose an enumeration of the device interrupts as an `Interrupt` `enum` in
353-
//! the root of the crate. This `enum` can be used with the `cortex-m` crate
354-
//! `NVIC` API.
386+
//! SVD files also describe the device interrupts. svd2rust generated crates expose an enumeration
387+
//! of the device interrupts as an `Interrupt` `enum` in the root of the crate. This `enum` can be
388+
//! used with the `cortex-m` crate `NVIC` API.
355389
//!
356390
//! ```
357391
//! extern crate cortex_m;
392+
//! extern crate stm32f30x;
358393
//!
359394
//! use cortex_m::interrupt;
360-
//! use cortex_m::peripheral::NVIC;
395+
//! use cortex_m::peripheral::Peripherals;
396+
//! use stm32f30x::Interrupt;
361397
//!
362-
//! interrupt::free(|cs| {
363-
//! let nvic = NVIC.borrow(cs);
398+
//! let p = Peripherals::take().unwrap();
399+
//! let mut nvic = p.NVIC;
364400
//!
365-
//! nvic.enable(Interrupt::TIM2);
366-
//! nvic.enable(Interrupt::TIM3);
367-
//! });
401+
//! nvic.enable(Interrupt::TIM2);
402+
//! nvic.enable(Interrupt::TIM3);
368403
//! ```
369404
//!
370405
//! ## the "rt" feature
371406
//!
372-
//! If the "rt" Cargo feature of the svd2rust generated crate is enabled the
373-
//! crate will populate the part of the vector table that contains the interrupt
374-
//! vectors and provide an [`interrupt!`](macro.interrupt.html) macro that can
375-
//! be used to register interrupt handlers.
407+
//! If the "rt" Cargo feature of the svd2rust generated crate is enabled the crate will populate the
408+
//! part of the vector table that contains the interrupt vectors and provide an
409+
//! [`interrupt!`](macro.interrupt.html) macro that can be used to register interrupt handlers.
376410
377411
// NOTE This file is for documentation only
378412

0 commit comments

Comments
 (0)