From 02c94d68c33f2848fc5ecb0a8a16e1d3bd33dfaf Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Thu, 16 Feb 2023 00:30:41 -0800 Subject: [PATCH 01/17] Updated cargo.toml files --- minimal_drivers/l2/Cargo.toml | 1 - minimal_drivers/l4/Cargo.toml | 2 -- minimal_drivers/l5/Cargo.toml | 1 - 3 files changed, 4 deletions(-) diff --git a/minimal_drivers/l2/Cargo.toml b/minimal_drivers/l2/Cargo.toml index a1631fb..877c130 100644 --- a/minimal_drivers/l2/Cargo.toml +++ b/minimal_drivers/l2/Cargo.toml @@ -8,6 +8,5 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -l0 = { path = "../l0" } # Add libraries here bitflags = "1.3.2" diff --git a/minimal_drivers/l4/Cargo.toml b/minimal_drivers/l4/Cargo.toml index b468f18..2f4bbdd 100644 --- a/minimal_drivers/l4/Cargo.toml +++ b/minimal_drivers/l4/Cargo.toml @@ -8,6 +8,4 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -l0 = { path = "../l0" } -l2 = { path = "../l2" } l3 = { path = "../l3" } diff --git a/minimal_drivers/l5/Cargo.toml b/minimal_drivers/l5/Cargo.toml index 5f95fcc..e9b764f 100644 --- a/minimal_drivers/l5/Cargo.toml +++ b/minimal_drivers/l5/Cargo.toml @@ -9,6 +9,5 @@ readme = "README.md" [dependencies] l0 = { path = "../l0" } -l2 = { path = "../l2" } l3 = { path = "../l3" } l4 = { path = "../l4" } From 5a3e0f93dfd3ad6fc89ad1c2619e206966b64352 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 05:04:43 -0800 Subject: [PATCH 02/17] Renamed peripheral.rs to singleton.rs --- minimal_drivers/l3/src/lib.rs | 4 ++-- minimal_drivers/l3/src/{peripheral.rs => singleton.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename minimal_drivers/l3/src/{peripheral.rs => singleton.rs} (100%) diff --git a/minimal_drivers/l3/src/lib.rs b/minimal_drivers/l3/src/lib.rs index 43f7995..c50440c 100644 --- a/minimal_drivers/l3/src/lib.rs +++ b/minimal_drivers/l3/src/lib.rs @@ -3,8 +3,8 @@ mod interfaces; pub use interfaces::*; -pub mod peripheral; -pub use peripheral::*; +pub mod singleton; +pub use singleton::*; // TODO, Add features // #[cfg(feature = "stm32l475xx")] diff --git a/minimal_drivers/l3/src/peripheral.rs b/minimal_drivers/l3/src/singleton.rs similarity index 100% rename from minimal_drivers/l3/src/peripheral.rs rename to minimal_drivers/l3/src/singleton.rs From 9783280215d831bdb8487423cd9cc76aabb815f7 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:15:51 -0800 Subject: [PATCH 03/17] Updated l0 library --- minimal_drivers/l0/build.rs | 5 ++++ minimal_drivers/l0/src/entry_point.rs | 15 ++++++++-- minimal_drivers/l0/src/global.rs | 8 +++++ minimal_drivers/l0/src/lib.rs | 20 +++++++++++-- minimal_drivers/l0/src/stm32l475xx/mod.rs | 2 ++ minimal_drivers/l0/src/stm32l475xx/private.rs | 30 +++++++++++++++++++ minimal_drivers/l0/src/utility/mod.rs | 21 +++++++++++++ 7 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 minimal_drivers/l0/src/global.rs create mode 100644 minimal_drivers/l0/src/stm32l475xx/mod.rs create mode 100644 minimal_drivers/l0/src/stm32l475xx/private.rs create mode 100644 minimal_drivers/l0/src/utility/mod.rs diff --git a/minimal_drivers/l0/build.rs b/minimal_drivers/l0/build.rs index ad6f5b5..ce7d158 100644 --- a/minimal_drivers/l0/build.rs +++ b/minimal_drivers/l0/build.rs @@ -16,6 +16,8 @@ fn parse_header(input_filename: &str, output_path: &PathBuf) { .wrap_unsafe_ops(true) .translate_enum_integer_types(true) .explicit_padding(false) + .generate_block(true) + .default_enum_style(bindgen::EnumVariation::ModuleConsts) .parse_callbacks(Box::new(bindgen::CargoCallbacks)) .generate() .expect("Unable to generate bindings"); @@ -35,6 +37,9 @@ fn main() { }; // TODO, Make this user configurable to support multiple microcontroller formats + // NOTE, This controller.rs contains both + // - Architecture considerations (ARM specific peripherals) + // - Microcontroller considerations (STM32 specific peripherals) const PARSE_INPUT_FILE: &str = "device/controller/stm32l475xx.h"; const OUTPUT_FILE: &str = "src/controller.rs"; if should_parse { diff --git a/minimal_drivers/l0/src/entry_point.rs b/minimal_drivers/l0/src/entry_point.rs index 27190e2..add8c0f 100644 --- a/minimal_drivers/l0/src/entry_point.rs +++ b/minimal_drivers/l0/src/entry_point.rs @@ -1,3 +1,5 @@ +use crate::chip::controller_init; + #[link_section = ".vector_table.reset_vector"] #[no_mangle] pub static RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; @@ -5,6 +7,7 @@ pub static RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; // NOTE, All the externed modules come here #[no_mangle] pub unsafe extern "C" fn Reset() -> ! { + // Data and BSS sections extern "C" { // .data section static mut __data_end__: u8; @@ -16,7 +19,7 @@ pub unsafe extern "C" fn Reset() -> ! { static mut __bss_end__: u8; } - // data + // Copy from VMA to LMA let vma_data_end = &__data_end__ as *const u8; let vma_data_start = &__data_start__ as *const u8; let lma_data_start = &__etext as *const u8; @@ -24,16 +27,22 @@ pub unsafe extern "C" fn Reset() -> ! { // core::ptr::copy_nonoverlapping(lma_data_start, &mut __data_start__ as *mut u8, count); core::ptr::copy_nonoverlapping(lma_data_start, vma_data_start as *mut u8, count); - // end + // Write 0 to .bss section let bss_end = &__bss_end__ as *const u8; let bss_start = &__bss_start__ as *const u8; let count = bss_end as usize - bss_start as usize; // core::ptr::write_bytes(&mut __bss_start__ as *mut u8, 0, count); core::ptr::write_bytes(bss_start as *mut u8, 0, count); + // Controller level startup system initialization + + // Jump to L0 controller system init + // TODO, Jump to L4 board init + // Jump to L5 main function extern "Rust" { fn main() -> !; } + controller_init(); main(); } @@ -68,7 +77,7 @@ pub static EXCEPTIONS: [Vector; 14] = [ Vector { reserved: 0 }, Vector { reserved: 0 }, Vector { handler: SVCall }, - Vector { reserved: 0 }, + Vector { reserved: 0 }, // Debug Monitor Handler comes here Vector { reserved: 0 }, Vector { handler: PendSV }, Vector { handler: SysTick }, diff --git a/minimal_drivers/l0/src/global.rs b/minimal_drivers/l0/src/global.rs new file mode 100644 index 0000000..bb52ecd --- /dev/null +++ b/minimal_drivers/l0/src/global.rs @@ -0,0 +1,8 @@ +use core::sync::atomic::AtomicU32; + +pub static SYSTEM_CLOCK: AtomicU32 = AtomicU32::new(4_000_000); + +pub fn get_system_clock() -> u32 { + use core::sync::atomic::Ordering; + SYSTEM_CLOCK.load(Ordering::SeqCst) +} diff --git a/minimal_drivers/l0/src/lib.rs b/minimal_drivers/l0/src/lib.rs index 1f0c362..9968b88 100644 --- a/minimal_drivers/l0/src/lib.rs +++ b/minimal_drivers/l0/src/lib.rs @@ -8,9 +8,23 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] +// * Private to l0 mod entry_point; +mod global; mod rust_entry_point; -// Generated controller bindings -mod controller; -pub use controller::*; +// TODO, Add features +// #[cfg(feature = "stm32l475xx")] +mod stm32l475xx; +use stm32l475xx as chip; + +// * Public APIs usable when l0 is a dependency +mod utility; // Macro export makes macros always public +pub use global::get_system_clock; + +// Generated controller bindings from C to Rust +pub mod controller; + +// Whats the difference between the chip module and controller module +// controller.rs contains bindings for ARM Architecture + Chip specific peripheral structs (STM32L475xx) +// chip.rs contains only Chip specific functionality (STM32L475xx) diff --git a/minimal_drivers/l0/src/stm32l475xx/mod.rs b/minimal_drivers/l0/src/stm32l475xx/mod.rs new file mode 100644 index 0000000..644f321 --- /dev/null +++ b/minimal_drivers/l0/src/stm32l475xx/mod.rs @@ -0,0 +1,2 @@ +mod private; +pub use private::*; diff --git a/minimal_drivers/l0/src/stm32l475xx/private.rs b/minimal_drivers/l0/src/stm32l475xx/private.rs new file mode 100644 index 0000000..2a059eb --- /dev/null +++ b/minimal_drivers/l0/src/stm32l475xx/private.rs @@ -0,0 +1,30 @@ +use crate::{get_port, global::SYSTEM_CLOCK, read_register}; +use core::ptr::read_volatile; +use core::sync::atomic::Ordering; + +use crate::controller::{RCC_TypeDef, RCC_BASE}; + +pub fn controller_init() { + // Update the System clock + let rcc_port = get_port!(RCC_TypeDef, RCC_BASE); + let cr_data = read_register!(rcc_port, CR); + let msi_range = (cr_data >> 4) & 0xF; + let system_clock: u32 = match msi_range { + 0 => todo!(), + 1 => todo!(), + 2 => todo!(), + 3 => todo!(), + 4 => 1_000_000, + 5 => 2_000_000, + 6 => 4_000_000, + 7 => todo!(), + 8 => todo!(), + 9 => todo!(), + 10 => todo!(), + 11 => todo!(), + _ => unreachable!(), + }; + SYSTEM_CLOCK.store(system_clock, Ordering::SeqCst) + + // TODO, Do more things +} diff --git a/minimal_drivers/l0/src/utility/mod.rs b/minimal_drivers/l0/src/utility/mod.rs new file mode 100644 index 0000000..1840c82 --- /dev/null +++ b/minimal_drivers/l0/src/utility/mod.rs @@ -0,0 +1,21 @@ +#[macro_export] +macro_rules! get_port { + ($register_map_struct:ident, $address:ident) => { + unsafe { &mut *($address as *mut $register_map_struct) } + }; +} + +#[macro_export] +macro_rules! read_register { + ($port:ident, $register_name:ident) => { + unsafe { read_volatile(&$port.$register_name) } + }; +} + +// TODO, Overload this macro to support $data:literal +#[macro_export] +macro_rules! write_register { + ($port:ident, $register_name:ident, $data:ident) => { + unsafe { write_volatile(&mut $port.$register_name, $data) } + }; +} From 0b520bc8ff5136e9c9710308d338d7105c1ee4ca Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:22:14 -0800 Subject: [PATCH 04/17] Added usart interface --- minimal_drivers/l3/src/interfaces/mod.rs | 3 ++ .../l3/src/interfaces/usart_interface.rs | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 minimal_drivers/l3/src/interfaces/usart_interface.rs diff --git a/minimal_drivers/l3/src/interfaces/mod.rs b/minimal_drivers/l3/src/interfaces/mod.rs index c739dee..7fbf6bc 100644 --- a/minimal_drivers/l3/src/interfaces/mod.rs +++ b/minimal_drivers/l3/src/interfaces/mod.rs @@ -4,5 +4,8 @@ pub use generic_interface::*; pub mod gpio_interface; pub use gpio_interface::*; +pub mod usart_interface; +pub use usart_interface::*; + pub mod utility_interface; pub use utility_interface::*; diff --git a/minimal_drivers/l3/src/interfaces/usart_interface.rs b/minimal_drivers/l3/src/interfaces/usart_interface.rs new file mode 100644 index 0000000..e12b249 --- /dev/null +++ b/minimal_drivers/l3/src/interfaces/usart_interface.rs @@ -0,0 +1,36 @@ +use core::fmt::Write; + +pub trait UsartOut { + fn write_character(&mut self, data: char); + fn write_string(&mut self, data: &str) { + data.chars().for_each(|d| { + self.write_character(d); + }); + } +} + +pub trait UsartIn { + fn read_character(&mut self) -> char; + fn read_chars(&mut self, data: &mut [char]) { + let c = self.read_character(); + data.iter_mut().for_each(|d| { + *d = c; + }); + } +} + +pub trait UsartInOut: UsartIn + UsartOut {} + +impl Write for dyn UsartOut { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write_string(&s); + Ok(()) + } +} + +impl Write for dyn UsartInOut { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write_string(&s); + Ok(()) + } +} From 58d440763d0f29e414f69c3e75bd089fef878e48 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:23:27 -0800 Subject: [PATCH 05/17] Added usart driver and minor modifications to other drivers --- .../l3/src/interfaces/generic_interface.rs | 2 +- minimal_drivers/l3/src/stm32l475xx/gpio.rs | 54 +++--- minimal_drivers/l3/src/stm32l475xx/mod.rs | 8 +- minimal_drivers/l3/src/stm32l475xx/rcc.rs | 10 +- minimal_drivers/l3/src/stm32l475xx/usart.rs | 167 ++++++++++++++++++ 5 files changed, 211 insertions(+), 30 deletions(-) create mode 100644 minimal_drivers/l3/src/stm32l475xx/usart.rs diff --git a/minimal_drivers/l3/src/interfaces/generic_interface.rs b/minimal_drivers/l3/src/interfaces/generic_interface.rs index ec3717d..9eb97d5 100644 --- a/minimal_drivers/l3/src/interfaces/generic_interface.rs +++ b/minimal_drivers/l3/src/interfaces/generic_interface.rs @@ -1,5 +1,5 @@ pub trait Port { - fn get_port(&self) -> &'static mut T { + fn get_port() -> &'static mut T { let mutable_ref = unsafe { &mut *(B as *mut T) }; mutable_ref } diff --git a/minimal_drivers/l3/src/stm32l475xx/gpio.rs b/minimal_drivers/l3/src/stm32l475xx/gpio.rs index a30c748..5624439 100644 --- a/minimal_drivers/l3/src/stm32l475xx/gpio.rs +++ b/minimal_drivers/l3/src/stm32l475xx/gpio.rs @@ -2,11 +2,9 @@ use core::ptr::{read_volatile, write_volatile}; -use crate::{EnumToNum, GpioIn, GpioOut, GpioValue, PeripheralConfiguration, Port, Singleton}; -use l0::{ - GPIO_TypeDef, GPIOA_BASE, GPIOB_BASE, GPIOC_BASE, GPIOD_BASE, GPIOE_BASE, GPIOF_BASE, - GPIOG_BASE, GPIOH_BASE, -}; +use crate::{EnumToNum, GpioIn, GpioOut, GpioValue, PeripheralConfiguration}; +use crate::{Port, Singleton}; +use l0::controller::*; pub enum GPIOMode { Input, @@ -132,40 +130,40 @@ impl GPIORegister { } fn set_moder(&mut self, moder: &GPIOMode) { - let mut moder_data = unsafe { read_volatile(&self.get_port().MODER) }; + let mut moder_data = unsafe { read_volatile(&Self::get_port().MODER) }; moder_data &= !(0x3 << self.pin * 2); // clear mode register moder_data |= moder.to_num() << self.pin * 2; - unsafe { write_volatile(&mut self.get_port().MODER, moder_data) }; + unsafe { write_volatile(&mut Self::get_port().MODER, moder_data) }; } fn set_otyper(&mut self, otyper: &GPIOType) { - let mut otyper_data = unsafe { read_volatile(&self.get_port().OTYPER) }; + let mut otyper_data = unsafe { read_volatile(&Self::get_port().OTYPER) }; otyper_data &= !(0x1 << self.pin); // clear type register otyper_data |= otyper.to_num() << self.pin; - unsafe { write_volatile(&mut self.get_port().OTYPER, otyper_data) }; + unsafe { write_volatile(&mut Self::get_port().OTYPER, otyper_data) }; } fn set_ospeedr(&mut self, ospeedr: &GPIOSpeed) { - let mut ospeedr_data = unsafe { read_volatile(&self.get_port().OSPEEDR) }; + let mut ospeedr_data = unsafe { read_volatile(&Self::get_port().OSPEEDR) }; ospeedr_data &= !(0x3 << self.pin * 2); // clear ospeedr register ospeedr_data |= ospeedr.to_num() << self.pin * 2; - unsafe { write_volatile(&mut self.get_port().OSPEEDR, ospeedr_data) }; + unsafe { write_volatile(&mut Self::get_port().OSPEEDR, ospeedr_data) }; } fn set_pupdr(&mut self, pupdr: &GPIOPull) { - let mut pupdr_data = unsafe { read_volatile(&self.get_port().PUPDR) }; + let mut pupdr_data = unsafe { read_volatile(&Self::get_port().PUPDR) }; pupdr_data &= !(0x3 << self.pin * 2); pupdr_data |= pupdr.to_num() << self.pin * 2; - unsafe { write_volatile(&mut self.get_port().PUPDR, pupdr_data) }; + unsafe { write_volatile(&mut Self::get_port().PUPDR, pupdr_data) }; } fn set_afr(&mut self, afr: &GPIOAlternate) { let (register, pin) = if self.pin > 7 { // Use AFRH - (&mut self.get_port().AFR[1], self.pin - 7) + (&mut Self::get_port().AFR[1], self.pin - 7) } else { // Use AFRL - (&mut self.get_port().AFR[0], self.pin) + (&mut Self::get_port().AFR[0], self.pin) }; let mut afr_data = unsafe { read_volatile(register) }; @@ -175,15 +173,15 @@ impl GPIORegister { } fn set_bsrr(&mut self) { - let mut bsrr_data = unsafe { read_volatile(&self.get_port().BSRR) }; + let mut bsrr_data = unsafe { read_volatile(&Self::get_port().BSRR) }; bsrr_data |= 1 << self.pin; - unsafe { write_volatile(&mut self.get_port().BSRR, bsrr_data) }; + unsafe { write_volatile(&mut Self::get_port().BSRR, bsrr_data) }; } fn set_brr(&mut self) { - let mut brr_data = unsafe { read_volatile(&self.get_port().BRR) }; + let mut brr_data = unsafe { read_volatile(&Self::get_port().BRR) }; brr_data |= 1 << self.pin; - unsafe { write_volatile(&mut self.get_port().BRR, brr_data) }; + unsafe { write_volatile(&mut Self::get_port().BRR, brr_data) }; } } @@ -198,7 +196,7 @@ impl GpioOut for GPIORegister { impl GpioIn for GPIORegister { fn read(&self) -> GpioValue { - let idr = unsafe { read_volatile(&self.get_port().IDR) }; + let idr = unsafe { read_volatile(&Self::get_port().IDR) }; let value = (idr >> self.pin) & 0x01; let value = match value { 0x0 => GpioValue::Low, @@ -213,7 +211,7 @@ impl GpioIn for GPIORegister { pub struct GPIOPeripheral; impl GPIOPeripheral { - pub fn configure_as_output(&self, pin: u32) -> impl GpioOut { + pub fn configure_for_output(&self, pin: u32) -> impl GpioOut { let config = GPIOConfig { pin, moder: GPIOMode::Output, @@ -225,7 +223,7 @@ impl GPIOPeripheral { self.configure(&config) } - pub fn configure_as_input(&self, pin: u32) -> impl GpioIn { + pub fn configure_for_input(&self, pin: u32) -> impl GpioIn { let config = GPIOConfig { pin, moder: GPIOMode::Input, @@ -236,6 +234,18 @@ impl GPIOPeripheral { }; self.configure(&config) } + + pub fn configure_for_usart(&self, afr: GPIOAlternate, pin: u32) -> GPIORegister { + let config = GPIOConfig { + pin, + moder: GPIOMode::AlternateFunction, + otyper: GPIOType::PushPull, + pupdr: GPIOPull::NoPullupOrPulldown, + ospeedr: GPIOSpeed::VeryHighSpeed, + afr, + }; + self.configure(&config) + } } pub struct GPIOConfig { diff --git a/minimal_drivers/l3/src/stm32l475xx/mod.rs b/minimal_drivers/l3/src/stm32l475xx/mod.rs index ad970ff..68dd1da 100644 --- a/minimal_drivers/l3/src/stm32l475xx/mod.rs +++ b/minimal_drivers/l3/src/stm32l475xx/mod.rs @@ -1,5 +1,9 @@ -mod gpio; mod rcc; +pub use rcc::*; +// Contains interfaces +mod gpio; pub use gpio::*; -pub use rcc::*; + +mod usart; +pub use usart::*; diff --git a/minimal_drivers/l3/src/stm32l475xx/rcc.rs b/minimal_drivers/l3/src/stm32l475xx/rcc.rs index 78c5542..8c85714 100644 --- a/minimal_drivers/l3/src/stm32l475xx/rcc.rs +++ b/minimal_drivers/l3/src/stm32l475xx/rcc.rs @@ -2,7 +2,7 @@ use core::ptr::{read_volatile, write_volatile}; -use l0::{RCC_TypeDef, RCC_BASE}; +use l0::controller::{RCC_TypeDef, RCC_BASE}; use l2::bitflags; use crate::{Port, Singleton}; @@ -34,18 +34,18 @@ pub struct RCCPeripheral; impl RCCPeripheral { pub fn set_ahb2enr(&mut self, ahb2: RCC_AHB2ENR) { - let mut ahb2enr = unsafe { read_volatile(&mut self.get_port().AHB2ENR) }; + let mut ahb2enr = unsafe { read_volatile(&mut Self::get_port().AHB2ENR) }; ahb2enr |= ahb2.bits(); unsafe { - write_volatile(&mut self.get_port().AHB2ENR, ahb2enr); + write_volatile(&mut Self::get_port().AHB2ENR, ahb2enr); } } pub fn set_apb2enr(&mut self, apb2: RCC_APB2ENR) { - let mut apb2enr = unsafe { read_volatile(&mut self.get_port().AHB2ENR) }; + let mut apb2enr = unsafe { read_volatile(&mut Self::get_port().APB2ENR) }; apb2enr |= apb2.bits(); unsafe { - write_volatile(&mut self.get_port().AHB2ENR, apb2enr); + write_volatile(&mut Self::get_port().APB2ENR, apb2enr); } } } diff --git a/minimal_drivers/l3/src/stm32l475xx/usart.rs b/minimal_drivers/l3/src/stm32l475xx/usart.rs new file mode 100644 index 0000000..1f30ee8 --- /dev/null +++ b/minimal_drivers/l3/src/stm32l475xx/usart.rs @@ -0,0 +1,167 @@ +// TODO, Remove this later +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use core::ptr::{read_volatile, write_volatile}; + +use l0::{ + controller::{USART_TypeDef, USART1_BASE}, + get_system_clock, +}; +use l2::bitflags; + +use crate::{PeripheralConfiguration, Port, Singleton, UsartIn, UsartInOut, UsartOut}; + +bitflags! { + pub struct USART_CR1 : u32 { + const UE = 1 << 0; + const RE = 1 << 2; + const TE = 1 << 3; + const M0 = 1 << 12; + const OVER8 = 1 << 15; + const M1 = 1 << 28; + } +} + +bitflags! { + pub struct USART_CR2 : u32 { + const STOP = 3 << 12; + } +} + +pub enum USARTWordLength { + Len8, + Len9, + Len7, +} + +pub enum USARTStopBit { + Bit1_0, + Bit0_5, + Bit2_0, + Bit1_5, +} + +pub enum USARTMode { + Inactive, + RxOnly, + TxOnly, + RxTx, +} + +pub struct USARTRegister {} + +impl USARTRegister { + fn via_configure(&mut self, config: &USARTConfig) { + // Disable USART + self.reset_cr1(USART_CR1::UE); + + // Baud rate + let system_clock = get_system_clock(); + let usartdiv = system_clock / config.baud_rate; + unsafe { write_volatile(&mut Self::get_port().BRR, usartdiv) }; + + // Stop bits + let mut cr2_data = unsafe { read_volatile(&Self::get_port().CR2) }; + cr2_data &= (!USART_CR2::STOP).bits(); + unsafe { write_volatile(&mut Self::get_port().CR2, cr2_data) }; + + // Set word length, usart mode and enable + let mut cr1_data = unsafe { read_volatile(&Self::get_port().CR1) }; + cr1_data &= (!USART_CR1::all()).bits(); + + // Set word length + cr1_data |= match config.word_length { + USARTWordLength::Len8 => 0, + USARTWordLength::Len9 => USART_CR1::M0.bits(), + USARTWordLength::Len7 => USART_CR1::M1.bits(), + }; + + // Set Mode + cr1_data |= match config.mode { + USARTMode::Inactive => 0, + USARTMode::RxOnly => USART_CR1::RE.bits(), + USARTMode::TxOnly => USART_CR1::TE.bits(), + USARTMode::RxTx => (USART_CR1::RE | USART_CR1::TE).bits(), + }; + + // Enable + cr1_data |= USART_CR1::UE.bits(); + + unsafe { write_volatile(&mut Self::get_port().CR1, cr1_data) }; + } + + fn reset_cr1(&mut self, cr1: USART_CR1) { + let mut cr1_data = unsafe { read_volatile(&Self::get_port().CR1) }; + cr1_data &= !(cr1.bits()); + unsafe { write_volatile(&mut Self::get_port().CR1, cr1_data) }; + } +} + +impl Port for USARTRegister {} + +impl UsartIn for USARTRegister { + fn read_character(&mut self) -> char { + todo!() + } +} + +impl UsartOut for USARTRegister { + fn write_character(&mut self, data: char) { + let is_bit_set = |bit: u32| { + let isr_data = unsafe { read_volatile(&Self::get_port().ISR) }; + isr_data & (1 << bit) == 0 + }; + + while is_bit_set(7) {} + unsafe { write_volatile(&mut Self::get_port().TDR, data as u16) }; + while is_bit_set(6) {} + } +} + +impl UsartInOut for USARTRegister {} + +pub struct USARTPeripheral {} + +impl USARTPeripheral { + pub fn configure_as_rx(&self) -> impl UsartIn { + let usart = USARTRegister:: {}; + usart + } + + pub fn configure_as_tx(&self) -> impl UsartOut { + let usart = USARTRegister:: {}; + usart + } + + pub fn configure_default_rx_tx(&self) -> impl UsartInOut { + self.configure(&USARTConfig { + mode: USARTMode::RxTx, + word_length: USARTWordLength::Len8, + stop_bit: USARTStopBit::Bit1_0, + baud_rate: 115200, + }) + } +} + +pub struct USARTConfig { + mode: USARTMode, + word_length: USARTWordLength, + stop_bit: USARTStopBit, + baud_rate: u32, +} + +impl PeripheralConfiguration for USARTPeripheral { + type Config = USARTConfig; + type Register = USARTRegister; + + fn configure(&self, configuration: &Self::Config) -> Self::Register { + let mut usart = USARTRegister:: {}; + usart.via_configure(&configuration); + usart + } +} + +type USART1 = USARTPeripheral; + +pub static USART1_PORT: Singleton = Singleton::new(USART1 {}); From 69635811573ecfd189701e5df245439ebab6a116 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:23:38 -0800 Subject: [PATCH 06/17] Updated main.rs example --- minimal_drivers/l5/src/main.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/minimal_drivers/l5/src/main.rs b/minimal_drivers/l5/src/main.rs index 6093d05..3aa4fc6 100644 --- a/minimal_drivers/l5/src/main.rs +++ b/minimal_drivers/l5/src/main.rs @@ -20,27 +20,38 @@ pub fn spin_delay(delay: u32) { #[cfg(all(target_arch = "arm", target_os = "none"))] #[no_mangle] fn main() -> ! { + use core::fmt::Write; + use l0::*; use l3::*; use l4::*; - // Activate clock control for GPIOA and GPIOC let mut rcc_peripheral = RCC_PORT.take(); - rcc_peripheral.set_ahb2enr(RCC_AHB2ENR::GPIOAEN | RCC_AHB2ENR::GPIOCEN); - let gpioa_peripheral = GPIOA_PORT.take(); - let gpioc_peripheral = GPIOC_PORT.take(); + // Activate clock control for GPIOA, GPIOB and GPIOC and USART1EN + rcc_peripheral.set_ahb2enr(RCC_AHB2ENR::GPIOAEN | RCC_AHB2ENR::GPIOBEN | RCC_AHB2ENR::GPIOCEN); + rcc_peripheral.set_apb2enr(RCC_APB2ENR::USART1EN); + let gpioa_peripheral = GPIOA_PORT.take(); // Configure GPIOA port and Pin 5 as output - let mut gpio_out_at_pin5 = gpioa_peripheral.configure_as_output(5); + let mut gpio_out_at_pin5 = gpioa_peripheral.configure_for_output(5); + let gpiob_peripheral = GPIOB_PORT.take(); + // Configure GPIOB port Pin 6 and Pin 7 for USART + gpiob_peripheral.configure_for_usart(GPIOAlternate::AF7, 6); + gpiob_peripheral.configure_for_usart(GPIOAlternate::AF7, 7); + + let usart1_rx_tx: &mut dyn UsartInOut = &mut USART1_PORT.take().configure_default_rx_tx(); + + let gpioc_peripheral = GPIOC_PORT.take(); // Configure GPIOC port and Pin 13 as input - let mut gpio_in_at_pin13 = gpioc_peripheral.configure_as_input(13); + let mut gpio_in_at_pin13 = gpioc_peripheral.configure_for_input(13); // Created led module let mut led = Led::new(&mut gpio_out_at_pin5); let button = Button::new(&mut gpio_in_at_pin13, GpioValue::High); let mut time; + let mut counter = 0; loop { if button.pressed() { time = 20_000; @@ -49,9 +60,17 @@ fn main() -> ! { } led.on(); + // Can also use write! and writeln! + usart1_rx_tx + .write_fmt(format_args!("LED ON: {}\r\n", counter)) + .unwrap(); spin_delay(time); led.off(); + usart1_rx_tx + .write_fmt(format_args!("LED OFF: {}\r\n", counter)) + .unwrap(); spin_delay(time); + counter += 1; } } From df815895bd3223e7a0d5d93920cb79559cf7a0b5 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:24:55 -0800 Subject: [PATCH 07/17] README updates --- minimal_drivers/README.md | 42 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/minimal_drivers/README.md b/minimal_drivers/README.md index 4ca70cf..488c1cd 100644 --- a/minimal_drivers/README.md +++ b/minimal_drivers/README.md @@ -3,14 +3,19 @@ - [Microcontrollers layers](#microcontrollers-layers) - [Pre-requisites](#pre-requisites) - [GPIO](#gpio) +- [Terminology](#terminology) - [Changelog](#changelog) + - [L0 Layer - Controller](#l0-layer---controller) + - [Global](#global) + - [Utility](#utility) + - [STM32L475xx](#stm32l475xx) - [L2 Layer - Utilities](#l2-layer---utilities) - [Own implementation](#own-implementation) - [Crates.io](#cratesio) - [L3 Layer - Interfaces](#l3-layer---interfaces) - [L3 Layer - Drivers](#l3-layer---drivers) - [L3 Layer - Miscellaneous](#l3-layer---miscellaneous) - - [L4](#l4) + - [L4 Sensor / Actuator](#l4-sensor--actuator) # Minimal Drivers @@ -60,7 +65,7 @@ This code has been tested on graph BT; subgraph Port GPIOA-H - subgraph Periphal + subgraph Peripheral GPIO subgraph Register MODER @@ -73,9 +78,35 @@ graph BT; end end ``` +# Terminology + +- Chip +- Controller +- Port +- Peripheral +- Register # Changelog +## L0 Layer - Controller + +### Global + +- System Clock + - Every microcontroller will have a system clock in Hz + +### Utility + +- Common macros for port and register access + - `get_port!` + - `read_register!` + - `write_register!` + +### STM32L475xx + +- Controller initialization + - For now it just updates the System Clock so that it can be used by upper layer (drivers etc) + ## L2 Layer - Utilities ### Own implementation @@ -99,13 +130,18 @@ graph BT; - RCC - GPIO + - [x] Input + - [x] Output +- USART + - [ ] Read + - [x] Write ## L3 Layer - Miscellaneous - Singleton - Safe access to global ports -## L4 +## L4 Sensor / Actuator - Led - Button From 8a167cc36a36fc6fce9f784cc40dd4a85b20d99b Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 06:40:13 -0800 Subject: [PATCH 08/17] Sanitize rcc module --- minimal_drivers/l0/src/utility/mod.rs | 4 +- .../l3/src/interfaces/generic_interface.rs | 5 ++- minimal_drivers/l3/src/stm32l475xx/rcc.rs | 37 ++++++++++++------- minimal_drivers/l5/src/main.rs | 7 ++-- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/minimal_drivers/l0/src/utility/mod.rs b/minimal_drivers/l0/src/utility/mod.rs index 1840c82..a1c6653 100644 --- a/minimal_drivers/l0/src/utility/mod.rs +++ b/minimal_drivers/l0/src/utility/mod.rs @@ -7,7 +7,7 @@ macro_rules! get_port { #[macro_export] macro_rules! read_register { - ($port:ident, $register_name:ident) => { + ($port:expr, $register_name:ident) => { unsafe { read_volatile(&$port.$register_name) } }; } @@ -15,7 +15,7 @@ macro_rules! read_register { // TODO, Overload this macro to support $data:literal #[macro_export] macro_rules! write_register { - ($port:ident, $register_name:ident, $data:ident) => { + ($port:expr, $register_name:ident, $data:ident) => { unsafe { write_volatile(&mut $port.$register_name, $data) } }; } diff --git a/minimal_drivers/l3/src/interfaces/generic_interface.rs b/minimal_drivers/l3/src/interfaces/generic_interface.rs index 9eb97d5..c30b12a 100644 --- a/minimal_drivers/l3/src/interfaces/generic_interface.rs +++ b/minimal_drivers/l3/src/interfaces/generic_interface.rs @@ -1,7 +1,8 @@ +use l0::get_port; + pub trait Port { fn get_port() -> &'static mut T { - let mutable_ref = unsafe { &mut *(B as *mut T) }; - mutable_ref + get_port!(T, B) } } diff --git a/minimal_drivers/l3/src/stm32l475xx/rcc.rs b/minimal_drivers/l3/src/stm32l475xx/rcc.rs index 8c85714..2d4c229 100644 --- a/minimal_drivers/l3/src/stm32l475xx/rcc.rs +++ b/minimal_drivers/l3/src/stm32l475xx/rcc.rs @@ -2,7 +2,10 @@ use core::ptr::{read_volatile, write_volatile}; -use l0::controller::{RCC_TypeDef, RCC_BASE}; +use l0::{ + controller::{RCC_TypeDef, RCC_BASE}, + read_register, write_register, +}; use l2::bitflags; use crate::{Port, Singleton}; @@ -29,23 +32,31 @@ bitflags! { } } -// Put functionality here i.e various valid configurations for your port -pub struct RCCPeripheral; +pub struct RCCRegister { + port: &'static mut RCC_TypeDef, +} -impl RCCPeripheral { +impl RCCRegister { pub fn set_ahb2enr(&mut self, ahb2: RCC_AHB2ENR) { - let mut ahb2enr = unsafe { read_volatile(&mut Self::get_port().AHB2ENR) }; - ahb2enr |= ahb2.bits(); - unsafe { - write_volatile(&mut Self::get_port().AHB2ENR, ahb2enr); - } + let mut ahb2enr_data = read_register!(self.port, AHB2ENR); + ahb2enr_data |= ahb2.bits(); + write_register!(self.port, AHB2ENR, ahb2enr_data); } pub fn set_apb2enr(&mut self, apb2: RCC_APB2ENR) { - let mut apb2enr = unsafe { read_volatile(&mut Self::get_port().APB2ENR) }; - apb2enr |= apb2.bits(); - unsafe { - write_volatile(&mut Self::get_port().APB2ENR, apb2enr); + let mut apb2enr_data = read_register!(self.port, APB2ENR); + apb2enr_data |= apb2.bits(); + write_register!(self.port, APB2ENR, apb2enr_data); + } +} + +// Put functionality here i.e various valid configurations for your port +pub struct RCCPeripheral; + +impl RCCPeripheral { + pub fn get_register(&self) -> RCCRegister { + RCCRegister { + port: Self::get_port(), } } } diff --git a/minimal_drivers/l5/src/main.rs b/minimal_drivers/l5/src/main.rs index 3aa4fc6..10cf08e 100644 --- a/minimal_drivers/l5/src/main.rs +++ b/minimal_drivers/l5/src/main.rs @@ -25,11 +25,10 @@ fn main() -> ! { use l3::*; use l4::*; - let mut rcc_peripheral = RCC_PORT.take(); - + let mut rcc_register = RCC_PORT.take().get_register(); // Activate clock control for GPIOA, GPIOB and GPIOC and USART1EN - rcc_peripheral.set_ahb2enr(RCC_AHB2ENR::GPIOAEN | RCC_AHB2ENR::GPIOBEN | RCC_AHB2ENR::GPIOCEN); - rcc_peripheral.set_apb2enr(RCC_APB2ENR::USART1EN); + rcc_register.set_ahb2enr(RCC_AHB2ENR::GPIOAEN | RCC_AHB2ENR::GPIOBEN | RCC_AHB2ENR::GPIOCEN); + rcc_register.set_apb2enr(RCC_APB2ENR::USART1EN); let gpioa_peripheral = GPIOA_PORT.take(); // Configure GPIOA port and Pin 5 as output From 3fa557bbd80adf861e34bec0fe8558210d7ec0b3 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 21:05:26 -0800 Subject: [PATCH 09/17] Updated read_register and write_register macros --- minimal_drivers/l0/src/stm32l475xx/private.rs | 2 +- minimal_drivers/l0/src/utility/mod.rs | 8 ++++---- minimal_drivers/l3/src/stm32l475xx/rcc.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/minimal_drivers/l0/src/stm32l475xx/private.rs b/minimal_drivers/l0/src/stm32l475xx/private.rs index 2a059eb..2896e72 100644 --- a/minimal_drivers/l0/src/stm32l475xx/private.rs +++ b/minimal_drivers/l0/src/stm32l475xx/private.rs @@ -7,7 +7,7 @@ use crate::controller::{RCC_TypeDef, RCC_BASE}; pub fn controller_init() { // Update the System clock let rcc_port = get_port!(RCC_TypeDef, RCC_BASE); - let cr_data = read_register!(rcc_port, CR); + let cr_data = read_register!(rcc_port.CR); let msi_range = (cr_data >> 4) & 0xF; let system_clock: u32 = match msi_range { 0 => todo!(), diff --git a/minimal_drivers/l0/src/utility/mod.rs b/minimal_drivers/l0/src/utility/mod.rs index a1c6653..d8d7253 100644 --- a/minimal_drivers/l0/src/utility/mod.rs +++ b/minimal_drivers/l0/src/utility/mod.rs @@ -7,15 +7,15 @@ macro_rules! get_port { #[macro_export] macro_rules! read_register { - ($port:expr, $register_name:ident) => { - unsafe { read_volatile(&$port.$register_name) } + ($register:expr) => { + unsafe { read_volatile(&$register) } }; } // TODO, Overload this macro to support $data:literal #[macro_export] macro_rules! write_register { - ($port:expr, $register_name:ident, $data:ident) => { - unsafe { write_volatile(&mut $port.$register_name, $data) } + ($register:expr, $data:ident) => { + unsafe { write_volatile(&mut $register, $data) } }; } diff --git a/minimal_drivers/l3/src/stm32l475xx/rcc.rs b/minimal_drivers/l3/src/stm32l475xx/rcc.rs index 2d4c229..b021e26 100644 --- a/minimal_drivers/l3/src/stm32l475xx/rcc.rs +++ b/minimal_drivers/l3/src/stm32l475xx/rcc.rs @@ -38,15 +38,15 @@ pub struct RCCRegister { impl RCCRegister { pub fn set_ahb2enr(&mut self, ahb2: RCC_AHB2ENR) { - let mut ahb2enr_data = read_register!(self.port, AHB2ENR); + let mut ahb2enr_data = read_register!(self.port.AHB2ENR); ahb2enr_data |= ahb2.bits(); - write_register!(self.port, AHB2ENR, ahb2enr_data); + write_register!(self.port.AHB2ENR, ahb2enr_data); } pub fn set_apb2enr(&mut self, apb2: RCC_APB2ENR) { - let mut apb2enr_data = read_register!(self.port, APB2ENR); + let mut apb2enr_data = read_register!(self.port.APB2ENR); apb2enr_data |= apb2.bits(); - write_register!(self.port, APB2ENR, apb2enr_data); + write_register!(self.port.APB2ENR, apb2enr_data); } } From 34e4a09f9cfce22781404ee9539effd7f1de03e1 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sat, 18 Feb 2023 23:55:20 -0800 Subject: [PATCH 10/17] Updated gpio driver --- minimal_drivers/l3/src/stm32l475xx/gpio.rs | 58 +++++++++++----------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/minimal_drivers/l3/src/stm32l475xx/gpio.rs b/minimal_drivers/l3/src/stm32l475xx/gpio.rs index 5624439..f69d5d7 100644 --- a/minimal_drivers/l3/src/stm32l475xx/gpio.rs +++ b/minimal_drivers/l3/src/stm32l475xx/gpio.rs @@ -2,9 +2,9 @@ use core::ptr::{read_volatile, write_volatile}; +use crate::Singleton; use crate::{EnumToNum, GpioIn, GpioOut, GpioValue, PeripheralConfiguration}; -use crate::{Port, Singleton}; -use l0::controller::*; +use l0::{controller::*, get_port, read_register, write_register}; pub enum GPIOMode { Input, @@ -114,13 +114,12 @@ impl EnumToNum for GPIOAlternate { } } -pub struct GPIORegister { +pub struct GPIORegister { + port: &'static mut GPIO_TypeDef, pin: u32, } -impl Port for GPIORegister {} - -impl GPIORegister { +impl GPIORegister { fn via_config(&mut self, config: &GPIOConfig) { self.set_moder(&config.moder); self.set_otyper(&config.otyper); @@ -130,62 +129,62 @@ impl GPIORegister { } fn set_moder(&mut self, moder: &GPIOMode) { - let mut moder_data = unsafe { read_volatile(&Self::get_port().MODER) }; + let mut moder_data = read_register!(self.port.MODER); moder_data &= !(0x3 << self.pin * 2); // clear mode register moder_data |= moder.to_num() << self.pin * 2; - unsafe { write_volatile(&mut Self::get_port().MODER, moder_data) }; + write_register!(self.port.MODER, moder_data); } fn set_otyper(&mut self, otyper: &GPIOType) { - let mut otyper_data = unsafe { read_volatile(&Self::get_port().OTYPER) }; + let mut otyper_data = read_register!(self.port.OTYPER); otyper_data &= !(0x1 << self.pin); // clear type register otyper_data |= otyper.to_num() << self.pin; - unsafe { write_volatile(&mut Self::get_port().OTYPER, otyper_data) }; + write_register!(self.port.OTYPER, otyper_data); } fn set_ospeedr(&mut self, ospeedr: &GPIOSpeed) { - let mut ospeedr_data = unsafe { read_volatile(&Self::get_port().OSPEEDR) }; + let mut ospeedr_data = read_register!(self.port.OSPEEDR); ospeedr_data &= !(0x3 << self.pin * 2); // clear ospeedr register ospeedr_data |= ospeedr.to_num() << self.pin * 2; - unsafe { write_volatile(&mut Self::get_port().OSPEEDR, ospeedr_data) }; + write_register!(self.port.OSPEEDR, ospeedr_data); } fn set_pupdr(&mut self, pupdr: &GPIOPull) { - let mut pupdr_data = unsafe { read_volatile(&Self::get_port().PUPDR) }; + let mut pupdr_data = read_register!(self.port.PUPDR); pupdr_data &= !(0x3 << self.pin * 2); pupdr_data |= pupdr.to_num() << self.pin * 2; - unsafe { write_volatile(&mut Self::get_port().PUPDR, pupdr_data) }; + write_register!(self.port.PUPDR, pupdr_data); } fn set_afr(&mut self, afr: &GPIOAlternate) { - let (register, pin) = if self.pin > 7 { + let (index, pin) = if self.pin > 7 { // Use AFRH - (&mut Self::get_port().AFR[1], self.pin - 7) + (1, self.pin - 7) } else { // Use AFRL - (&mut Self::get_port().AFR[0], self.pin) + (0, self.pin) }; - let mut afr_data = unsafe { read_volatile(register) }; + let mut afr_data = read_register!(self.port.AFR[index]); afr_data &= !(0xF << (pin << 2)); afr_data |= afr.to_num() << (pin << 2); - unsafe { write_volatile(register, afr_data) }; + write_register!(self.port.AFR[index], afr_data); } fn set_bsrr(&mut self) { - let mut bsrr_data = unsafe { read_volatile(&Self::get_port().BSRR) }; + let mut bsrr_data = read_register!(self.port.BSRR); bsrr_data |= 1 << self.pin; - unsafe { write_volatile(&mut Self::get_port().BSRR, bsrr_data) }; + write_register!(self.port.BSRR, bsrr_data); } fn set_brr(&mut self) { - let mut brr_data = unsafe { read_volatile(&Self::get_port().BRR) }; + let mut brr_data = read_register!(self.port.BRR); brr_data |= 1 << self.pin; - unsafe { write_volatile(&mut Self::get_port().BRR, brr_data) }; + write_register!(self.port.BRR, brr_data); } } -impl GpioOut for GPIORegister { +impl GpioOut for GPIORegister { fn write(&mut self, value: GpioValue) { match value { GpioValue::Low => self.set_brr(), @@ -194,9 +193,9 @@ impl GpioOut for GPIORegister { } } -impl GpioIn for GPIORegister { +impl GpioIn for GPIORegister { fn read(&self) -> GpioValue { - let idr = unsafe { read_volatile(&Self::get_port().IDR) }; + let idr = read_register!(self.port.IDR); let value = (idr >> self.pin) & 0x01; let value = match value { 0x0 => GpioValue::Low, @@ -235,7 +234,7 @@ impl GPIOPeripheral { self.configure(&config) } - pub fn configure_for_usart(&self, afr: GPIOAlternate, pin: u32) -> GPIORegister { + pub fn configure_for_usart(&self, afr: GPIOAlternate, pin: u32) -> GPIORegister { let config = GPIOConfig { pin, moder: GPIOMode::AlternateFunction, @@ -259,10 +258,11 @@ pub struct GPIOConfig { impl PeripheralConfiguration for GPIOPeripheral { type Config = GPIOConfig; - type Register = GPIORegister; + type Register = GPIORegister; fn configure(&self, configuration: &Self::Config) -> Self::Register { - let mut gpio = GPIORegister:: { + let mut gpio = GPIORegister { + port: get_port!(GPIO_TypeDef, B), pin: configuration.pin, }; gpio.via_config(&configuration); From ad21004f6512963ce22fe77036b7e1372b3bc9ed Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 00:10:01 -0800 Subject: [PATCH 11/17] Updated rcc driver --- minimal_drivers/l3/src/stm32l475xx/rcc.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/minimal_drivers/l3/src/stm32l475xx/rcc.rs b/minimal_drivers/l3/src/stm32l475xx/rcc.rs index b021e26..dc68dc9 100644 --- a/minimal_drivers/l3/src/stm32l475xx/rcc.rs +++ b/minimal_drivers/l3/src/stm32l475xx/rcc.rs @@ -4,11 +4,11 @@ use core::ptr::{read_volatile, write_volatile}; use l0::{ controller::{RCC_TypeDef, RCC_BASE}, - read_register, write_register, + get_port, read_register, write_register, }; use l2::bitflags; -use crate::{Port, Singleton}; +use crate::Singleton; bitflags! { pub struct RCC_AHB2ENR : u32 { @@ -56,13 +56,11 @@ pub struct RCCPeripheral; impl RCCPeripheral { pub fn get_register(&self) -> RCCRegister { RCCRegister { - port: Self::get_port(), + port: get_port!(RCC_TypeDef, B), } } } -impl Port for RCCPeripheral {} - // Create established ports here type RCC = RCCPeripheral; From 7b04278a43ad094d6a4c01656c07f9d0d0b9affb Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 00:51:25 -0800 Subject: [PATCH 12/17] Updated usart driver --- minimal_drivers/l3/src/stm32l475xx/usart.rs | 79 +++++++++++++-------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/minimal_drivers/l3/src/stm32l475xx/usart.rs b/minimal_drivers/l3/src/stm32l475xx/usart.rs index 1f30ee8..152f726 100644 --- a/minimal_drivers/l3/src/stm32l475xx/usart.rs +++ b/minimal_drivers/l3/src/stm32l475xx/usart.rs @@ -1,16 +1,14 @@ -// TODO, Remove this later -#![allow(dead_code)] #![allow(non_camel_case_types)] use core::ptr::{read_volatile, write_volatile}; use l0::{ controller::{USART_TypeDef, USART1_BASE}, - get_system_clock, + get_port, get_system_clock, read_register, write_register, }; use l2::bitflags; -use crate::{PeripheralConfiguration, Port, Singleton, UsartIn, UsartInOut, UsartOut}; +use crate::{PeripheralConfiguration, Singleton, UsartIn, UsartInOut, UsartOut}; bitflags! { pub struct USART_CR1 : u32 { @@ -49,9 +47,11 @@ pub enum USARTMode { RxTx, } -pub struct USARTRegister {} +pub struct USARTRegister { + port: &'static mut USART_TypeDef, +} -impl USARTRegister { +impl USARTRegister { fn via_configure(&mut self, config: &USARTConfig) { // Disable USART self.reset_cr1(USART_CR1::UE); @@ -59,15 +59,21 @@ impl USARTRegister { // Baud rate let system_clock = get_system_clock(); let usartdiv = system_clock / config.baud_rate; - unsafe { write_volatile(&mut Self::get_port().BRR, usartdiv) }; + write_register!(self.port.BRR, usartdiv); // Stop bits - let mut cr2_data = unsafe { read_volatile(&Self::get_port().CR2) }; + let mut cr2_data = read_register!(self.port.CR2); cr2_data &= (!USART_CR2::STOP).bits(); - unsafe { write_volatile(&mut Self::get_port().CR2, cr2_data) }; + cr2_data |= match config.stop_bit { + USARTStopBit::Bit1_0 => 0 << 12, + USARTStopBit::Bit0_5 => 1 << 12, + USARTStopBit::Bit2_0 => 2 << 12, + USARTStopBit::Bit1_5 => 3 << 12, + }; + write_register!(self.port.CR2, cr2_data); // Set word length, usart mode and enable - let mut cr1_data = unsafe { read_volatile(&Self::get_port().CR1) }; + let mut cr1_data = read_register!(self.port.CR1); cr1_data &= (!USART_CR1::all()).bits(); // Set word length @@ -88,50 +94,59 @@ impl USARTRegister { // Enable cr1_data |= USART_CR1::UE.bits(); - unsafe { write_volatile(&mut Self::get_port().CR1, cr1_data) }; + write_register!(self.port.CR1, cr1_data); } fn reset_cr1(&mut self, cr1: USART_CR1) { - let mut cr1_data = unsafe { read_volatile(&Self::get_port().CR1) }; + let mut cr1_data = read_register!(self.port.CR1); cr1_data &= !(cr1.bits()); - unsafe { write_volatile(&mut Self::get_port().CR1, cr1_data) }; + write_register!(self.port.CR1, cr1_data); } } -impl Port for USARTRegister {} - -impl UsartIn for USARTRegister { +impl UsartIn for USARTRegister { fn read_character(&mut self) -> char { todo!() } } -impl UsartOut for USARTRegister { +impl UsartOut for USARTRegister { fn write_character(&mut self, data: char) { let is_bit_set = |bit: u32| { - let isr_data = unsafe { read_volatile(&Self::get_port().ISR) }; + let isr_data = read_register!(self.port.ISR); isr_data & (1 << bit) == 0 }; - while is_bit_set(7) {} - unsafe { write_volatile(&mut Self::get_port().TDR, data as u16) }; - while is_bit_set(6) {} + const ISR_TXE: u32 = 7; + const ISR_TC: u32 = 6; + while is_bit_set(ISR_TXE) {} + write_register!(self.port.TDR, data as u16); + while is_bit_set(ISR_TC) {} } } -impl UsartInOut for USARTRegister {} +impl UsartInOut for USARTRegister {} +// Put functionality here i.e various valid configurations for your peripheral pub struct USARTPeripheral {} impl USARTPeripheral { - pub fn configure_as_rx(&self) -> impl UsartIn { - let usart = USARTRegister:: {}; - usart + pub fn configure_default_rx(&self) -> impl UsartIn { + self.configure(&USARTConfig { + mode: USARTMode::RxOnly, + word_length: USARTWordLength::Len8, + stop_bit: USARTStopBit::Bit1_0, + baud_rate: 115200, + }) } - pub fn configure_as_tx(&self) -> impl UsartOut { - let usart = USARTRegister:: {}; - usart + pub fn configure_default_tx(&self) -> impl UsartOut { + self.configure(&USARTConfig { + mode: USARTMode::TxOnly, + word_length: USARTWordLength::Len8, + stop_bit: USARTStopBit::Bit1_0, + baud_rate: 115200, + }) } pub fn configure_default_rx_tx(&self) -> impl UsartInOut { @@ -153,15 +168,19 @@ pub struct USARTConfig { impl PeripheralConfiguration for USARTPeripheral { type Config = USARTConfig; - type Register = USARTRegister; + type Register = USARTRegister; fn configure(&self, configuration: &Self::Config) -> Self::Register { - let mut usart = USARTRegister:: {}; + let mut usart = USARTRegister { + port: get_port!(USART_TypeDef, B), + }; usart.via_configure(&configuration); usart } } +// Create established ports here + type USART1 = USARTPeripheral; pub static USART1_PORT: Singleton = Singleton::new(USART1 {}); From f02732b64bcd726eca5fae7c40d94028cab82aa6 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 00:51:56 -0800 Subject: [PATCH 13/17] Removed port implementation, use get_port! macro instead Updated to write_register port --- minimal_drivers/l0/src/utility/mod.rs | 2 +- minimal_drivers/l3/src/interfaces/generic_interface.rs | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/minimal_drivers/l0/src/utility/mod.rs b/minimal_drivers/l0/src/utility/mod.rs index d8d7253..88e2c38 100644 --- a/minimal_drivers/l0/src/utility/mod.rs +++ b/minimal_drivers/l0/src/utility/mod.rs @@ -15,7 +15,7 @@ macro_rules! read_register { // TODO, Overload this macro to support $data:literal #[macro_export] macro_rules! write_register { - ($register:expr, $data:ident) => { + ($register:expr, $data:expr) => { unsafe { write_volatile(&mut $register, $data) } }; } diff --git a/minimal_drivers/l3/src/interfaces/generic_interface.rs b/minimal_drivers/l3/src/interfaces/generic_interface.rs index c30b12a..961e572 100644 --- a/minimal_drivers/l3/src/interfaces/generic_interface.rs +++ b/minimal_drivers/l3/src/interfaces/generic_interface.rs @@ -1,11 +1,3 @@ -use l0::get_port; - -pub trait Port { - fn get_port() -> &'static mut T { - get_port!(T, B) - } -} - pub trait PeripheralConfiguration { type Config; type Register; From 7c8d680ba2b9341695fffb359b9cfca70531d279 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 03:55:08 -0800 Subject: [PATCH 14/17] Added USART RX support --- minimal_drivers/l3/src/interfaces/usart_interface.rs | 6 ------ minimal_drivers/l3/src/stm32l475xx/usart.rs | 11 +++++++---- minimal_drivers/l5/src/main.rs | 7 +++++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/minimal_drivers/l3/src/interfaces/usart_interface.rs b/minimal_drivers/l3/src/interfaces/usart_interface.rs index e12b249..03e6596 100644 --- a/minimal_drivers/l3/src/interfaces/usart_interface.rs +++ b/minimal_drivers/l3/src/interfaces/usart_interface.rs @@ -11,12 +11,6 @@ pub trait UsartOut { pub trait UsartIn { fn read_character(&mut self) -> char; - fn read_chars(&mut self, data: &mut [char]) { - let c = self.read_character(); - data.iter_mut().for_each(|d| { - *d = c; - }); - } } pub trait UsartInOut: UsartIn + UsartOut {} diff --git a/minimal_drivers/l3/src/stm32l475xx/usart.rs b/minimal_drivers/l3/src/stm32l475xx/usart.rs index 152f726..a46e23e 100644 --- a/minimal_drivers/l3/src/stm32l475xx/usart.rs +++ b/minimal_drivers/l3/src/stm32l475xx/usart.rs @@ -106,22 +106,25 @@ impl USARTRegister { impl UsartIn for USARTRegister { fn read_character(&mut self) -> char { - todo!() + const ISR_RXNE: u32 = 5; + while (read_register!(self.port.ISR) & 1 << ISR_RXNE) == 0 {} + let data = read_register!(self.port.RDR) as u8; + data as char } } impl UsartOut for USARTRegister { fn write_character(&mut self, data: char) { - let is_bit_set = |bit: u32| { + let bit_unset = |bit: u32| { let isr_data = read_register!(self.port.ISR); isr_data & (1 << bit) == 0 }; const ISR_TXE: u32 = 7; const ISR_TC: u32 = 6; - while is_bit_set(ISR_TXE) {} + while bit_unset(ISR_TXE) {} write_register!(self.port.TDR, data as u16); - while is_bit_set(ISR_TC) {} + while bit_unset(ISR_TC) {} } } diff --git a/minimal_drivers/l5/src/main.rs b/minimal_drivers/l5/src/main.rs index 10cf08e..56d1910 100644 --- a/minimal_drivers/l5/src/main.rs +++ b/minimal_drivers/l5/src/main.rs @@ -63,6 +63,13 @@ fn main() -> ! { usart1_rx_tx .write_fmt(format_args!("LED ON: {}\r\n", counter)) .unwrap(); + usart1_rx_tx + .write_str("Waiting for a character\r\n> ") + .unwrap(); + let char = usart1_rx_tx.read_character(); + usart1_rx_tx + .write_fmt(format_args!("Character: {:#?}\r\n", char)) + .unwrap(); spin_delay(time); led.off(); usart1_rx_tx From 40e1921d070837227f75ab5a4df96971a228b1ee Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 04:03:48 -0800 Subject: [PATCH 15/17] Cleaned up usart interface and implementation --- .../l3/src/interfaces/usart_interface.rs | 25 ++----------------- minimal_drivers/l3/src/stm32l475xx/usart.rs | 24 +++++++++++------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/minimal_drivers/l3/src/interfaces/usart_interface.rs b/minimal_drivers/l3/src/interfaces/usart_interface.rs index 03e6596..90f0ff3 100644 --- a/minimal_drivers/l3/src/interfaces/usart_interface.rs +++ b/minimal_drivers/l3/src/interfaces/usart_interface.rs @@ -1,30 +1,9 @@ use core::fmt::Write; -pub trait UsartOut { - fn write_character(&mut self, data: char); - fn write_string(&mut self, data: &str) { - data.chars().for_each(|d| { - self.write_character(d); - }); - } -} +// * Instead of having an `UsartOut` trait, we can use the Rust core library `core::fmt::Write` trait pub trait UsartIn { fn read_character(&mut self) -> char; } -pub trait UsartInOut: UsartIn + UsartOut {} - -impl Write for dyn UsartOut { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - self.write_string(&s); - Ok(()) - } -} - -impl Write for dyn UsartInOut { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - self.write_string(&s); - Ok(()) - } -} +pub trait UsartInOut: UsartIn + Write {} diff --git a/minimal_drivers/l3/src/stm32l475xx/usart.rs b/minimal_drivers/l3/src/stm32l475xx/usart.rs index a46e23e..0263050 100644 --- a/minimal_drivers/l3/src/stm32l475xx/usart.rs +++ b/minimal_drivers/l3/src/stm32l475xx/usart.rs @@ -1,6 +1,9 @@ #![allow(non_camel_case_types)] -use core::ptr::{read_volatile, write_volatile}; +use core::{ + fmt::Write, + ptr::{read_volatile, write_volatile}, +}; use l0::{ controller::{USART_TypeDef, USART1_BASE}, @@ -8,7 +11,7 @@ use l0::{ }; use l2::bitflags; -use crate::{PeripheralConfiguration, Singleton, UsartIn, UsartInOut, UsartOut}; +use crate::{PeripheralConfiguration, Singleton, UsartIn, UsartInOut}; bitflags! { pub struct USART_CR1 : u32 { @@ -113,18 +116,21 @@ impl UsartIn for USARTRegister { } } -impl UsartOut for USARTRegister { - fn write_character(&mut self, data: char) { - let bit_unset = |bit: u32| { +impl Write for USARTRegister { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let bit_not_set = |bit: u32| { let isr_data = read_register!(self.port.ISR); isr_data & (1 << bit) == 0 }; const ISR_TXE: u32 = 7; const ISR_TC: u32 = 6; - while bit_unset(ISR_TXE) {} - write_register!(self.port.TDR, data as u16); - while bit_unset(ISR_TC) {} + s.chars().for_each(|c| { + while bit_not_set(ISR_TXE) {} + write_register!(self.port.TDR, c as u16); + }); + while bit_not_set(ISR_TC) {} + Ok(()) } } @@ -143,7 +149,7 @@ impl USARTPeripheral { }) } - pub fn configure_default_tx(&self) -> impl UsartOut { + pub fn configure_default_tx(&self) -> impl Write { self.configure(&USARTConfig { mode: USARTMode::TxOnly, word_length: USARTWordLength::Len8, From eaac5328d14f31faf4157a6258b16c1e4908f8f7 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 04:09:04 -0800 Subject: [PATCH 16/17] Updated README --- minimal_drivers/README.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/minimal_drivers/README.md b/minimal_drivers/README.md index 488c1cd..8196388 100644 --- a/minimal_drivers/README.md +++ b/minimal_drivers/README.md @@ -3,7 +3,6 @@ - [Microcontrollers layers](#microcontrollers-layers) - [Pre-requisites](#pre-requisites) - [GPIO](#gpio) -- [Terminology](#terminology) - [Changelog](#changelog) - [L0 Layer - Controller](#l0-layer---controller) - [Global](#global) @@ -13,6 +12,7 @@ - [Own implementation](#own-implementation) - [Crates.io](#cratesio) - [L3 Layer - Interfaces](#l3-layer---interfaces) + - [Rust interfaces used](#rust-interfaces-used) - [L3 Layer - Drivers](#l3-layer---drivers) - [L3 Layer - Miscellaneous](#l3-layer---miscellaneous) - [L4 Sensor / Actuator](#l4-sensor--actuator) @@ -78,14 +78,6 @@ graph BT; end end ``` -# Terminology - -- Chip -- Controller -- Port -- Peripheral -- Register - # Changelog ## L0 Layer - Controller @@ -120,11 +112,12 @@ graph BT; - GpioIn - GpioOut - UsartIn -- UsartOut - UsartInOut -- Port - - Generic interface that creates a port using base address and peripheral register layout - - In C it would be the equivalent of `GPIO_TypeDef * gpio = (GPIO_TypeDef *)BASE_ADDRESS` + +### Rust interfaces used + +- Write + - Used instead of creating out own UsartOut interface ## L3 Layer - Drivers @@ -133,7 +126,7 @@ graph BT; - [x] Input - [x] Output - USART - - [ ] Read + - [x] Read - [x] Write ## L3 Layer - Miscellaneous From 3fe3d36894737ae6171d8adfbef5f9f77b8f438d Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Sun, 19 Feb 2023 04:18:56 -0800 Subject: [PATCH 17/17] Update README.md --- minimal_drivers/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/minimal_drivers/README.md b/minimal_drivers/README.md index 8196388..fda361d 100644 --- a/minimal_drivers/README.md +++ b/minimal_drivers/README.md @@ -45,6 +45,26 @@ This code has been tested on - L4 Sensor - L5 Application +``` +application v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l5) +├── l0 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l0) +│ [build-dependencies] +│ └── bindgen v0.63.0 +├── l3 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l3) +│ ├── l0 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l0) (*) +│ └── l2 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l2) +└── l4 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l4) + └── l3 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l3) (*) + +l0 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l0) (*) + +l2 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l2) (*) + +l3 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l3) (*) + +l4 v0.1.0 (D:\Repositories\lowlevel_rust\minimal_drivers\l4) (*) +``` + ## Pre-requisites - Pre-requisites from `minimal_controller_peripheral`