├── .gitignore ├── Cargo.toml ├── README.md └── src ├── components ├── flash │ ├── acr.rs │ └── mod.rs ├── gpio │ ├── mod.rs │ └── stm32f7 │ │ ├── alternate_fn.rs │ │ ├── bit_set_reset.rs │ │ ├── input_data.rs │ │ ├── mod.rs │ │ ├── mode.rs │ │ ├── out_speed.rs │ │ ├── out_type.rs │ │ ├── output_data.rs │ │ └── resistor.rs ├── mod.rs ├── pwr │ ├── cr1.rs │ ├── csr1.rs │ └── mod.rs ├── rcc │ ├── ahb1_enr.rs │ ├── ahb1_rstr.rs │ ├── ahb3_enr.rs │ ├── ahb3_rstr.rs │ ├── apb1_enr.rs │ ├── apb2_enr.rs │ ├── cfgr.rs │ ├── cr.rs │ ├── dckcfgr1.rs │ ├── mod.rs │ ├── pll_cfgr.rs │ ├── plli2scfgr.rs │ └── pllsaicfgr.rs └── systick │ ├── csr.rs │ ├── cvr.rs │ ├── mod.rs │ └── rvr.rs ├── interfaces ├── gpio │ └── mod.rs └── mod.rs ├── irq.rs ├── lib.rs ├── runtime.rs └── util.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Marc Brinkmann ", "Philipp Oppermann "] 3 | description = "Work in progress embedded library; pre-release for single issue." 4 | license = "MIT/Apache-2.0" 5 | name = "embedded" 6 | version = "0.3.0" 7 | 8 | [dependencies] 9 | bit_field = "0.4.0" 10 | bitflags = "0.7.0" 11 | volatile = "0.2.0" 12 | 13 | [dependencies.arrayvec] 14 | version = "0.3.20" 15 | default-features = false 16 | 17 | [features] 18 | default = ["panic-fmt", "unwind-cpp"] 19 | panic-fmt = [] 20 | unwind-cpp = [] 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Rust embedded development 2 | ========================= 3 | 4 | The `embed` crates strives to make development on the embedded board safe and fun. It provides the minimal required runtime and abstractions for common hardware concepts as well as a library for some boards. 5 | 6 | 7 | Getting started 8 | --------------- 9 | 10 | The following are requisites for embedded development: 11 | 12 | 1. A working Rust nightly, [https://www.rustup.rs](rustup.rs) is highly recommeded. 13 | 2. A linker that can link for the target platform, like `arm-none-eabi-gcc`. 14 | 3. [Xargo](https://github.com/japaric/xargo), which can conveniently be installed through `cargo install xargo` 15 | -------------------------------------------------------------------------------- /src/components/flash/acr.rs: -------------------------------------------------------------------------------- 1 | //! Flash access control register (FLASH_ACR) 2 | 3 | #[derive(Debug, Clone, Copy)] 4 | pub struct Register(u32); 5 | 6 | impl Register { 7 | pub fn latency(&mut self) -> u32 { 8 | self.0 & 0b1111 9 | } 10 | 11 | pub fn set_latency(&mut self, latency: u32) { 12 | assert!(latency < 16); 13 | self.0 |= latency; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/flash/mod.rs: -------------------------------------------------------------------------------- 1 | //! FLASH registers 2 | 3 | use volatile::Volatile; 4 | 5 | pub mod acr; 6 | 7 | #[repr(C)] 8 | pub struct FlashBank { 9 | pub acr: Volatile, 10 | keyr: u32, 11 | opt_keyr: u32, 12 | sr: u32, 13 | 14 | // 0x10 15 | cr: u32, 16 | opt_cr: u32, 17 | opt_cr1: u32, 18 | } 19 | -------------------------------------------------------------------------------- /src/components/gpio/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod stm32f7; 2 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/alternate_fn.rs: -------------------------------------------------------------------------------- 1 | //! GPIO alternate function register (GPIOx_AFRL and GPIOx_AFRH) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | #[repr(C)] 9 | pub struct AlternateFunctionRegister { 10 | low: Low, 11 | high: High, 12 | } 13 | 14 | impl AlternateFunctionRegister { 15 | /// Sets `pin` 16 | pub fn set(&mut self, pin: Pin, alternate_fn: AlternateFunction) { 17 | self.low.set(pin, alternate_fn); 18 | self.high.set(pin, alternate_fn); 19 | } 20 | } 21 | 22 | #[derive(Debug, Clone, Copy)] 23 | #[repr(u32)] 24 | pub enum AlternateFunction { 25 | AF0 = 0b0000, 26 | AF1 = 0b0001, 27 | AF2 = 0b0010, 28 | AF3 = 0b0011, 29 | AF4 = 0b0100, 30 | AF5 = 0b0101, 31 | AF6 = 0b0110, 32 | AF7 = 0b0111, 33 | AF8 = 0b1000, 34 | AF9 = 0b1001, 35 | AF10 = 0b1010, 36 | AF11 = 0b1011, 37 | AF12 = 0b1100, 38 | AF13 = 0b1101, 39 | AF14 = 0b1110, 40 | AF15 = 0b1111, 41 | } 42 | 43 | 44 | #[derive(Clone, Copy)] 45 | #[repr(C)] 46 | struct High(BitField); 47 | 48 | impl High { 49 | /// Sets the alternate function for the given high pins 50 | pub fn set(&mut self, pin: Pin, alternate_fn: AlternateFunction) { 51 | let pin_number = pin as u8; 52 | if pin_number >= 8 { 53 | let offset = (pin_number - 8) * 4; 54 | self.0.set_range(offset..(offset + 4), alternate_fn as u32); 55 | } 56 | } 57 | } 58 | 59 | #[derive(Clone, Copy)] 60 | #[repr(C)] 61 | struct Low(BitField); 62 | 63 | impl Low { 64 | /// Sets the alternate function for the given low pins 65 | pub fn set(&mut self, pin: Pin, alternate_fn: AlternateFunction) { 66 | let pin_number = pin as u8; 67 | if pin_number < 8 { 68 | let offset = pin_number * 4; 69 | self.0.set_range(offset..(offset + 4), alternate_fn as u32); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/bit_set_reset.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port bit set/reset register (GPIOx_BSRR) 2 | 3 | use super::Pin; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct BitSetResetRegister(u32); 7 | 8 | impl BitSetResetRegister { 9 | pub fn set(&mut self, pin: Pin) { 10 | self.0 |= 1u32 << pin as u8; 11 | } 12 | 13 | pub fn reset(&mut self, pin: Pin) { 14 | self.0 |= 1u32 << (pin as u8 + 16); 15 | } 16 | } 17 | 18 | impl Default for BitSetResetRegister { 19 | fn default() -> BitSetResetRegister { 20 | BitSetResetRegister(0) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/input_data.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port input data register (GPIOx_IDR) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct InputDataRegister(BitField); 9 | 10 | impl InputDataRegister { 11 | /// Get input pin 12 | pub fn get(&self, pin: Pin) -> bool { 13 | self.0.get_bit(pin as u8) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/mod.rs: -------------------------------------------------------------------------------- 1 | //! General Purpose I/O 2 | 3 | mod mode; 4 | mod input_data; 5 | mod output_data; 6 | mod bit_set_reset; 7 | mod out_speed; 8 | mod out_type; 9 | mod resistor; 10 | mod alternate_fn; 11 | 12 | pub use self::mode::{ModeRegister, Mode}; 13 | pub use self::input_data::InputDataRegister; 14 | pub use self::output_data::OutputDataRegister; 15 | pub use self::bit_set_reset::BitSetResetRegister; 16 | pub use self::out_type::{OutputTypeRegister, OutputType}; 17 | pub use self::out_speed::{OutputSpeedRegister, OutputSpeed}; 18 | pub use self::resistor::{ResistorRegister, Resistor}; 19 | pub use self::alternate_fn::{AlternateFunctionRegister, AlternateFunction}; 20 | 21 | use volatile::{ReadOnly, WriteOnly, ReadWrite}; 22 | 23 | #[repr(C)] 24 | pub struct Gpio { 25 | pub mode: ReadWrite, 26 | pub out_type: ReadWrite, 27 | pub out_speed: ReadWrite, 28 | pub pupd: ReadWrite, 29 | 30 | // 0x10 31 | pub input_data: ReadOnly, 32 | pub output_data: ReadOnly, 33 | pub bit_set_reset: WriteOnly, 34 | pub lckr: ReadWrite, 35 | 36 | // 0x20 37 | pub alternate_fn: ReadWrite, 38 | } 39 | 40 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 41 | #[repr(u8)] 42 | pub enum Pin { 43 | Pin0 = 0, 44 | Pin1, 45 | Pin2, 46 | Pin3, 47 | Pin4, 48 | Pin5, 49 | Pin6, 50 | Pin7, 51 | Pin8, 52 | Pin9, 53 | Pin10, 54 | Pin11, 55 | Pin12, 56 | Pin13, 57 | Pin14, 58 | Pin15, 59 | } 60 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/mode.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port mode register (GPIOx_MODER) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct ModeRegister(BitField); 9 | 10 | impl ModeRegister { 11 | /// Sets the mode for the given pins 12 | pub fn set(&mut self, pin: Pin, mode: Mode) { 13 | let offset = (pin as u8) * 2; 14 | self.0.set_range(offset..offset + 2, mode as u32); 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone, Copy)] 19 | #[repr(u32)] 20 | pub enum Mode { 21 | Input = 0b00, 22 | Output = 0b01, 23 | AlternateFunction = 0b10, 24 | Analog = 0b11, 25 | } 26 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/out_speed.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port output speed register (GPIOx_OSPEEDR) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct OutputSpeedRegister(BitField); 9 | 10 | impl OutputSpeedRegister { 11 | /// Returns the output speed for the given pins 12 | pub fn set(&mut self, pin: Pin, speed: OutputSpeed) { 13 | let offset = (pin as u8) * 2; 14 | self.0.set_range(offset..offset + 2, speed as u32); 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone, Copy)] 19 | #[repr(u32)] 20 | pub enum OutputSpeed { 21 | Low = 0b00, 22 | Medium = 0b01, 23 | High = 0b10, 24 | VeryHigh = 0b11, 25 | } 26 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/out_type.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port output type register (GPIOx_OTYPER) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct OutputTypeRegister(BitField); 9 | 10 | impl OutputTypeRegister { 11 | /// Sets the output type for the given pins 12 | pub fn set(&mut self, pin: Pin, typ: OutputType) { 13 | let offset = pin as u8; 14 | self.0.set_range(offset..offset + 1, typ as u32); 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone, Copy)] 19 | #[repr(u32)] 20 | pub enum OutputType { 21 | PushPull = 0, 22 | OpenDrain = 1, 23 | } 24 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/output_data.rs: -------------------------------------------------------------------------------- 1 | //! port output data register (GPIOx_ODR) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct OutputDataRegister(BitField); 9 | 10 | #[allow(dead_code)] 11 | impl OutputDataRegister { 12 | /// Get output pin 13 | pub fn get(&self, pin: Pin) -> bool { 14 | self.0.get_bit(pin as u8) 15 | } 16 | /// Set output pin 17 | pub fn set(&mut self, pin: Pin, value: bool) { 18 | self.0.set_bit(pin as u8, value); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/gpio/stm32f7/resistor.rs: -------------------------------------------------------------------------------- 1 | //! GPIO port pull-up/pull-down register (GPIOx_PUPDR) 2 | 3 | use super::Pin; 4 | use bit_field::BitField; 5 | 6 | /// Register 7 | #[derive(Clone, Copy)] 8 | pub struct ResistorRegister(BitField); 9 | 10 | impl ResistorRegister { 11 | /// Sets the resistor for the given pins 12 | pub fn set(&mut self, pin: Pin, resistor: Resistor) { 13 | let offset = (pin as u8) * 2; 14 | self.0.set_range(offset..offset + 2, resistor as u32); 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone, Copy)] 19 | #[repr(u32)] 20 | pub enum Resistor { 21 | NoPull = 0b00, 22 | PullUp = 0b01, 23 | PullDown = 0b10, 24 | } 25 | -------------------------------------------------------------------------------- /src/components/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gpio; 2 | pub mod systick; 3 | pub mod rcc; 4 | pub mod pwr; 5 | pub mod flash; 6 | -------------------------------------------------------------------------------- /src/components/pwr/cr1.rs: -------------------------------------------------------------------------------- 1 | //! PWR power control register (PWR_CR1) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const LPDS = 1 << 0, 6 | const PDDS = 1 << 1, 7 | const CSBF = 1 << 3, 8 | const PVDE = 1 << 4, 9 | const PLS_0 = 1 << 5, 10 | const PLS_1 = 1 << 6, 11 | const PLS_2 = 1 << 7, 12 | const DBP = 1 << 8, 13 | const FPDS = 1 << 9, 14 | const LPUDS = 1 << 10, 15 | const MRUDS = 1 <<11, 16 | const ADCDC_1 = 1 << 13, 17 | const VOS_0 = 1 << 14, 18 | const VOS_1 = 1 << 15, 19 | const ODEN = 1 << 16, 20 | const ODSWEN = 1 << 17, 21 | const UDEN_0 = 1 << 18, 22 | const UDEN_1 = 1 << 19, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/pwr/csr1.rs: -------------------------------------------------------------------------------- 1 | //! PWR power control/status register (PWR_CSR1) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const WUIF = 1 << 0, 6 | const SBF = 1 << 1, 7 | const PVDO = 1 << 2, 8 | const BRR = 1 << 3, 9 | const EIWUP = 1 << 8, 10 | const BRE = 1 << 9, 11 | const VOS_RDY = 1 << 14, 12 | const OD_RDY = 1 << 16, 13 | const ODSW_RDY = 1 << 17, 14 | const UD_RDY_0 = 1 << 18, 15 | const UD_RDY_1 = 1 << 19, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/pwr/mod.rs: -------------------------------------------------------------------------------- 1 | //! Power controller (PWR) 2 | 3 | use volatile::Volatile; 4 | 5 | pub mod cr1; 6 | pub mod csr1; 7 | 8 | #[repr(C)] 9 | pub struct PwrBank { 10 | pub cr1: Volatile, 11 | pub csr1: Volatile, 12 | cr2: u32, 13 | csr2: u32, 14 | } 15 | -------------------------------------------------------------------------------- /src/components/rcc/ahb1_enr.rs: -------------------------------------------------------------------------------- 1 | //! RCC AHB1 peripheral clock register (RCC_AHB1ENR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const GPIO_A_ENABLE = 1 << 0, 6 | const GPIO_B_ENABLE = 1 << 1, 7 | const GPIO_C_ENABLE = 1 << 2, 8 | const GPIO_D_ENABLE = 1 << 3, 9 | const GPIO_E_ENABLE = 1 << 4, 10 | const GPIO_F_ENABLE = 1 << 5, 11 | const GPIO_G_ENABLE = 1 << 6, 12 | const GPIO_H_ENABLE = 1 << 7, 13 | const GPIO_I_ENABLE = 1 << 8, 14 | const GPIO_J_ENABLE = 1 << 9, 15 | const GPIO_K_ENABLE = 1 << 10, 16 | 17 | const CRC_ENABLE = 1 << 12, 18 | const BKPSRAM_ENABLE = 1 << 18, 19 | const DTCMRAM_ENABLE = 1 << 20, 20 | const DMA1_ENABLE = 1 << 21, 21 | const DMA2_ENABLE = 1 << 22, 22 | const DMA2D_ENABLE = 1 << 23, 23 | const ETHMAC_ENABLE = 1 << 25, 24 | const ETHMAC_TX_ENABLE = 1 << 26, 25 | const ETHMAC_RX_ENABLE = 1 << 27, 26 | const ETHMAC_PTP_ENABLE = 1 << 28, 27 | const OTG_HS_ENABLE = 1 << 29, 28 | const OTG_HSULPI_ENABLE = 1 << 30, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/rcc/ahb1_rstr.rs: -------------------------------------------------------------------------------- 1 | //! RCC AHB1 peripheral reset register (RCC_AHB1RSTR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const GPIO_A_RESET = 1 << 0, 6 | const GPIO_B_RESET = 1 << 1, 7 | const GPIO_C_RESET = 1 << 2, 8 | const GPIO_D_RESET = 1 << 3, 9 | const GPIO_E_RESET = 1 << 4, 10 | const GPIO_F_RESET = 1 << 5, 11 | const GPIO_G_RESET = 1 << 6, 12 | const GPIO_H_RESET = 1 << 7, 13 | const GPIO_I_RESET = 1 << 8, 14 | const GPIO_J_RESET = 1 << 9, 15 | const GPIO_K_RESET = 1 << 10, 16 | 17 | // etc 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/rcc/ahb3_enr.rs: -------------------------------------------------------------------------------- 1 | //! RCC AHB3 peripheral clock enable register (RCC_AHB3ENR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | /// Flexible memory controller clock enable 6 | const FMC_ENABLE = 1, 7 | /// Quad SPI memory controller clock enable 8 | const QSPI_ENABLE = 1 << 1, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/rcc/ahb3_rstr.rs: -------------------------------------------------------------------------------- 1 | //! RCC AHB3 peripheral reset register (RCC_AHB3RSTR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const FMCRST = 1, 6 | const QSPIRST = 1 << 1, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/components/rcc/apb1_enr.rs: -------------------------------------------------------------------------------- 1 | //! RCC APB1 peripheral clock enable register (RCC_APB1ENR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const TIM_2_ENABLE = 1 << 0, 6 | const TIM_3_ENABLE = 1 << 1, 7 | const TIM_4_ENABLE = 1 << 2, 8 | const TIM_5_ENABLE = 1 << 3, 9 | const TIM_6_ENABLE = 1 << 4, 10 | const TIM_7_ENABLE = 1 << 5, 11 | const TIM_12_ENABLE = 1 << 6, 12 | const TIM_13_ENABLE = 1 << 7, 13 | const TIM_14_ENABLE = 1 << 8, 14 | const LPTIM_1_ENABLE = 1 << 9, 15 | const WWDG_ENABLE = 1 << 11, 16 | const SPI_2_ENABLE = 1 << 14, 17 | const SPI_3_ENABLE = 1 << 15, 18 | const SPDIFRX_ENABLE = 1 << 16, 19 | const USART_2_ENABLE = 1 << 17, 20 | const USART_3_ENABLE = 1 << 18, 21 | const UART_4_ENABLE = 1 << 19, 22 | const UART_5_ENABLE = 1 << 20, 23 | const I2C_1_ENABLE = 1 << 21, 24 | const I2C_2_ENABLE = 1 << 22, 25 | const I2C_3_ENABLE = 1 << 23, 26 | const I2C_4_ENABLE = 1 << 24, 27 | const CAN_1_ENABLE = 1 << 25, 28 | const CAN_2_ENABLE = 1 << 26, 29 | const CEC_ENABLE = 1 << 27, 30 | const PWR_ENABLE = 1 << 28, 31 | const DAC_ENABLE = 1 << 29, 32 | const UART_7_ENABLE = 1 << 30, 33 | const UART_8_ENABLE = 1 << 31, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/rcc/apb2_enr.rs: -------------------------------------------------------------------------------- 1 | //! RCC APB2 peripheral clock enable register (RCC_APB2ENR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const TIM_1_ENABLE = 1 << 0, 6 | const TIM_8_ENABLE = 1 << 1, 7 | const USART_1_ENABLE = 1 << 4, 8 | const USART_6_ENABLE = 1 << 5, 9 | const ADC_1_ENABLE = 1 << 8, 10 | const ADC_2_ENABLE = 1 << 9, 11 | const ADC_3_ENABLE = 1 << 10, 12 | const SDMMC_1_ENABLE = 1 << 11, 13 | const SPI_1_ENABLE = 1 << 12, 14 | const SPI_4_ENABLE = 1 << 13, 15 | const SYSCFG_ENABLE = 1 << 14, 16 | const TIM_9_ENABLE = 1 << 16, 17 | const TIM_10_ENABLE = 1 << 17, 18 | const TIM_11_ENABLE = 1 << 18, 19 | const SPI_5_ENABLE = 1 << 20, 20 | const SPI_6_ENABLE = 1 << 21, 21 | const SAI_1_ENABLE = 1 << 22, 22 | const SAI_2_ENABLE = 1 << 23, 23 | const LTDC_ENABLE = 1 << 26, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/rcc/cfgr.rs: -------------------------------------------------------------------------------- 1 | //! RCC clock configuration register (RCC_CFGR) 2 | 3 | use bit_field::BitField; 4 | 5 | /// Register 6 | #[derive(Clone, Copy)] 7 | pub struct Register(BitField); 8 | 9 | impl Register { 10 | pub fn system_clock(&mut self) -> Option { 11 | match self.0.get_range(2..4) { 12 | 0b00 => Some(SystemClock::HSI), 13 | 0b01 => Some(SystemClock::HSE), 14 | 0b10 => Some(SystemClock::PLL), 15 | 0b11 => None, 16 | _ => unreachable!(), 17 | } 18 | } 19 | 20 | pub fn set_system_clock(&mut self, value: SystemClock) { 21 | self.0.set_range(0..2, value as u32); 22 | } 23 | 24 | pub fn set_ahb_prescaler(&mut self, value: AhbClockDivisionFactor) { 25 | self.0.set_range(4..8, value as u32); 26 | } 27 | 28 | pub fn set_apb_low_speed_prescaler(&mut self, value: ApbClockDivisionFactor) { 29 | self.0.set_range(10..13, value as u32); 30 | } 31 | 32 | pub fn set_apb_high_speed_prescaler(&mut self, value: ApbClockDivisionFactor) { 33 | self.0.set_range(13..16, value as u32); 34 | } 35 | } 36 | 37 | #[derive(Debug, Clone, Copy)] 38 | #[repr(u32)] 39 | pub enum SystemClock { 40 | HSI = 0b00, 41 | HSE = 0b01, 42 | PLL = 0b10, 43 | } 44 | 45 | #[derive(Debug, Clone, Copy)] 46 | #[repr(u32)] 47 | pub enum AhbClockDivisionFactor { 48 | NoDivide = 0b0000, 49 | Divide2 = 0b1000, 50 | Divide4 = 0b1001, 51 | Divide8 = 0b1010, 52 | Divide16 = 0b1011, 53 | Divide64 = 0b1100, 54 | Divide128 = 0b1101, 55 | Divide256 = 0b1110, 56 | Divide512 = 0b1111, 57 | } 58 | 59 | #[derive(Debug, Clone, Copy)] 60 | #[repr(u32)] 61 | pub enum ApbClockDivisionFactor { 62 | NoDivide = 0b000, 63 | Divide2 = 0b100, 64 | Divide4 = 0b101, 65 | Divide8 = 0b110, 66 | Divide16 = 0b111, 67 | } 68 | -------------------------------------------------------------------------------- /src/components/rcc/cr.rs: -------------------------------------------------------------------------------- 1 | //! RCC clock control register (RCC_CR) 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const HSI_ON = 1 << 0, 6 | const HSI_RDY = 1 << 1, 7 | const HSE_ON = 1 << 16, 8 | const HSE_RDY = 1 << 17, 9 | const HSE_BYP = 1 << 18, 10 | const CSS_ON = 1 << 19, 11 | const PLL_ON = 1 << 24, 12 | const PLL_RDY = 1 << 25, 13 | const PLLI2S_ON = 1 << 26, 14 | const PLLI2S_RDY = 1 << 27, 15 | const PLLSAI_ON = 1 << 28, 16 | const PLLSAI_RDY = 1 << 29, 17 | 18 | // etc 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/rcc/dckcfgr1.rs: -------------------------------------------------------------------------------- 1 | //! RCC dedicated clocks configuration register (RCC_DKCFGR1) 2 | 3 | use bit_field::BitField; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Register(BitField); 7 | 8 | impl Register { 9 | /** 10 | division factor for LCD_CLK 11 | 12 | These bits are set and cleared by software to control the frequency of LCD_CLK. 13 | They should be written only if PLLSAI is disabled. 14 | LCD_CLK frequency = f(PLLSAI_R) / PLLSAIDIVR with 2 ≤ PLLSAIDIVR ≤ 16 15 | **/ 16 | pub fn set_pllsai_divr(&mut self, number: u32) { 17 | let bits = match number { 18 | 2 => 0b00, 19 | 4 => 0b01, 20 | 8 => 0b10, 21 | 16 => 0b11, 22 | _ => panic!("invalid value"), 23 | }; 24 | self.0.set_range(16..18, bits); 25 | } 26 | 27 | pub fn pllsai_divq(&self) -> u32 { 28 | self.0.get_range(8..13) 29 | } 30 | 31 | pub fn set_sai2_clock_source(&mut self, clock_source: SaiClockSource) { 32 | self.0.set_range(22..24, clock_source as u32); 33 | } 34 | 35 | pub fn set_plli2s_divq(&mut self, number: u32) { 36 | self.0.set_range(0..5, number - 1); 37 | } 38 | 39 | // etc 40 | } 41 | 42 | #[derive(Debug)] 43 | #[repr(u32)] 44 | pub enum SaiClockSource { 45 | PllI2S = 0b00, 46 | PllSai = 0b01, 47 | PinInput = 0b10, 48 | } 49 | -------------------------------------------------------------------------------- /src/components/rcc/mod.rs: -------------------------------------------------------------------------------- 1 | use volatile::Volatile; 2 | 3 | pub mod cr; 4 | pub mod pll_cfgr; 5 | pub mod cfgr; 6 | pub mod ahb1_enr; 7 | pub mod ahb3_enr; 8 | pub mod apb1_enr; 9 | pub mod apb2_enr; 10 | pub mod ahb1_rstr; 11 | pub mod ahb3_rstr; 12 | pub mod pllsaicfgr; 13 | pub mod plli2scfgr; 14 | pub mod dckcfgr1; 15 | 16 | #[repr(C)] 17 | pub struct RccBank { 18 | pub cr: Volatile, 19 | pub pll_cfgr: Volatile, 20 | pub cfgr: Volatile, 21 | cir: u32, 22 | 23 | // 0x10 24 | pub ahb1_rstr: Volatile, 25 | ahb2_rstr: u32, 26 | pub ahb3_rstr: Volatile, 27 | _pad1: u32, 28 | 29 | // 0x20 30 | apb1_rstr: u32, 31 | apb2_rstr: u32, 32 | _pad2: u32, 33 | _pad3: u32, 34 | 35 | // 0x30 36 | pub ahb1_enr: Volatile, 37 | ahb2_enr: u32, 38 | pub ahb3_enr: Volatile, 39 | _pad4: u32, 40 | 41 | // 0x40 42 | pub apb1_enr: Volatile, 43 | pub apb2_enr: Volatile, 44 | _pad5: u32, 45 | _pad6: u32, 46 | 47 | // 0x50 48 | ahb1_lpenr: u32, 49 | ahb2_lpenr: u32, 50 | ahb3_lpenr: u32, 51 | _pad7: u32, 52 | 53 | // 0x60 54 | apb1_lpenr: u32, 55 | apb2_lpenr: u32, 56 | _pad8: u32, 57 | _pad9: u32, 58 | 59 | // 0x70 60 | bdcr: u32, 61 | csr: u32, 62 | _pad10: u32, 63 | _pad11: u32, 64 | 65 | // 0x80 66 | sscgr: u32, 67 | pub plli2scfgr: Volatile, 68 | pub pllsaicfgr: Volatile, 69 | pub dckcfgr1: Volatile, 70 | 71 | // 0x90 72 | dckcfgr2: u32, 73 | } 74 | 75 | impl RccBank { 76 | pub fn enable_all_gpio_ports(&mut self) { 77 | self.ahb1_enr.update(|r| { 78 | r.insert(ahb1_enr::GPIO_A_ENABLE | ahb1_enr::GPIO_B_ENABLE | ahb1_enr::GPIO_C_ENABLE | 79 | ahb1_enr::GPIO_D_ENABLE | 80 | ahb1_enr::GPIO_E_ENABLE | ahb1_enr::GPIO_F_ENABLE | 81 | ahb1_enr::GPIO_G_ENABLE | 82 | ahb1_enr::GPIO_H_ENABLE | 83 | ahb1_enr::GPIO_I_ENABLE | 84 | ahb1_enr::GPIO_J_ENABLE | ahb1_enr::GPIO_K_ENABLE) 85 | }); 86 | } 87 | 88 | pub fn reset_all_gpio_ports(&mut self) { 89 | // set reset bits 90 | self.ahb1_rstr.update(|r| { 91 | r.insert(ahb1_rstr::GPIO_A_RESET | ahb1_rstr::GPIO_B_RESET | ahb1_rstr::GPIO_C_RESET | 92 | ahb1_rstr::GPIO_D_RESET | 93 | ahb1_rstr::GPIO_E_RESET | ahb1_rstr::GPIO_F_RESET | 94 | ahb1_rstr::GPIO_G_RESET | 95 | ahb1_rstr::GPIO_H_RESET | 96 | ahb1_rstr::GPIO_I_RESET | 97 | ahb1_rstr::GPIO_J_RESET | ahb1_rstr::GPIO_K_RESET) 98 | }); 99 | // clear reset bits 100 | self.ahb1_rstr.update(|r| { 101 | r.remove(ahb1_rstr::GPIO_A_RESET | ahb1_rstr::GPIO_B_RESET | ahb1_rstr::GPIO_C_RESET | 102 | ahb1_rstr::GPIO_D_RESET | 103 | ahb1_rstr::GPIO_E_RESET | ahb1_rstr::GPIO_F_RESET | 104 | ahb1_rstr::GPIO_G_RESET | 105 | ahb1_rstr::GPIO_H_RESET | 106 | ahb1_rstr::GPIO_I_RESET | 107 | ahb1_rstr::GPIO_J_RESET | ahb1_rstr::GPIO_K_RESET) 108 | }); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/components/rcc/pll_cfgr.rs: -------------------------------------------------------------------------------- 1 | //! RCC PLL configuration register (RCC_PLLCFGR) 2 | 3 | use bit_field::BitField; 4 | 5 | /// Register 6 | #[derive(Clone, Copy)] 7 | pub struct Register(BitField); 8 | 9 | impl Register { 10 | pub fn pllm(&self) -> u32 { 11 | self.0.get_range(0..6) 12 | } 13 | 14 | pub fn plln(&self) -> u32 { 15 | self.0.get_range(6..15) 16 | } 17 | 18 | pub fn pllp(&self) -> u32 { 19 | (self.0.get_range(16..18) + 1) * 2 20 | } 21 | 22 | pub fn pllq(&self) -> u32 { 23 | self.0.get_range(24..28) 24 | } 25 | 26 | 27 | /// Division factor for the main PLLs (PLL, PLLI2S and PLLSAI) input clock 28 | /// 29 | /// Set and cleared by software to divide the PLL and PLLI2S input clock before the VCO. 30 | /// These bits can be written only when the PLL and PLLI2S are disabled. 31 | pub fn set_pllm(&mut self, value: u32) { 32 | self.0.set_range(0..6, value); 33 | } 34 | 35 | /// Main PLL (PLL) multiplication factor for VCO 36 | /// 37 | /// Set and cleared by software to control the multiplication factor of the VCO. These bits can 38 | /// be written only when PLL is disabled. Only half-word and word accesses are allowed to 39 | /// write these bits. 40 | pub fn set_plln(&mut self, value: u32) { 41 | self.0.set_range(6..15, value); 42 | } 43 | 44 | /// Main PLL (PLL) division factor for main system clock 45 | /// 46 | /// Set and cleared by software to control the frequency of the general PLL output clock. These 47 | /// bits can be written only if PLL is disabled. 48 | pub fn set_pllp(&mut self, value: u32) { 49 | self.0.set_range(16..18, value / 2 - 1); 50 | } 51 | 52 | /// Set main PLL(PLL) and audio PLL (PLLI2S) entry clock source to HSE oscillator clock 53 | /// 54 | /// Set and cleared by software to select PLL and PLLI2S clock source. This bit can be written 55 | /// only when PLL and PLLI2S are disabled. 56 | pub fn set_pllsrc(&mut self, value: bool) { 57 | self.0.set_bit(22, value); 58 | } 59 | 60 | /// Main PLL (PLL) division factor for USB OTG FS, SDMMC and random number generator clocks 61 | /// 62 | /// Set and cleared by software to control the frequency of USB OTG FS clock, the random 63 | /// number generator clock and the SDMMC clock. These bits should be written only if PLL is 64 | /// disabled. 65 | pub fn set_pllq(&mut self, value: u32) { 66 | self.0.set_range(24..28, value); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/components/rcc/plli2scfgr.rs: -------------------------------------------------------------------------------- 1 | //! RCC PLLI2S configuration register (RCC_PLLI2SCFGR) 2 | 3 | use bit_field::BitField; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Register(BitField); 7 | 8 | impl Register { 9 | pub fn plli2sn(&self) -> u32 { 10 | self.0.get_range(6..15) 11 | } 12 | pub fn set_plli2sn(&mut self, number: u32) { 13 | assert!(number >= 50 && number < 433); 14 | self.0.set_range(6..15, number); 15 | } 16 | pub fn set_plli2sp(&mut self, number: u32) { 17 | let value = match number { 18 | 2 => 0b00, 19 | 4 => 0b01, 20 | 6 => 0b10, 21 | 8 => 0b11, 22 | _ => panic!("invalid plli2sp value"), 23 | }; 24 | self.0.set_range(16..18, value); 25 | } 26 | pub fn plli2sq(&self) -> u32 { 27 | self.0.get_range(24..28) 28 | } 29 | pub fn set_plli2sq(&mut self, number: u32) { 30 | assert!(number >= 2 && number < 16); 31 | self.0.set_range(24..28, number); 32 | } 33 | pub fn set_plli2sr(&mut self, number: u32) { 34 | assert!(number >= 2 && number < 8); 35 | self.0.set_range(28..31, number); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/rcc/pllsaicfgr.rs: -------------------------------------------------------------------------------- 1 | //! RCC PLL configuration register (RCC_PLLSAICFGR) 2 | 3 | use bit_field::BitField; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Register(BitField); 7 | 8 | impl Register { 9 | pub fn pllsain(&self) -> u32 { 10 | self.0.get_range(6..15) 11 | } 12 | pub fn set_pllsain(&mut self, number: u32) { 13 | assert!(number >= 50 && number < 433); 14 | self.0.set_range(6..15, number); 15 | } 16 | pub fn set_pllsaip(&mut self, number: u32) { 17 | let value = match number { 18 | 2 => 0b00, 19 | 4 => 0b01, 20 | 6 => 0b10, 21 | 8 => 0b11, 22 | _ => panic!("invalid pllsaip value"), 23 | }; 24 | self.0.set_range(16..18, value); 25 | } 26 | pub fn pllsaiq(&self) -> u32 { 27 | self.0.get_range(24..28) 28 | } 29 | pub fn set_pllsaiq(&mut self, number: u32) { 30 | assert!(number >= 2 && number < 16); 31 | self.0.set_range(24..28, number); 32 | } 33 | pub fn set_pllsair(&mut self, number: u32) { 34 | assert!(number >= 2 && number < 8); 35 | self.0.set_range(28..31, number); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/systick/csr.rs: -------------------------------------------------------------------------------- 1 | //! SysTick Control and Status Register 2 | 3 | bitflags! { 4 | pub flags Register: u32 { 5 | const ENABLE = 1 << 0, 6 | const TICKINT = 1 << 1, 7 | const CLKSOURCE = 1 << 2, // 0: external clock, 1: processor clock 8 | const COUNTFLAG = 1 << 16, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/systick/cvr.rs: -------------------------------------------------------------------------------- 1 | //! SysTick Current Value Register 2 | 3 | #[derive(Debug, Clone, Copy)] 4 | pub struct Register(u32); 5 | 6 | impl Register { 7 | pub fn value(&self) -> u32 { 8 | self.0 9 | } 10 | 11 | pub fn clear(&mut self) { 12 | self.0 = 0; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/components/systick/mod.rs: -------------------------------------------------------------------------------- 1 | // see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646b/Bhccjgga.html 2 | 3 | use components::rcc::RccBank; 4 | use volatile::Volatile; 5 | 6 | pub mod csr; 7 | pub mod rvr; 8 | pub mod cvr; 9 | 10 | #[repr(C)] 11 | pub struct SysTickBank { 12 | /// Control and Status Register 13 | pub csr: Volatile, 14 | /// Reload Value Register 15 | pub rvr: Volatile, 16 | /// Current Value Register 17 | pub cvr: Volatile, 18 | /// Calibration Register 19 | calib: u32, 20 | } 21 | 22 | impl SysTickBank { 23 | pub fn setup(&'static mut self, rcc: &RccBank, enable_interrupt: bool) -> SysTick { 24 | // Progam SysTick 25 | let pll_cfgr = rcc.pll_cfgr.read(); 26 | let pllm = pll_cfgr.pllm(); 27 | let plln = pll_cfgr.plln(); 28 | let pllp = pll_cfgr.pllp(); 29 | self.rvr.update(|r| r.set(25 * 1000 / pllm * plln / pllp - 1)); // hse runs at 25 MHz 30 | self.cvr.update(|r| r.clear()); 31 | 32 | let mut flags = self::csr::CLKSOURCE | self::csr::ENABLE; 33 | if enable_interrupt { 34 | flags |= self::csr::TICKINT; 35 | } 36 | self.csr.write(flags); 37 | 38 | SysTick(self) 39 | } 40 | } 41 | 42 | pub struct SysTick(&'static mut SysTickBank); 43 | 44 | impl SysTick { 45 | pub fn busy_wait(&self, milliseconds: u32) { 46 | for _ in 0..milliseconds { 47 | while !self.0.csr.read().contains(csr::COUNTFLAG) {} 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/components/systick/rvr.rs: -------------------------------------------------------------------------------- 1 | //! SysTick Reload Value Register 2 | 3 | #[derive(Debug, Clone, Copy)] 4 | pub struct Register(u32); 5 | 6 | impl Register { 7 | pub fn set(&mut self, value: u32) { 8 | assert!(value & 0xff00_0000 == 0); 9 | self.0 = value; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/interfaces/gpio/mod.rs: -------------------------------------------------------------------------------- 1 | use components::gpio::stm32f7; 2 | use volatile::{ReadOnly, WriteOnly, ReadWrite}; 3 | use arrayvec::ArrayVec; 4 | 5 | pub use components::gpio::stm32f7::{Pin, OutputType, OutputSpeed, Resistor, AlternateFunction}; 6 | 7 | #[derive(Debug)] 8 | pub enum Error { 9 | PinAlreadyInUse(Pin), 10 | } 11 | 12 | pub struct Gpio { 13 | port_a: GpioPort, 14 | port_b: GpioPort, 15 | port_c: GpioPort, 16 | port_d: GpioPort, 17 | port_e: GpioPort, 18 | port_f: GpioPort, 19 | port_g: GpioPort, 20 | port_h: GpioPort, 21 | port_i: GpioPort, 22 | port_j: GpioPort, 23 | port_k: GpioPort, 24 | } 25 | 26 | impl Gpio { 27 | pub fn new(gpio_a: &'static mut stm32f7::Gpio, 28 | gpio_b: &'static mut stm32f7::Gpio, 29 | gpio_c: &'static mut stm32f7::Gpio, 30 | gpio_d: &'static mut stm32f7::Gpio, 31 | gpio_e: &'static mut stm32f7::Gpio, 32 | gpio_f: &'static mut stm32f7::Gpio, 33 | gpio_g: &'static mut stm32f7::Gpio, 34 | gpio_h: &'static mut stm32f7::Gpio, 35 | gpio_i: &'static mut stm32f7::Gpio, 36 | gpio_j: &'static mut stm32f7::Gpio, 37 | gpio_k: &'static mut stm32f7::Gpio) 38 | -> Gpio { 39 | Gpio { 40 | port_a: GpioPort::new(gpio_a), 41 | port_b: GpioPort::new(gpio_b), 42 | port_c: GpioPort::new(gpio_c), 43 | port_d: GpioPort::new(gpio_d), 44 | port_e: GpioPort::new(gpio_e), 45 | port_f: GpioPort::new(gpio_f), 46 | port_g: GpioPort::new(gpio_g), 47 | port_h: GpioPort::new(gpio_h), 48 | port_i: GpioPort::new(gpio_i), 49 | port_j: GpioPort::new(gpio_j), 50 | port_k: GpioPort::new(gpio_k), 51 | } 52 | } 53 | 54 | pub fn to_input(&mut self, pin: (Port, Pin), resistor: Resistor) -> Result { 55 | self.port(pin.0).to_input(pin.1, resistor) 56 | } 57 | 58 | pub fn to_output(&mut self, 59 | pin: (Port, Pin), 60 | out_type: OutputType, 61 | out_speed: OutputSpeed, 62 | resistor: Resistor) 63 | -> Result { 64 | self.port(pin.0).to_output(pin.1, out_type, out_speed, resistor) 65 | } 66 | 67 | pub fn to_alternate_function(&mut self, 68 | pin: (Port, Pin), 69 | alternate_fn: AlternateFunction, 70 | typ: OutputType, 71 | speed: OutputSpeed, 72 | resistor: Resistor) 73 | -> Result<(), Error> { 74 | self.port(pin.0).to_alternate_function(pin.1, alternate_fn, typ, speed, resistor) 75 | } 76 | 77 | pub fn to_alternate_function_all(&mut self, 78 | pins: &[(Port, Pin)], 79 | alternate_fn: AlternateFunction, 80 | typ: OutputType, 81 | speed: OutputSpeed, 82 | resistor: Resistor) 83 | -> Result<(), Error> { 84 | 85 | // check that all pins are unused 86 | let mut pin_in_use = [self.port_a.pin_in_use, 87 | self.port_b.pin_in_use, 88 | self.port_c.pin_in_use, 89 | self.port_d.pin_in_use, 90 | self.port_e.pin_in_use, 91 | self.port_f.pin_in_use, 92 | self.port_g.pin_in_use, 93 | self.port_h.pin_in_use, 94 | self.port_i.pin_in_use, 95 | self.port_j.pin_in_use, 96 | self.port_k.pin_in_use]; 97 | for &(port, pin) in pins { 98 | if pin_in_use[port as usize][pin as usize] { 99 | return Err(Error::PinAlreadyInUse(pin)); 100 | } else { 101 | pin_in_use[port as usize][pin as usize] = true; 102 | } 103 | } 104 | 105 | // configure the pins for each port 106 | use self::Port::*; 107 | let ports = [PortA, PortB, PortC, PortD, PortE, PortF, PortG, PortH, PortI, PortJ, PortK]; 108 | for &port in ports.iter() { 109 | // create a pin_vec that contains all pins belonging to the port 110 | let mut pin_vec = ArrayVec::<[_; 16]>::new(); 111 | for pin in pins.iter().filter(|p| p.0 == port).map(|p| p.1) { 112 | // the array can't be too small since we check for duplicate pins 113 | assert!(pin_vec.push(pin).is_none()); 114 | } 115 | 116 | // configure the pins as alternate function pins 117 | self.port(port) 118 | .to_alternate_function_all(pin_vec.as_slice(), alternate_fn, typ, speed, resistor)?; 119 | } 120 | Ok(()) 121 | } 122 | 123 | pub fn port(&mut self, port: Port) -> &mut GpioPort { 124 | use self::Port::*; 125 | match port { 126 | PortA => &mut self.port_a, 127 | PortB => &mut self.port_b, 128 | PortC => &mut self.port_c, 129 | PortD => &mut self.port_d, 130 | PortE => &mut self.port_e, 131 | PortF => &mut self.port_f, 132 | PortG => &mut self.port_g, 133 | PortH => &mut self.port_h, 134 | PortI => &mut self.port_i, 135 | PortJ => &mut self.port_j, 136 | PortK => &mut self.port_k, 137 | } 138 | } 139 | } 140 | 141 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 142 | #[repr(u8)] 143 | pub enum Port { 144 | PortA = 0, 145 | PortB, 146 | PortC, 147 | PortD, 148 | PortE, 149 | PortF, 150 | PortG, 151 | PortH, 152 | PortI, 153 | PortJ, 154 | PortK, 155 | } 156 | 157 | pub struct GpioPort { 158 | pin_in_use: [bool; 16], 159 | mode: &'static mut ReadWrite, 160 | out_type: &'static mut ReadWrite, 161 | out_speed: &'static mut ReadWrite, 162 | pupd: &'static mut ReadWrite, 163 | input_data: &'static ReadOnly, 164 | output_data: &'static ReadOnly, 165 | bit_set_reset: BsrrRef, 166 | alternate_fn: &'static mut ReadWrite, 167 | } 168 | 169 | impl GpioPort { 170 | pub fn new(gpio: &'static mut stm32f7::Gpio) -> GpioPort { 171 | GpioPort { 172 | pin_in_use: [false; 16], 173 | mode: &mut gpio.mode, 174 | out_type: &mut gpio.out_type, 175 | out_speed: &mut gpio.out_speed, 176 | pupd: &mut gpio.pupd, 177 | input_data: &gpio.input_data, 178 | output_data: &gpio.output_data, 179 | bit_set_reset: BsrrRef(&mut gpio.bit_set_reset), 180 | alternate_fn: &mut gpio.alternate_fn, 181 | } 182 | } 183 | 184 | pub fn to_input(&mut self, pin: Pin, resistor: Resistor) -> Result { 185 | self.use_pin(pin)?; 186 | 187 | self.mode.update(|r| r.set(pin, stm32f7::Mode::Input)); 188 | self.pupd.update(|r| r.set(pin, resistor)); 189 | 190 | Ok(InputPin { 191 | pin: pin, 192 | input_data: self.input_data, 193 | }) 194 | } 195 | 196 | pub fn to_output(&mut self, 197 | pin: Pin, 198 | out_type: OutputType, 199 | out_speed: OutputSpeed, 200 | resistor: Resistor) 201 | -> Result { 202 | self.use_pin(pin)?; 203 | 204 | self.mode.update(|r| r.set(pin, stm32f7::Mode::Output)); 205 | self.out_type.update(|r| r.set(pin, out_type)); 206 | self.out_speed.update(|r| r.set(pin, out_speed)); 207 | self.pupd.update(|r| r.set(pin, resistor)); 208 | 209 | Ok(OutputPin { 210 | pin: pin, 211 | output_data: self.output_data, 212 | bit_set_reset: self.bit_set_reset.clone(), 213 | }) 214 | } 215 | 216 | pub fn to_alternate_function(&mut self, 217 | pin: Pin, 218 | alternate_fn: AlternateFunction, 219 | typ: OutputType, 220 | speed: OutputSpeed, 221 | resistor: Resistor) 222 | -> Result<(), Error> { 223 | self.to_alternate_function_all(&[pin], alternate_fn, typ, speed, resistor) 224 | } 225 | 226 | pub fn to_alternate_function_all(&mut self, 227 | pins: &[Pin], 228 | alternate_fn: AlternateFunction, 229 | typ: OutputType, 230 | speed: OutputSpeed, 231 | resistor: Resistor) 232 | -> Result<(), Error> { 233 | self.use_pins(pins)?; 234 | 235 | self.mode.update(|r| for &pin in pins { 236 | r.set(pin, stm32f7::Mode::AlternateFunction) 237 | }); 238 | self.pupd.update(|r| for &pin in pins { 239 | r.set(pin, resistor) 240 | }); 241 | self.out_type.update(|r| for &pin in pins { 242 | r.set(pin, typ) 243 | }); 244 | self.out_speed.update(|r| for &pin in pins { 245 | r.set(pin, speed) 246 | }); 247 | self.alternate_fn.update(|r| for &pin in pins { 248 | r.set(pin, alternate_fn) 249 | }); 250 | 251 | Ok(()) 252 | } 253 | 254 | fn use_pin(&mut self, pin: Pin) -> Result<(), Error> { 255 | if self.pin_in_use[pin as usize] { 256 | Err(Error::PinAlreadyInUse(pin)) 257 | } else { 258 | self.pin_in_use[pin as usize] = true; 259 | Ok(()) 260 | } 261 | } 262 | 263 | fn use_pins(&mut self, pins: &[Pin]) -> Result<(), Error> { 264 | // create a copy of the pin_in_use array since we only want to modify it in case of success 265 | let mut pin_in_use = self.pin_in_use; 266 | 267 | for &pin in pins { 268 | if pin_in_use[pin as usize] { 269 | return Err(Error::PinAlreadyInUse(pin)); 270 | } else { 271 | pin_in_use[pin as usize] = true; 272 | } 273 | } 274 | 275 | // success => write back updated pin_in_use array 276 | self.pin_in_use = pin_in_use; 277 | 278 | Ok(()) 279 | } 280 | } 281 | 282 | pub struct InputPin { 283 | pin: Pin, 284 | input_data: &'static ReadOnly, 285 | } 286 | 287 | impl InputPin { 288 | pub fn get(&self) -> bool { 289 | self.input_data.read().get(self.pin) 290 | } 291 | } 292 | 293 | pub struct OutputPin { 294 | pin: Pin, 295 | output_data: &'static ReadOnly, 296 | bit_set_reset: BsrrRef, 297 | } 298 | 299 | impl OutputPin { 300 | pub fn get(&self) -> bool { 301 | self.output_data.read().get(self.pin) 302 | } 303 | 304 | pub fn set(&mut self, value: bool) { 305 | self.bit_set_reset.set(self.pin, value); 306 | } 307 | } 308 | 309 | #[derive(Debug, Clone)] 310 | struct BsrrRef(*mut WriteOnly); 311 | 312 | unsafe impl Send for BsrrRef {} 313 | 314 | impl BsrrRef { 315 | fn set(&self, pin: Pin, value: bool) { 316 | let mut bsrr = stm32f7::BitSetResetRegister::default(); 317 | if value { 318 | bsrr.set(pin); 319 | } else { 320 | bsrr.reset(pin); 321 | } 322 | unsafe { (&mut *self.0).write(bsrr) }; 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /src/interfaces/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gpio; 2 | -------------------------------------------------------------------------------- /src/irq.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::ops::{Deref, DerefMut, Drop}; 3 | 4 | /// Enable IRQs (disables PRIMASK) 5 | /// 6 | /// Implemented using a single instruction. Does not affect NMI and 7 | /// HardFault. 8 | #[cfg(target_arch = "arm")] 9 | pub unsafe fn enable_irq() { 10 | asm!("CPSIE i" : : : : "volatile"); 11 | } 12 | 13 | /// Disables IRQs (enables PRIMASK) 14 | /// 15 | /// Implemented using a single instruction. 16 | #[cfg(target_arch = "arm")] 17 | pub unsafe fn disable_irq() { 18 | asm!("CPSID i" : : : : "volatile"); 19 | } 20 | 21 | /// Enable IRQs (disables FAULTMASK) 22 | /// 23 | /// Implemented using a single instruction. Does not affect NMI. 24 | #[cfg(target_arch = "arm")] 25 | pub unsafe fn enable_fault_irq() { 26 | asm!("CPSIE f" : : : : "volatile"); 27 | } 28 | 29 | /// Disables IRQs (enables FAULTMASK) 30 | /// 31 | /// Implemented using a single instruction. 32 | #[cfg(target_arch = "arm")] 33 | pub unsafe fn disable_fault_irq() { 34 | asm!("CPSID f" : : : : "volatile"); 35 | } 36 | 37 | pub trait MaskRegister { 38 | fn get_mask(&self) -> bool; 39 | fn set_mask(&mut self, enabled: bool); 40 | } 41 | 42 | pub struct MaskMutex { 43 | // FIXME: Rust's MaskMutex uses Box - but we do not always have a heap. 44 | // For now, take ownership of the object, which might be a pointer 45 | // anyway. 46 | data: UnsafeCell, 47 | reg: UnsafeCell, 48 | } 49 | 50 | pub struct MaskMutexGuard<'a, R: MaskRegister + 'a, T: 'a> { 51 | _data: &'a mut T, 52 | reg: &'a mut R, 53 | prev: bool, 54 | } 55 | 56 | impl<'a, R: MaskRegister, T> MaskMutex { 57 | pub fn new(p: R, t: T) -> MaskMutex { 58 | MaskMutex { 59 | data: UnsafeCell::new(t), 60 | reg: UnsafeCell::new(p), 61 | } 62 | } 63 | 64 | pub fn lock(&'a self) -> MaskMutexGuard<'a, R, T> { 65 | let reg = unsafe { &mut *self.reg.get() }; 66 | 67 | // Note: Locks can never be poisoned, as we don't have "real" 68 | // multithreading, so we always return a guard 69 | let prev = reg.get_mask(); 70 | reg.set_mask(true); 71 | 72 | MaskMutexGuard { 73 | // UnsafeCell better here? 74 | _data: unsafe { &mut *self.data.get() }, 75 | reg: reg, 76 | prev: prev, 77 | } 78 | } 79 | 80 | pub fn into_inner(self) -> T { 81 | unsafe { self.data.into_inner() } 82 | } 83 | } 84 | 85 | impl<'a, R: MaskRegister + 'a, T: 'a> Drop for MaskMutexGuard<'a, R, T> { 86 | fn drop(&mut self) { 87 | self.reg.set_mask(self.prev) 88 | } 89 | } 90 | 91 | impl<'a, R: MaskRegister + 'a, T: 'a> Deref for MaskMutexGuard<'a, R, T> { 92 | type Target = T; 93 | 94 | fn deref(&self) -> &T { 95 | self._data 96 | } 97 | } 98 | 99 | impl<'a, R: MaskRegister + 'a, T: 'a> DerefMut for MaskMutexGuard<'a, R, T> { 100 | fn deref_mut(&mut self) -> &mut T { 101 | self._data 102 | } 103 | } 104 | 105 | // NOTE: Could add a less-complicated, non-reentrant version of the lock here 106 | // if we wanted. 107 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! STM32-Discovery boards minimal runtime. 2 | //! 3 | //! See the `README.md` for a detailed introduction. 4 | 5 | #![feature(asm)] 6 | #![feature(lang_items)] 7 | #![feature(unwind_attributes)] 8 | #![no_std] 9 | 10 | #[macro_use] 11 | extern crate bitflags; 12 | extern crate bit_field; 13 | extern crate volatile; 14 | extern crate arrayvec; 15 | 16 | pub mod components; 17 | pub mod interfaces; 18 | pub mod irq; 19 | pub mod util; 20 | pub mod runtime; 21 | 22 | pub type InterruptHandler = extern "C" fn() -> (); 23 | 24 | #[allow(improper_ctypes)] 25 | extern "C" { 26 | static _STACK_TOP: (); 27 | } 28 | 29 | #[macro_export] 30 | macro_rules! board { 31 | ($board:ident, 32 | { 33 | $( $fname:ident : $fval:expr),* 34 | } 35 | ) => 36 | ( 37 | use $crate::boards::$board::Hardware; 38 | 39 | #[allow(improper_ctypes)] 40 | extern { 41 | static _STACK_TOP: (); 42 | } 43 | 44 | extern "C" fn _rust_start() { 45 | ::main(unsafe { $crate::boards::$board::hw() }) 46 | } 47 | 48 | #[link_section="vectors"] 49 | #[no_mangle] 50 | pub static VECTORS: $crate::boards::$board::VectorTable = 51 | $crate::boards::$board::VectorTable { 52 | msp: unsafe { &_STACK_TOP }, 53 | reset: Some(_rust_start), 54 | $( $fname: $fval, )* 55 | ..$crate::boards::$board::VECTOR_TABLE 56 | }; 57 | 58 | use $crate::boards::$board::INITIAL_CPU_FREQ; 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /src/runtime.rs: -------------------------------------------------------------------------------- 1 | // provisional runtime 2 | // apparently, even with panic="abort" you need to have a panic_fmt 3 | // implementation 4 | #[cfg(feature = "panic-fmt")] 5 | use core::fmt; 6 | 7 | #[cfg(feature = "panic-fmt")] 8 | #[lang = "panic_fmt"] 9 | extern "C" fn panic_impl(_: fmt::Arguments, _: &'static str, _: u32) -> ! { 10 | loop {} 11 | } 12 | 13 | #[cfg(feature = "unwind-cpp")] 14 | #[no_mangle] 15 | pub extern "C" fn __aeabi_unwind_cpp_pr0() {} 16 | 17 | // end runtime 18 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | #[inline(always)] 2 | pub fn keep() { 3 | // FIXME: gate on arm architecture 4 | unsafe { 5 | asm!(""); 6 | } 7 | } 8 | 9 | #[inline(always)] 10 | pub fn nop() { 11 | // FIXME: gate using arm architecture 12 | unsafe { 13 | asm!("NOP" : : : : "volatile"); 14 | } 15 | } 16 | 17 | /// Delay for roughly n instructions 18 | /// 19 | /// Note: This function usually compiles down to a 2-instruction loop + some 20 | /// minor overhead. `n` is therefore halved. 21 | /// 22 | /// Compiling without --release will cause this function to take between 10 to 23 | /// 30 times as long, making it quite unuseable. 24 | pub fn delay(n: usize) { 25 | for _ in 0..(n / 2) { 26 | // example loop disassembly: 27 | // 8010080: 3801 subs r0, #1 28 | // 8010082: d1fd bne.n 8010080 29 | keep(); 30 | } 31 | } 32 | --------------------------------------------------------------------------------