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
//! Peripheral is a group of [`memory-mapped registers`](reg) or their fields. //! //! # Singular Peripheral //! //! Singular peripheral is a unique group of registers or their fields that have //! a common purpose. Here is an example of how to define and use it: //! //! ``` //! # #![feature(proc_macro_hygiene)] //! # use drone_core::reg; //! # use drone_core::reg::prelude::*; //! # reg!(pub mod RCC APB1ENR1; 0 32 0; RTCAPBEN { 0 1 }); //! # reg!(pub mod RTC TR; 0 32 0;); //! # reg!(pub mod RTC DR; 0 32 0;); //! # reg!(pub mod RTC CR; 0 32 0;); //! # reg::tokens! { //! # macro reg_tokens; crate; crate; //! # mod RCC { APB1ENR1; } //! # mod RTC { TR; DR; CR; } //! # } //! # reg_tokens!(struct Regs;); //! use core::mem::size_of_val; //! use drone_core::periph; //! //! periph::singular! { //! /// Extracts RTC register tokens. //! pub macro periph_rtc; //! /// Real-Time Clock peripheral. //! pub struct RtcPeriph; //! //! // Path prefix to reach registers. //! crate; //! // Absolute path to the current module. //! crate; //! //! // In the register block RCC... //! RCC { //! // In the register APB1ENR1... //! APB1ENR1 { //! // Map the single field RTCAPBEN. Other fields in this register //! // could be used by other peripherals. //! RTCAPBEN; //! } //! } //! // In the register block RTC... //! RTC { //! // Map the whole registers TR, DR, and CR. //! TR; //! DR; //! CR; //! } //! } //! //! // This will expand to the struct and the macro below: //! //! # mod _scope { //! # use super::*; //! /// Real-Time Clock. //! pub struct RtcPeriph { //! pub rcc_apb1enr1_rtcapben: rcc::apb1enr1::Rtcapben<Srt>, //! pub rtc_tr: rtc::Tr<Srt>, //! pub rtc_dr: rtc::Dr<Srt>, //! pub rtc_cr: rtc::Cr<Srt>, //! } //! //! /// Extracts RTC register tokens. //! macro_rules! periph_rtc { //! ($reg:ident) => { //! RtcPeriph { //! rcc_apb1enr1_rtcapben: $reg.rcc_apb1enr1.rtcapben, //! rtc_tr: $reg.rtc_tr, //! rtc_dr: $reg.rtc_dr, //! rtc_cr: $reg.rtc_cr, //! } //! }; //! } //! # } //! //! // Here is how to use it in your `trunk` thread: //! //! fn trunk(reg: Regs) { //! let rtc = periph_rtc!(reg); //! assert_eq!(size_of_val(&rtc), 0); //! } //! //! # fn main() { trunk(unsafe { drone_core::token::Token::take()} ); } //! ``` //! //! # Generic Peripheral //! //! Often there are multiple peripherals of a single type. For example in //! STM32L4S9 microcontroller there are USART1, USART2, USART3, UART4, UART5, //! and LPUART1. Most of their registers are the same, but also there are some //! differences. USART1, USART2, USART3 support synchronous transmission, and //! LPUART1 can function in low-power modes. However their drivers would have //! many functions in common. For this reason we map those peripheral registers //! together in a generic structure, and also map their differences. Here is an //! example: //! //! ``` //! # #![feature(proc_macro_hygiene)] //! # use drone_core::reg; //! # use drone_core::reg::prelude::*; //! # reg!(pub mod RCC APB1ENR1; 0 32 0 RReg WReg; UART4EN { 0 1 RRRegField WWRegField } //! # UARTRST { 0 1 RRRegField WWRegField }); //! # reg!(pub mod UART4 CR1; 0 32 0 RReg WReg; CMIE { 0 1 RRRegField WWRegField }); //! # reg!(pub mod UART4 RTOR; 0 32 0 RReg WReg; BLEN { 0 2 RRRegField WWRegField }); //! # reg::tokens! { //! # macro reg_tokens; crate; crate; //! # mod RCC { APB1ENR1; } //! # mod UART4 { CR1; RTOR; } //! # } //! # reg_tokens!(struct Regs;); //! # fn main() {} //! use drone_core::{periph, reg::marker::*}; //! //! // Here we define the generic UART peripheral. //! periph! { //! /// Generic Universal Asynchronous Receiver/Transmitter peripheral variant. //! pub trait UartMap { //! // Concrete UART peripherals will implement this trait. Arbitrary code //! // can be placed here. //! } //! // This will be the peripheral struct with public fields corresponding to //! // registers and/or register fields. The signature is //! // `struct UartPeriph<T: UartMap>`. //! /// Generic Universal Asynchronous Receiver/Transmitter peripheral. //! pub struct UartPeriph; //! //! // With RCC namespace... //! RCC { //! APBENR { //! // We need to declare the size of the register and its properties. //! // `RwReg` is a marker trait from `drone_core::reg::marker`, and it //! // means this is a read-write register. `Shared` is a special //! // property, which means the peripheral will not own the whole //! // register, but will own only a part of its fields. //! 0x20 RwReg Shared; //! // All peripherals will have UARTEN field. Again, `RwRwRegFieldBit` //! // is a marker trait from `drone_core::reg::marker`, and it means //! // this is a read-write single-bit field. //! UARTEN { RwRwRegFieldBit } //! // This is an optional field. Not all concrete peripherals will have //! // it. //! UARTRST { RwRwRegFieldBit Option } //! } //! } //! // Actually there is no UART register block. There are USART1, USART2, //! // USART3 and so on. This namespace is virtual; concrete peripherals //! // will map actual blocks to this namespace. //! UART { //! CR1 { //! 0x20 RwReg; //! CMIE { RwRwRegFieldBit } //! EOBIE { RwRwRegFieldBit Option } //! } //! RTOR { //! // This is an optional register. //! 0x20 RwReg Option; //! BLEN { RwRwRegFieldBits } //! // And this is an optional field of the optional register. //! RTO { RwRwRegFieldBits Option } //! } //! } //! } //! //! // Here we define the concrete UART4 peripheral. //! periph::map! { //! // Extracts UART4 register tokens. //! pub macro periph_uart4; //! // UART4 peripheral variant. //! pub struct Uart4; //! //! impl UartMap for Uart4 { //! // If `UartMap` defined some items, they should be implemented here. //! } //! //! // Path prefix to reach registers. //! crate; //! // Absolute path to the current module. //! crate; //! //! RCC { //! APBENR { //! // Here we provide the real name of the register - APB1ENR1. And //! // also the special properties like `Shared` or `Option`. //! APB1ENR1 Shared; //! // Again, we provide the real name of the field. //! UARTEN { UART4EN } //! // If the name is the same, we should provide it. Also if an //! // optional field present, we should mark it with `Option`. //! UARTRST { UARTRST Option } //! } //! } //! UART { //! // The real name of the block of registers. //! UART4; //! CR1 { //! CR1; //! CMIE { CMIE } //! // If the optional field absent, we should mention it like this. //! EOBIE {} //! } //! RTOR { //! RTOR Option; //! BLEN { BLEN } //! RTO {} //! } //! } //! } //! //! // Here is how we define a function generic over all variants of the peripheral. //! // Optional fields will not be available even if the concrete peripheral has them. //! fn basic_fields<T: UartMap>(uart: UartPeriph<T>) {} //! //! // Here is a generic function over peripherals that have all optional fields. //! fn opt_fields<T>(uart: UartPeriph<T>) //! where //! T: UartMap + RccApbenrUartrst + UartCr1Eobie + UartRtorRto, //! { //! } //! ``` /// Implements the generic peripheral. /// /// See [the module level documentation](self) for details. #[doc(inline)] pub use drone_core_macros::periph_map as map; /// Defines a singular peripheral. /// /// See [the module level documentation](self) for details. #[doc(inline)] pub use drone_core_macros::periph_singular as singular;