This commit is contained in:
2025-06-04 17:20:04 +02:00
parent a289dcfd17
commit c78d834742
8 changed files with 190 additions and 61 deletions

164
src/peripherals/gpio.rs Normal file
View File

@@ -0,0 +1,164 @@
use core::ptr::{read_volatile, write_volatile};
use core::result::Result;
use core::result::Result::Err;
use core::result::Result::Ok;
use crate::timer::delay_nops;
const GPFSEL_BASE: u32 = 0x3F20_0000;
const GPSET_BASE: u32 = 0x3F20_001C;
const GPCLR_BASE: u32 = 0x3F20_0028;
const GPLEV_BASE: u32 = 0x3F20_0034;
const GPPUD: u32 = 0x3F20_0094;
const GPPUDCLK_BASE: u32 = 0x3F20_0098;
const GPREN_BASE: u32 = 0x3F20_004C;
const GPFEN_BASE: u32 = 0x3F20_0058;
#[repr(u32)]
pub enum GPIOState {
Input = 0b000,
Output = 0b001,
Alternative0 = 0b100,
Alternative1 = 0b101,
Alternative2 = 0b110,
Alternative3 = 0b111,
Alternative4 = 0b011,
Alternative5 = 0b010,
}
pub fn set_gpio_state(gpio: u8, state: GPIOState) -> Result<(), &'static str> {
if gpio > 53 {
return Err("GPIO out of range");
}
let register_index = gpio / 10;
let register_offset = (gpio % 10) * 3;
let register_addr = GPFSEL_BASE + (register_index as u32 * 4);
unsafe {
let current = core::ptr::read_volatile(register_addr as *const u32);
let mask = !(0b111 << register_offset);
let cleared = current & mask;
let new_val = cleared | ((state as u32) << register_offset);
core::ptr::write_volatile(register_addr as *mut u32, new_val);
}
Ok(())
}
pub fn gpio_high(gpio: u8) -> Result<(), &'static str> {
unsafe {
let register_index = gpio / 32;
let register_offset = gpio % 32;
let register_addr = GPSET_BASE + (register_index as u32 * 4);
core::ptr::write_volatile(register_addr as *mut u32, 1 << register_offset);
}
Ok(())
}
pub fn gpio_low(gpio: u8) -> Result<(), &'static str> {
unsafe {
let register_index = gpio / 32;
let register_offset = gpio % 32;
let register_addr = GPCLR_BASE + (register_index as u32 * 4);
core::ptr::write_volatile(register_addr as *mut u32, 1 << register_offset);
}
Ok(())
}
pub fn gpio_get_state(gpio: u8) -> u8 {
unsafe {
let register_index = gpio / 32;
let register_offset = gpio % 32;
let register_addr = GPLEV_BASE + (register_index as u32 * 4);
let state = core::ptr::read_volatile(register_addr as *mut u32);
return ((state >> register_offset) & 0b1) as u8;
}
}
pub fn gpio_pull_up(gpio: u8) {
gpio_pull_up_down(gpio, 0b10);
}
pub fn gpio_pull_down(gpio: u8) {
gpio_pull_up_down(gpio, 0b01);
}
fn gpio_pull_up_down(gpio: u8, val: u32) {
unsafe {
// Determine GPPUDCLK Register
let register_addr = GPPUDCLK_BASE + 4 * (gpio as u32 / 32);
let register_offset = gpio % 32;
// 1. Write Pull up
write_volatile(GPPUD as *mut u32, val);
// 2. Delay 150 cycles
delay_nops(150);
// 3. Write to clock
let new_val = 0b1 << register_offset;
write_volatile(register_addr as *mut u32, new_val);
// 4. Delay 150 cycles
delay_nops(150);
// 5. reset GPPUD
write_volatile(GPPUD as *mut u32, 0);
// 6. reset clock
write_volatile(register_addr as *mut u32, 0);
}
}
pub fn read_falling_edge_detect(gpio: u8) -> u32 {
unsafe {
// Determine GPLEN Register
let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32);
let register_offset = gpio % 32;
let current = read_volatile(register_addr as *const u32);
return (current >> register_offset) & 0b1;
}
}
pub fn set_falling_edge_detect(gpio: u8, enable: bool) {
unsafe {
// Determine GPLEN Register
let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32);
let register_offset = gpio % 32;
let current = read_volatile(register_addr as *const u32);
let mask = 0b1 << register_offset;
let new_val = if enable {
current | mask
} else {
current & !mask
};
write_volatile(register_addr as *mut u32, new_val);
}
}
pub fn set_rising_edge_detect(gpio: u8, enable: bool) {
unsafe {
// Determine GPHEN Register
let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32);
let register_offset = gpio % 32;
let current = read_volatile(register_addr as *const u32);
let mask = 0b1 << register_offset;
let new_val = if enable {
current | mask
} else {
current & !mask
};
write_volatile(register_addr as *mut u32, new_val);
}
}

2
src/peripherals/mod.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod gpio;
pub mod uart;

94
src/peripherals/uart.rs Normal file
View File

@@ -0,0 +1,94 @@
const BAUD: u32 = 115200;
const UART_CLK: u32 = 48_000_000;
const UART0_DR: u32 = 0x3F20_1000;
const UART0_FR: u32 = 0x3F20_1018;
const UART0_FR_TXFF: u32 = 1 << 5;
const UART0_IBRD: u32 = 0x3F20_1024;
const UART0_FBRD: u32 = 0x3F20_1028;
const UART0_CR: u32 = 0x3F20_1030;
const UART0_CR_UARTEN: u32 = 1 << 0;
const UART0_CR_TXE: u32 = 1 << 8;
const UART0_LCRH: u32 = 0x3F20_102c;
const UART0_LCRH_FEN: u32 = 1 << 4;
/// Print `s` over UART
pub fn print(s: &str) {
for byte in s.bytes() {
unsafe {
while core::ptr::read_volatile(UART0_FR as *const u32) & UART0_FR_TXFF != 0 {}
core::ptr::write_volatile(UART0_DR as *mut u32, byte as u32);
}
}
// wait till uart is not busy anymore
unsafe { while (core::ptr::read_volatile(UART0_FR as *const u32) >> 3) & 0b1 != 0 {} }
}
/// Initialize UART peripheral
pub fn uart_init() {
let baud_div_times_64 = (UART_CLK * 4) / BAUD;
let ibrd = baud_div_times_64 / 64;
let fbrd = baud_div_times_64 % 64;
unsafe {
uart_enable(false);
uart_fifo_enable(false);
core::ptr::write_volatile(UART0_IBRD as *mut u32, ibrd);
core::ptr::write_volatile(UART0_FBRD as *mut u32, fbrd);
uart_set_lcrh(0b11, true);
// Enable transmit and uart
let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32);
cr |= UART0_CR_UARTEN | UART0_CR_TXE;
core::ptr::write_volatile(UART0_CR as *mut u32, cr);
}
}
/// Enable UARTEN
fn uart_enable(enable: bool) {
unsafe {
let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32);
if enable {
cr |= UART0_CR_UARTEN;
} else {
cr &= !UART0_CR_UARTEN;
}
core::ptr::write_volatile(UART0_CR as *mut u32, cr);
}
}
/// Enable UART FIFO
fn uart_fifo_enable(enable: bool) {
unsafe {
let mut lcrh = core::ptr::read_volatile(UART0_LCRH as *mut u32);
if enable {
lcrh |= UART0_LCRH_FEN;
} else {
lcrh &= !UART0_LCRH_FEN;
}
core::ptr::write_volatile(UART0_LCRH as *mut u32, lcrh);
}
}
/// Set UART word length and set FIFO status
fn uart_set_lcrh(wlen: u32, enable_fifo: bool) {
unsafe {
let mut value = (wlen & 0b11) << 5;
if enable_fifo {
value |= UART0_LCRH_FEN;
}
core::ptr::write_volatile(UART0_LCRH as *mut u32, value);
}
}