1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
//! Peripheral API generator from [CMSIS-SVD] files //! //! [CMSIS-SVD]: http://www.keil.com/pack/doc/CMSIS/SVD/html/index.html //! //! A SVD file is an XML file that describes the hardware features of a //! microcontroller. In particular, it list all the peripherals available to the //! device, where the registers associated to each device are located in memory //! and what's the function of each register. //! //! `svd2rust` is a command line tool that transforms SVD files into crates that //! expose a type safe API to access the peripherals of the device. //! //! # Installation //! //! ``` //! $ cargo install svd2rust //! ``` //! //! # Usage //! //! `svd2rust` supports Cortex-M and MSP430 microcontrollers. The generated //! crate can be tailored for either architecture using the `--target` flag. The //! flag accepts "cortex-m", "msp430" and "none" as values. "none" can be used //! to generate a crate that's architecture agnostic and that should work for //! architectures that `svd2rust` doesn't currently know about like the Cortex-A //! architecture. //! //! If the `--target` flag is omitted `svd2rust` assumes the target is the //! Cortex-M architecture. //! //! ``` //! $ svd2rust -i STM32F30x.svd | rustfmt | tee src/lib.rs //! //! Peripheral access API for STM32F30X microcontrollers //! //! (generated using svd2rust v0.11.0) //! //! #![deny(missing_docs)] //! #![deny(warnings)] //! #![no_std] //! //! extern crate cortex_m; //! extern crate cortex_m_rt; //! extern crate vcell; //! //! use cortex_m::peripheral::Peripheral; //! //! /// Interrupts //! pub mod interrupt { //! .. //! } //! //! /// General-purpose I/Os //! pub const GPIOA: Peripheral<GPIOA> = unsafe { Peripheral::new(1207959552) }; //! //! /// General-purpose I/Os //! pub mod gpioa { //! pub struct RegisterBlock { //! /// GPIO port mode register //! pub moder: MODER, //! .. //! } //! .. //! } //! //! pub struct GPIOA { //! register_block: gpioa::RegisterBlock, //! } //! //! /// General-purpose I/Os //! pub const GPIOB: Peripheral<GPIOB> = unsafe { Peripheral::new(1207960576) }; //! //! /// General-purpose I/Os //! pub mod gpiob { //! .. //! } //! //! pub struct GPIOB { //! register_block: gpiob::RegisterBlock, //! } //! //! /// GPIOC //! pub const GPIOC: Peripheral<GPIOC> = unsafe { Peripheral::new(1207961600) }; //! //! /// Register block //! pub type GPIOC = GPIOB; //! //! // .. //! ``` //! //! # Dependencies //! //! The generated crate depends on: //! //! - [`bare-metal`](https://crates.io/crates/bare-metal) v0.1.x //! - [`vcell`](https://crates.io/crates/vcell) v0.1.x //! - [`cortex-m-rt`](https://crates.io/crates/cortex-m-rt) v0.3.x if targeting //! the Cortex-M architecture. //! - [`cortex-m`](https://crates.io/crates/cortex-m) v0.3.x if targeting the //! Cortex-M architecture. //! - [`msp430`](https://crates.io/crates/msp430) v0.1.x if targeting the MSP430 //! architecture. //! - [`msp430-rt`](https://crates.io/crates/msp430-rt) v0.1.x if targeting the //! MSP430 architecture. //! //! # Peripheral API //! //! In the root of the generated API, you'll find all the device peripherals as //! `const`ant `struct`s. You can access the register block behind the //! peripheral using either of these two methods: //! //! - `get()` for `unsafe`, unsynchronized access to the peripheral, or //! //! - `borrow()` which grants you exclusive access to the peripheral but can //! only be used within a critical section (`interrupt::free`). //! //! The register block is basically a `struct` where each field represents a //! register. //! //! ``` //! /// Inter-integrated circuit //! pub mod i2c1 { //! /// Register block //! pub struct RegisterBlock { //! /// 0x00 - Control register 1 //! pub cr1: CR1, //! /// 0x04 - Control register 2 //! pub cr2: CR2, //! /// 0x08 - Own address register 1 //! pub oar1: OAR1, //! /// 0x0c - Own address register 2 //! pub oar2: OAR2, //! /// 0x10 - Timing register //! pub timingr: TIMINGR, //! /// Status register 1 //! pub timeoutr: TIMEOUTR, //! /// Interrupt and Status register //! pub isr: ISR, //! /// 0x1c - Interrupt clear register //! pub icr: ICR, //! /// 0x20 - PEC register //! pub pecr: PECR, //! /// 0x24 - Receive data register //! pub rxdr: RXDR, //! /// 0x28 - Transmit data register //! pub txdr: TXDR, //! } //! } //! ``` //! //! # `read` / `modify` / `write` API //! //! Each register in the register block, e.g. the `cr1` field in the `I2C` //! struct, exposes a combination of the `read`, `modify` and `write` methods. //! Which methods exposes each register depends on whether the register is //! read-only, read-write or write-only: //! //! - read-only registers only expose the `read` method. //! - write-only registers only expose the `write` method. //! - read-write registers expose all the methods: `read`, `modify` and //! `write`. //! //! This is signature of each of these methods: //! //! (using `I2C`'s `CR2` register as an example) //! //! ``` rust //! impl CR2 { //! /// Modifies the contents of the register //! pub fn modify<F>(&mut self, f: F) //! where //! for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W //! { //! .. //! } //! //! /// Reads the contents of the register //! pub fn read(&self) -> R { .. } //! //! /// Writes to the register //! pub fn write<F>(&mut self, f: F) //! where //! F: FnOnce(&mut W) -> &mut W, //! { //! .. //! } //! } //! ``` //! //! 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: //! //! ``` rust //! /// Value read from the register //! impl R { //! /// Bit 0 - Slave address bit 0 (master mode) //! pub fn sadd0(&self) -> SADD0R { .. } //! //! /// Bits 1:7 - Slave address bit 7:1 (master mode) //! pub fn sadd1(&self) -> SADD1R { .. } //! //! (..) //! } //! ``` //! //! Usage looks like this: //! //! ``` rust //! // is the SADD0 bit of the CR2 register set? //! if i2c1.c2r.read().sadd0().bit() { //! // yes //! } else { //! // no //! } //! ``` //! //! 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. //! //! ``` rust //! impl CR2W { //! /// Reset value //! pub fn reset_value() -> Self { //! CR2W { bits: 0 } //! } //! //! /// Bits 1:7 - Slave address bit 7:1 (master mode) //! pub fn sadd1(&mut self) -> _SADD1W { .. } //! //! /// Bit 0 - Slave address bit 0 (master mode) //! pub fn sadd0(&mut self) -> SADD0R { .. } //! } //! ``` //! //! The `write` method takes a closure with signature `(&mut W) -> &mut W`. If //! the "identity closure", `|w| w`, is passed then the `write` method will set //! the `CR2` register to its reset value. Otherwise, the closure specifies how //! the reset value will be modified *before* it's written to `CR2`. //! //! Usage looks like this: //! //! ``` rust //! // Starting from the reset value, `0x0000_0000`, change the bitfields SADD0 //! // and SADD1 to `1` and `0b0011110` respectively and write that to the //! // register CR2. //! i2c1.cr2.write(|w| unsafe { w.sadd0().bit(true).sadd1().bits(0b0011110) }); //! // NOTE ^ unsafe because you could be writing a reserved bit pattern into //! // the register. In this case, the SVD doesn't provide enough information to //! // check whether that's the case. //! //! // NOTE The argument to `bits` will be *masked* before writing it to the //! // bitfield. This makes it impossible to write, for example, `6` to a 2-bit //! // field; instead, `6 & 3` (i.e. `2`) will be written to the bitfield. //! ``` //! //! 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 //! register. This method accepts a closure that specifies how the CR2 register //! will be modified (the `w` argument) and also provides access to the state of //! the register before it's modified (the `r` argument). //! //! Usage looks like this: //! //! ``` rust //! // Set the START bit to 1 while KEEPING the state of the other bits intact //! i2c1.cr2.modify(|_, w| unsafe { w.start().bit(true) }); //! //! // TOGGLE the STOP bit, all the other bits will remain untouched //! i2c1.cr2.modify(|r, w| w.stop().bit(!r.stop().bit())); //! ``` //! //! # enumeratedValues //! //! If your SVD uses the `<enumeratedValues>` feature, then the API will be //! *extended* to provide even more type safety. This extension is backward //! compatible with the original version so you could "upgrade" your SVD by //! adding, yourself, `<enumeratedValues>` to it and then use `svd2rust` to //! re-generate a better API that doesn't break the existing code that uses //! that API. //! //! The new `read` API returns an enum that you can match: //! //! ``` //! match gpioa.dir.read().pin0() { //! gpioa::dir::PIN0R::Input => { .. }, //! gpioa::dir::PIN0R::Output => { .. }, //! } //! ``` //! //! or test for equality //! //! ``` //! if gpioa.dir.read().pin0() == gpio::dir::PIN0R::Input { //! .. //! } //! ``` //! //! It also provides convenience methods to check for a specific variant without //! having to import the enum: //! //! ``` //! if gpioa.dir.read().pin0().is_input() { //! .. //! } //! //! if gpioa.dir.read().pin0().is_output() { //! .. //! } //! ``` //! //! The original `bits` method is available as well: //! //! ``` //! if gpioa.dir.read().pin0().bits() == 0 { //! .. //! } //! ``` //! //! And the new `write` API provides similar additions as well: `variant` lets //! you pick the value to write from an `enum`eration of the possible ones: //! //! ``` //! // enum DIRW { Input, Output } //! gpioa.dir.write(|w| w.pin0().variant(gpio::dir::PIN0W::Output)); //! ``` //! //! There are convenience methods to pick one of the variants without having to //! import the enum: //! //! ``` //! gpioa.dir.write(|w| w.pin0().output()); //! ``` //! //! The `bits` (or `bit`) method is still available but will become safe if it's //! impossible to write a reserved bit pattern into the register: //! //! ``` //! // safe because there are only two options: `0` or `1` //! gpioa.dir.write(|w| w.pin0().bit(true)); //! ``` //! //! # Interrupt API //! //! SVD files also describe the device interrupts. svd2rust generated crates //! expose an enumeration of the device interrupts as an `Interrupt` `enum` in //! the root of the crate. This `enum` can be used with the `cortex-m` crate //! `NVIC` API. //! //! ``` //! extern crate cortex_m; //! //! use cortex_m::interrupt; //! use cortex_m::peripheral::NVIC; //! //! interrupt::free(|cs| { //! let nvic = NVIC.borrow(cs); //! //! nvic.enable(Interrupt::TIM2); //! nvic.enable(Interrupt::TIM3); //! }); //! ``` //! //! ## the "rt" feature //! //! If the "rt" Cargo feature of the svd2rust generated crate is enabled the //! crate will populate the part of the vector table that contains the interrupt //! vectors and provide an [`interrupt!`](macro.interrupt.html) macro that can //! be used to register interrupt handlers. // NOTE This file is for documentation only /// Assigns a handler to an interrupt /// /// This macro takes two arguments: the name of an interrupt and the path to the /// function that will be used as the handler of that interrupt. That function /// must have signature `fn()`. /// /// Optionally, a third argument may be used to declare interrupt local data. /// The handler will have exclusive access to these *local* variables on each /// invocation. If the third argument is used then the signature of the handler /// function must be `fn(&mut $NAME::Locals)` where `$NAME` is the first argument /// passed to the macro. /// /// # Example /// /// ``` ignore /// interrupt!(TIM2, periodic); /// /// fn periodic() { /// print!("."); /// } /// /// interrupt!(TIM3, tick, locals: { /// tick: bool = false; /// }); /// /// fn tick(locals: &mut TIM3::Locals) { /// locals.tick = !locals.tick; /// /// if locals.tick { /// println!("Tick"); /// } else { /// println!("Tock"); /// } /// } /// ``` #[macro_export] macro_rules! interrupt { ($NAME:ident, $path:path) => {}; ($NAME:ident, $path:path, locals: { $($lvar:ident: $lty:ty = $lval:expr;)+ }) => {}; }