diff --git a/README.md b/README.md index d5f8e05..372bebc 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,13 @@ NovaOS is a expository project where I build a kernel from scratch for a Raspberry PI 3 B+. [Technical write-up](https://blog.leafnova.net/projects/pi3_kernel/) + +## Features + +- Delay and sleep ✓ +- UART ✓ +- GPIOs ✓ +- GPIO Interrupts ✓ +- Frame Buffer +- MMU +- Basic Terminal over UART diff --git a/src/main.rs b/src/main.rs index 207b20e..479f264 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use nova::{ peripherals::{ gpio::{ gpio_get_state, gpio_high, gpio_low, gpio_pull_up, set_falling_edge_detect, - set_gpio_state, GPIOState, + set_gpio_function, GPIOFunction, }, uart::{print, uart_init}, }, @@ -49,7 +49,7 @@ pub extern "C" fn main() -> ! { enable_uart(); // Set ACT Led to Outout - let _ = set_gpio_state(21, GPIOState::Output); + let _ = set_gpio_function(21, GPIOFunction::Output); print_current_el_str(); @@ -72,7 +72,7 @@ pub extern "C" fn kernel_main() -> ! { // Set GPIO 26 to Input enable_irq_source(nova::irq_interrupt::IRQState::GpioInt0); //26 is on the first GPIO bank - let _ = set_gpio_state(26, GPIOState::Input); + let _ = set_gpio_function(26, GPIOFunction::Input); gpio_pull_up(26); set_falling_edge_detect(26, true); @@ -112,8 +112,8 @@ pub fn get_current_el() -> u64 { fn enable_uart() { uart_init(); // Set GPIO Pins to UART - let _ = set_gpio_state(14, GPIOState::Alternative0); - let _ = set_gpio_state(15, GPIOState::Alternative0); + let _ = set_gpio_function(14, GPIOFunction::Alternative0); + let _ = set_gpio_function(15, GPIOFunction::Alternative0); } fn print_current_el_str() { diff --git a/src/peripherals/gpio.rs b/src/peripherals/gpio.rs index f149837..3f830bd 100644 --- a/src/peripherals/gpio.rs +++ b/src/peripherals/gpio.rs @@ -1,6 +1,5 @@ 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; @@ -15,7 +14,7 @@ const GPREN_BASE: u32 = 0x3F20_004C; const GPFEN_BASE: u32 = 0x3F20_0058; #[repr(u32)] -pub enum GPIOState { +pub enum GPIOFunction { Input = 0b000, Output = 0b001, Alternative0 = 0b100, @@ -26,11 +25,8 @@ pub enum GPIOState { Alternative5 = 0b010, } -pub fn set_gpio_state(gpio: u8, state: GPIOState) -> Result<(), &'static str> { - if gpio > 53 { - return Err("GPIO out of range"); - } - +/// Set the function of the GPIO pin +pub fn set_gpio_function(gpio: u8, state: GPIOFunction) -> Result<(), &'static str> { let register_index = gpio / 10; let register_offset = (gpio % 10) * 3; let register_addr = GPFSEL_BASE + (register_index as u32 * 4); @@ -47,6 +43,9 @@ pub fn set_gpio_state(gpio: u8, state: GPIOState) -> Result<(), &'static str> { Ok(()) } +/// Set the GPIO to high +/// +/// 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; @@ -58,6 +57,9 @@ pub fn gpio_high(gpio: u8) -> Result<(), &'static str> { Ok(()) } +/// Set the GPIO to low +/// +/// 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; @@ -69,6 +71,7 @@ pub fn gpio_low(gpio: u8) -> Result<(), &'static str> { Ok(()) } +/// Read the current GPIO power state pub fn gpio_get_state(gpio: u8) -> u8 { unsafe { let register_index = gpio / 32; @@ -80,10 +83,16 @@ pub fn gpio_get_state(gpio: u8) -> u8 { } } +/// Pull GPIO up +/// +/// Should be used when GPIO function is set to `INPUT` via `set_gpio_function` pub fn gpio_pull_up(gpio: u8) { gpio_pull_up_down(gpio, 0b10); } +/// Pull GPIO down +/// +/// Should be used when GPIO function is set to `INPUT` via `set_gpio_function` pub fn gpio_pull_down(gpio: u8) { gpio_pull_up_down(gpio, 0b01); } @@ -115,20 +124,31 @@ fn gpio_pull_up_down(gpio: u8, val: u32) { } } -pub fn read_falling_edge_detect(gpio: u8) -> u32 { +/// Get the current status if falling edge detection is set +pub fn read_falling_edge_detect(gpio: u8) -> 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); - return (current >> register_offset) & 0b1; + ((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 current = read_volatile(register_addr as *const u32); + ((current >> register_offset) & 0b1) != 0 + } +} + +/// Enables falling edge detection 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; @@ -144,9 +164,9 @@ pub fn set_falling_edge_detect(gpio: u8, enable: bool) { } } +/// Enables rising edge detection 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;