diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..4f483d0 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,68 @@ +use crate::{ + delay, + uart::{self}, +}; + +const GPFSEL4: u32 = 0x3F20_0010; //GPIO 40-49 +const GPPUD: u32 = 0x3F20_0094; +const GPPUD_CLK: u32 = 0x3F20_0098; // GPIO 32-53 + +unsafe fn set_gpio47_to_output() { + let value: u32 = 0b001 << 21; + + core::ptr::write_volatile(GPFSEL4 as *mut u32, value); +} + +unsafe fn enable_pull_up() { + let value: u32 = 0b10; + + core::ptr::write_volatile(GPPUD as *mut u32, value); +} + +unsafe fn enable_pull_down() { + let value: u32 = 0b01; + + core::ptr::write_volatile(GPPUD as *mut u32, value); +} + +unsafe fn disable_GPPUD() { + core::ptr::write_volatile(GPPUD as *mut u32, 0); +} + +unsafe fn enable_clock_gpio47() { + let value: u32 = 0b1 << 13; + + core::ptr::write_volatile(GPPUD as *mut u32, value); +} + +unsafe fn disable_GPPUD_CLK() { + core::ptr::write_volatile(GPPUD as *mut u32, 0); +} + +pub fn pull_up_gpio47() { + unsafe { + uart::print("Pull Up\n"); + set_gpio47_to_output(); + enable_pull_up(); + // Wait 150 cycles + delay(150); + enable_clock_gpio47(); + delay(150); + disable_GPPUD(); + disable_GPPUD_CLK(); + } +} + +pub fn pull_down_gpio47() { + unsafe { + uart::print("Pull Down\n"); + set_gpio47_to_output(); + enable_pull_down(); + // Wait 150 cycles + delay(150); + enable_clock_gpio47(); + delay(150); + disable_GPPUD(); + disable_GPPUD_CLK(); + } +} diff --git a/src/main.rs b/src/main.rs index 6aee0e2..705027f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,47 +2,17 @@ #![no_std] #![feature(asm_experimental_arch)] -use core::{ - arch::asm, - fmt::{self, Write}, - panic::PanicInfo, -}; +use core::panic::PanicInfo; + +use gpio::{pull_down_gpio47, pull_up_gpio47}; + +mod gpio; +mod uart; #[panic_handler] fn panic(_panic: &PanicInfo) -> ! { - loop {} -} - -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; -const UART0_LCRH_WLEN: u32 = 11 << 5; - -struct Uart; - -impl Write for Uart { - fn write_str(&mut self, s: &str) -> fmt::Result { - 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); - } - } - Ok(()) + loop { + uart::print("Panic"); } } @@ -54,77 +24,23 @@ pub extern "C" fn _start() -> ! { #[no_mangle] fn main() { - configure_uart(); - delay(50000); - let mut uart = Uart {}; + uart::configure_uart(); + + // Delay so clock speed can stabilize + unsafe { delay(50000) } + uart::print("Hello World!\n"); + loop { - writeln!(uart, "Hello World!"); + pull_up_gpio47(); + unsafe { delay(10_000_000) } // ~0.5s + pull_down_gpio47(); + unsafe { delay(10_000_000) } } } -pub fn configure_uart() { - 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); - } -} - -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); - } -} - -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); - } -} - -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); - } -} - -fn delay(count: u32) { +unsafe fn delay(count: u32) { for _ in 0..count { // Prevent compiler optimizing away the loop - core::sync::atomic::spin_loop_hint(); + core::arch::asm!("nop"); } } diff --git a/src/uart.rs b/src/uart.rs new file mode 100644 index 0000000..703e0c5 --- /dev/null +++ b/src/uart.rs @@ -0,0 +1,86 @@ +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; + +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); + } + } +} + +pub fn configure_uart() { + 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); + } +} + +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); + } +} + +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); + } +} + +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); + } +}