diff --git a/src/irq_interrupt.rs b/src/irq_interrupt.rs index b8311a6..27b2af8 100644 --- a/src/irq_interrupt.rs +++ b/src/irq_interrupt.rs @@ -1,10 +1,9 @@ use core::{ arch::asm, - ptr::{read_volatile, write_volatile}, sync::atomic::{compiler_fence, Ordering}, }; -use crate::peripherals::uart::print; +use crate::{mmio_read, mmio_write, peripherals::uart::print}; const INTERRUPT_BASE: u32 = 0x3F00_B000; const IRQ_PENDING_BASE: u32 = INTERRUPT_BASE + 0x204; @@ -57,7 +56,7 @@ pub fn read_gpio_event_detect_status(id: u32) -> bool { let register = GPEDS_BASE + (id / 32) * 4; let register_offset = id % 32; - let val = unsafe { read_volatile(register as *const u32) >> register_offset }; + let val = mmio_read(register) >> register_offset; (val & 0b1) != 0 } @@ -66,7 +65,7 @@ pub fn reset_gpio_event_detect_status(id: u32) { let register = GPEDS_BASE + (id / 32) * 4; let register_offset = id % 32; - unsafe { write_volatile(register as *mut u32, 0b1 << register_offset) } + mmio_write(register, 0b1 << register_offset); compiler_fence(Ordering::SeqCst); } @@ -75,12 +74,10 @@ pub fn enable_irq_source(state: IRQState) { let nr = state as u32; let register = ENABLE_IRQ_BASE + 4 * (nr / 32); let register_offset = nr % 32; - unsafe { - let current = read_volatile(register as *const u32); - let mask = 0b1 << register_offset; - let new_val = current | mask; - write_volatile(register as *mut u32, new_val); - } + let current = mmio_read(register); + let mask = 0b1 << register_offset; + let new_val = current | mask; + mmio_write(register, new_val); } /// Disable IRQ Source @@ -88,12 +85,10 @@ pub fn disable_irq_source(state: IRQState) { let nr = state as u32; let register = DISABLE_IRQ_BASE + 4 * (nr / 32); let register_offset = nr % 32; - unsafe { - let current = read_volatile(register as *const u32); - let mask = 0b1 << register_offset; - let new_val = current | mask; - write_volatile(register as *mut u32, new_val); - } + let current = mmio_read(register); + let mask = 0b1 << register_offset; + let new_val = current | mask; + mmio_write(register, new_val); } /// Read current IRQ Source status @@ -101,7 +96,7 @@ pub fn read_irq_source_status(state: IRQState) -> u32 { let nr = state as u32; let register = ENABLE_IRQ_BASE + 4 * (nr / 32); let register_offset = nr % 32; - unsafe { (read_volatile(register as *const u32) >> register_offset) & 0b1 } + (mmio_read(register) >> register_offset) & 0b1 } /// Status if a IRQ Source is enabled @@ -109,7 +104,7 @@ pub fn read_irq_pending(state: IRQState) -> bool { let nr = state as u32; let register = IRQ_PENDING_BASE + 4 * (nr / 32); let register_offset = nr % 32; - (unsafe { (read_volatile(register as *const u32) >> register_offset) & 0b1 }) != 0 + ((mmio_read(register) >> register_offset) & 0b1) != 0 } /// Clears the IRQ DAIF Mask diff --git a/src/lib.rs b/src/lib.rs index 812aeb8..8d909e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,17 @@ #![no_std] +use core::ptr::{read_volatile, write_volatile}; + pub mod peripherals; pub mod irq_interrupt; +pub mod mailbox; pub mod timer; + +pub fn mmio_read(address: u32) -> u32 { + unsafe { read_volatile(address as *const u32) } +} + +pub fn mmio_write(address: u32, data: u32) { + unsafe { write_volatile(address as *mut u32, data) } +} diff --git a/src/peripherals/gpio.rs b/src/peripherals/gpio.rs index 3f830bd..709277f 100644 --- a/src/peripherals/gpio.rs +++ b/src/peripherals/gpio.rs @@ -1,8 +1,8 @@ -use core::ptr::{read_volatile, write_volatile}; use core::result::Result; use core::result::Result::Ok; use crate::timer::delay_nops; +use crate::{mmio_read, mmio_write}; const GPFSEL_BASE: u32 = 0x3F20_0000; const GPSET_BASE: u32 = 0x3F20_001C; @@ -30,16 +30,14 @@ pub fn set_gpio_function(gpio: u8, state: GPIOFunction) -> Result<(), &'static s 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 current = mmio_read(register_addr); - let mask = !(0b111 << register_offset); - let cleared = current & mask; + let mask = !(0b111 << register_offset); + let cleared = current & mask; - let new_val = cleared | ((state as u32) << register_offset); + let new_val = cleared | ((state as u32) << register_offset); - core::ptr::write_volatile(register_addr as *mut u32, new_val); - } + mmio_write(register_addr, new_val); Ok(()) } @@ -47,13 +45,11 @@ pub fn set_gpio_function(gpio: u8, state: GPIOFunction) -> Result<(), &'static s /// /// Should be used when GPIO function is set to `OUTPUT` via `set_gpio_function` 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); + 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); - } + mmio_write(register_addr, 1 << register_offset); Ok(()) } @@ -61,26 +57,22 @@ pub fn gpio_high(gpio: u8) -> Result<(), &'static str> { /// /// Should be used when GPIO function is set to `OUTPUT` via `set_gpio_function` 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); + 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); - } + mmio_write(register_addr, 1 << register_offset); Ok(()) } /// Read the current GPIO power state 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 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; - } + let state = mmio_read(register_addr); + return ((state >> register_offset) & 0b1) as u8; } /// Pull GPIO up @@ -104,81 +96,73 @@ fn gpio_pull_up_down(gpio: u8, val: u32) { let register_offset = gpio % 32; // 1. Write Pull up - write_volatile(GPPUD as *mut u32, val); + mmio_write(GPPUD, 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); + mmio_write(register_addr, new_val); // 4. Delay 150 cycles delay_nops(150); // 5. reset GPPUD - write_volatile(GPPUD as *mut u32, 0); + mmio_write(GPPUD, 0); // 6. reset clock - write_volatile(register_addr as *mut u32, 0); + mmio_write(register_addr, 0); } } /// Get the current status if falling edge detection is set pub fn read_falling_edge_detect(gpio: u8) -> bool { - unsafe { - let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); - let register_offset = gpio % 32; + let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); + let register_offset = gpio % 32; - let current = read_volatile(register_addr as *const u32); - ((current >> register_offset) & 0b1) != 0 - } + let current = mmio_read(register_addr); + ((current >> register_offset) & 0b1) != 0 } /// Get the current status if falling edge detection is set pub fn read_rising_edge_detect(gpio: u8) -> bool { - unsafe { - let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32); - let register_offset = gpio % 32; + let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32); + let register_offset = gpio % 32; - let current = read_volatile(register_addr as *const u32); - ((current >> register_offset) & 0b1) != 0 - } + let current = mmio_read(register_addr); + ((current >> register_offset) & 0b1) != 0 } /// Enables falling edge detection pub fn set_falling_edge_detect(gpio: u8, enable: bool) { - unsafe { - let register_addr = GPFEN_BASE + 4 * (gpio as u32 / 32); - let register_offset = gpio % 32; + 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 - }; + let current = mmio_read(register_addr); + let mask = 0b1 << register_offset; + let new_val = if enable { + current | mask + } else { + current & !mask + }; - write_volatile(register_addr as *mut u32, new_val); - } + mmio_write(register_addr, new_val); } /// Enables rising edge detection pub fn set_rising_edge_detect(gpio: u8, enable: bool) { - unsafe { - let register_addr = GPREN_BASE + 4 * (gpio as u32 / 32); - let register_offset = gpio % 32; + 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 current = mmio_read(register_addr); - let mask = 0b1 << register_offset; - let new_val = if enable { - current | mask - } else { - current & !mask - }; + let mask = 0b1 << register_offset; + let new_val = if enable { + current | mask + } else { + current & !mask + }; - write_volatile(register_addr as *mut u32, new_val); - } + mmio_write(register_addr, new_val); } diff --git a/src/peripherals/uart.rs b/src/peripherals/uart.rs index 2d45e58..1ad0fd2 100644 --- a/src/peripherals/uart.rs +++ b/src/peripherals/uart.rs @@ -1,3 +1,5 @@ +use crate::{mmio_read, mmio_write}; + const BAUD: u32 = 115200; const UART_CLK: u32 = 48_000_000; @@ -19,13 +21,11 @@ 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); - } + while mmio_read(UART0_FR) & UART0_FR_TXFF != 0 {} + mmio_write(UART0_DR, byte as u32); } // wait till uart is not busy anymore - unsafe { while (core::ptr::read_volatile(UART0_FR as *const u32) >> 3) & 0b1 != 0 {} } + while (mmio_read(UART0_FR) >> 3) & 0b1 != 0 {} } /// Initialize UART peripheral @@ -35,60 +35,52 @@ pub fn uart_init() { let ibrd = baud_div_times_64 / 64; let fbrd = baud_div_times_64 % 64; - unsafe { - uart_enable(false); - uart_fifo_enable(false); + 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); + mmio_write(UART0_IBRD, ibrd); + mmio_write(UART0_FBRD, fbrd); - uart_set_lcrh(0b11, true); + 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; + // Enable transmit and uart + let mut cr = mmio_read(UART0_CR); + cr |= UART0_CR_UARTEN | UART0_CR_TXE; - core::ptr::write_volatile(UART0_CR as *mut u32, cr); - } + mmio_write(UART0_CR, cr); } /// Enable UARTEN fn uart_enable(enable: bool) { - unsafe { - let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32); + let mut cr = mmio_read(UART0_CR); - if enable { - cr |= UART0_CR_UARTEN; - } else { - cr &= !UART0_CR_UARTEN; - } - - core::ptr::write_volatile(UART0_CR as *mut u32, cr); + if enable { + cr |= UART0_CR_UARTEN; + } else { + cr &= !UART0_CR_UARTEN; } + + mmio_write(UART0_CR, cr); } /// Enable UART FIFO fn uart_fifo_enable(enable: bool) { - unsafe { - let mut lcrh = core::ptr::read_volatile(UART0_LCRH as *mut u32); + let mut lcrh = mmio_read(UART0_LCRH); - if enable { - lcrh |= UART0_LCRH_FEN; - } else { - lcrh &= !UART0_LCRH_FEN; - } - - core::ptr::write_volatile(UART0_LCRH as *mut u32, lcrh); + if enable { + lcrh |= UART0_LCRH_FEN; + } else { + lcrh &= !UART0_LCRH_FEN; } + + mmio_write(UART0_LCRH, 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); + let mut value = (wlen & 0b11) << 5; + if enable_fifo { + value |= UART0_LCRH_FEN; } + mmio_write(UART0_LCRH, value); } diff --git a/src/timer.rs b/src/timer.rs index 7b81dad..73c3b00 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,7 +1,9 @@ +use crate::mmio_read; + const TIMER_CLO: u32 = 0x3F00_3004; fn read_clo() -> u32 { - unsafe { return core::ptr::read_volatile(TIMER_CLO as *const u32) } + return mmio_read(TIMER_CLO); } /// Sleep for `us` microseconds