Skip to content

Minimal USART Driver #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions minimal_drivers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
- [Pre-requisites](#pre-requisites)
- [GPIO](#gpio)
- [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)
- [Rust interfaces used](#rust-interfaces-used)
- [L3 Layer - Drivers](#l3-layer---drivers)
- [L3 Layer - Miscellaneous](#l3-layer---miscellaneous)
- [L4](#l4)
- [L4 Sensor / Actuator](#l4-sensor--actuator)

# Minimal Drivers

Expand Down Expand Up @@ -40,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`
Expand All @@ -60,7 +85,7 @@ This code has been tested on
graph BT;
subgraph Port
GPIOA-H
subgraph Periphal
subgraph Peripheral
GPIO
subgraph Register
MODER
Expand All @@ -73,9 +98,27 @@ graph BT;
end
end
```

# 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
Expand All @@ -89,23 +132,29 @@ 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

- RCC
- GPIO
- [x] Input
- [x] Output
- USART
- [x] Read
- [x] Write

## L3 Layer - Miscellaneous

- Singleton
- Safe access to global ports

## L4
## L4 Sensor / Actuator

- Led
- Button
5 changes: 5 additions & 0 deletions minimal_drivers/l0/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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 {
Expand Down
15 changes: 12 additions & 3 deletions minimal_drivers/l0/src/entry_point.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::chip::controller_init;

#[link_section = ".vector_table.reset_vector"]
#[no_mangle]
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;
Expand All @@ -16,24 +19,30 @@ 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;
let count: usize = vma_data_end as usize - vma_data_start as usize;
// 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();
}

Expand Down Expand Up @@ -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 },
Expand Down
8 changes: 8 additions & 0 deletions minimal_drivers/l0/src/global.rs
Original file line number Diff line number Diff line change
@@ -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)
}
20 changes: 17 additions & 3 deletions minimal_drivers/l0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions minimal_drivers/l0/src/stm32l475xx/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod private;
pub use private::*;
30 changes: 30 additions & 0 deletions minimal_drivers/l0/src/stm32l475xx/private.rs
Original file line number Diff line number Diff line change
@@ -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
}
21 changes: 21 additions & 0 deletions minimal_drivers/l0/src/utility/mod.rs
Original file line number Diff line number Diff line change
@@ -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 {
($register:expr) => {
unsafe { read_volatile(&$register) }
};
}

// TODO, Overload this macro to support $data:literal
#[macro_export]
macro_rules! write_register {
($register:expr, $data:expr) => {
unsafe { write_volatile(&mut $register, $data) }
};
}
1 change: 0 additions & 1 deletion minimal_drivers/l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
7 changes: 0 additions & 7 deletions minimal_drivers/l3/src/interfaces/generic_interface.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
pub trait Port<T, const B: u32> {
fn get_port(&self) -> &'static mut T {
let mutable_ref = unsafe { &mut *(B as *mut T) };
mutable_ref
}
}

pub trait PeripheralConfiguration {
type Config;
type Register;
Expand Down
3 changes: 3 additions & 0 deletions minimal_drivers/l3/src/interfaces/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
9 changes: 9 additions & 0 deletions minimal_drivers/l3/src/interfaces/usart_interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use core::fmt::Write;

// * 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 + Write {}
4 changes: 2 additions & 2 deletions minimal_drivers/l3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
Loading