From d875364debaeb4719eee977f2623662b1cac2aef Mon Sep 17 00:00:00 2001 From: J / Jacob Babich Date: Sun, 17 Apr 2022 20:08:48 -0400 Subject: [PATCH] stuffs --- src/lib/board.rs | 4 +- src/lib/gpio/pins.rs | 216 ++++++++++++++++++------------------------ src/lib/gpio/ports.rs | 4 +- src/main.rs | 154 ++++++++++++++++++++++-------- 4 files changed, 215 insertions(+), 163 deletions(-) diff --git a/src/lib/board.rs b/src/lib/board.rs index aed7c9e..bf66ce0 100644 --- a/src/lib/board.rs +++ b/src/lib/board.rs @@ -2,10 +2,12 @@ use crate::gpio::ports::{setup_gpio_port, Port, PortOptions, UsablePort}; pub struct UsableBoard; impl UsableBoard { - pub fn setup_gpio_port(&self, port: Port, options: PortOptions) -> UsablePort { + pub fn setup_gpio_port(&mut self, port: Port, options: PortOptions) -> UsablePort { setup_gpio_port(port, options) } + // TODO: have a no_op function here if so desired + // TODO: check page 704 for timers // TODO: impl Drop trait so that tasks all run before the main function ends? // TODO: examine page 670 for when (if) I do interrupts diff --git a/src/lib/gpio/pins.rs b/src/lib/gpio/pins.rs index 3ee3053..ceb3438 100644 --- a/src/lib/gpio/pins.rs +++ b/src/lib/gpio/pins.rs @@ -1,7 +1,17 @@ -use crate::{memory, L}; +use crate::{memory, H, L}; use super::ports::Port; +fn reverse_array(array: [T; N]) -> [T; N] { + let mut result: [T; N] = [::default(); N]; + + for (out_index, in_index) in (0..N).rev().enumerate() { + result[out_index] = array[in_index]; + } + + result +} + #[derive(Clone, Copy)] pub enum Pin { Zero = 0, @@ -14,6 +24,10 @@ pub enum Pin { Seven = 7, } +fn pins_to_bits(pins: &[Pin; N]) -> [u32; N] { + pins.map(|pin| pin as u32) +} + pub enum Function { Analog, Digital, @@ -23,10 +37,16 @@ pub enum Function { UART, } +pub enum Pull { + Down, + Up, + Neither, +} + /// Page 1351 of data sheet pub struct ReadablePinOptions { pub function: Function, - pub pull_up: Option, + pub pull: Pull, } pub struct ReadablePins { data_address: *mut u32, @@ -128,121 +148,49 @@ impl WritablePin { /// Page 684 of the data sheet for how the lock mechanism works const UNLOCK: u32 = 0x4C4F434B; -fn setup_pins() { - todo!(); -} - -pub fn setup_readable_pins( +fn setup_pins( port: Port, pins: [Pin; N], - options: ReadablePinOptions, -) -> ReadablePins { + writable: bool, + function: Function, + pull: Pull, +) { // Unlock the pins unsafe { memory::write(port.lock(), UNLOCK); - memory::set_bits(port.commit(), &pins.map(|bit| bit as u32)); + memory::set_bits(port.commit(), &pins_to_bits(&pins)); } // Disable analog when it's not selected (and enable analog if it is) - match options.function { + match function { Function::Analog => unsafe { - memory::set_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); + memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins)); }, _ => unsafe { - memory::clear_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); + memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins)); }, } - unsafe { - memory::clear_bits(port.direction(), &pins.map(|bit| bit as u32)); - } - - for pin in pins { - let mut memory_bits = [0; 4]; - - let min = (pin as u32) * 4; - let max = min + 4; - let range = min..max; - - for (i, memory_bit) in range.enumerate() { - memory_bits[i] = memory_bit; - } - - let values = match options.function { - Function::Analog => todo!(), - Function::Digital => [L, L, L, L], - Function::CAN => todo!(), - Function::I2C => todo!(), - Function::PWM => todo!(), - Function::UART => todo!(), - }; + // Set to output pins if output (otherwise set to input) + if writable { unsafe { - memory::write_bits(port.port_control(), &memory_bits, values); + memory::set_bits(port.direction(), &pins_to_bits(&pins)); + } + } else { + unsafe { + memory::clear_bits(port.direction(), &pins_to_bits(&pins)); } } - // Configure pull-up and pull-down resistors - match options.pull_up { - Some(true) => unsafe { - memory::set_bits(port.pull_up_select(), &pins.map(|bit| bit as u32)); - }, - Some(false) => unsafe { - memory::set_bits(port.pull_down_select(), &pins.map(|bit| bit as u32)); - }, - None => { - unsafe { - memory::clear_bits(port.pull_up_select(), &pins.map(|bit| bit as u32)); - } - unsafe { - memory::clear_bits(port.pull_down_select(), &pins.map(|bit| bit as u32)); - } - } - } - - match options.function { - Function::Digital => unsafe { - memory::set_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); - }, - Function::Analog => unsafe { - memory::clear_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); - }, - _ => todo!(), - } - - let data_address = port.data(&pins); - - let pins: [ReadablePin; N] = pins.map(|bit| ReadablePin { data_address, bit }); - - ReadablePins { data_address, pins } -} - -pub fn setup_writable_pins( - port: Port, - pins: [Pin; N], - options: WritablePinOptions, -) -> WritablePins { - // Unlock the pins - unsafe { - memory::write(port.lock(), UNLOCK); - - memory::set_bits(port.commit(), &pins.map(|bit| bit as u32)); - } - - // Disable analog when it's not selected (and enable analog if it is) - match options.function { - Function::Analog => unsafe { - memory::set_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); - }, - _ => unsafe { - memory::clear_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); - }, - } - - unsafe { - memory::set_bits(port.direction(), &pins.map(|bit| bit as u32)); - } - + let function_values = reverse_array(match function { + Function::Analog => todo!(), + Function::Digital => [L, L, L, L], + Function::CAN => [H, L, L, L], + Function::I2C => [L, L, H, H], + Function::PWM => [L, H, L, H], + Function::UART => [L, L, L, H], + }); for pin in pins { let mut memory_bits = [0; 4]; @@ -254,54 +202,76 @@ pub fn setup_writable_pins( memory_bits[i] = memory_bit; } - let values = match options.function { - Function::Analog => todo!(), - Function::Digital => [L, L, L, L], - Function::CAN => todo!(), - Function::I2C => todo!(), - Function::PWM => todo!(), - Function::UART => todo!(), - }; unsafe { - memory::write_bits(port.port_control(), &memory_bits, values); + memory::write_bits(port.port_control(), &memory_bits, function_values); + } + } + + // Configure pull-up and pull-down resistors + match pull { + Pull::Down => unsafe { + memory::set_bits(port.pull_down_select(), &pins_to_bits(&pins)); + }, + Pull::Up => unsafe { + memory::set_bits(port.pull_up_select(), &pins_to_bits(&pins)); + }, + Pull::Neither => { + unsafe { + memory::clear_bits(port.pull_up_select(), &pins_to_bits(&pins)); + } + unsafe { + memory::clear_bits(port.pull_down_select(), &pins_to_bits(&pins)); + } } } // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states - // TODO: finish - - match options.function { + // Disable alternate function when it's not used (and enable it when it is) + match function { Function::Analog | Function::Digital => unsafe { - memory::clear_bits( - port.alternate_function_select(), - &pins.map(|bit| bit as u32), - ); + memory::clear_bits(port.alternate_function_select(), &pins_to_bits(&pins)); }, _ => unsafe { - memory::set_bits( - port.alternate_function_select(), - &pins.map(|bit| bit as u32), - ); + memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins)); }, } - match options.function { - Function::Digital => unsafe { - memory::set_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); + // Enable digital function when it's needed (and disable it when it's not) + match function { + Function::Digital | Function::UART => unsafe { + memory::set_bits(port.digital_enable(), &pins_to_bits(&pins)); }, Function::Analog => unsafe { - memory::clear_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); + memory::clear_bits(port.digital_enable(), &pins_to_bits(&pins)); }, _ => todo!(), } +} + +pub fn setup_readable_pins( + port: Port, + pins: [Pin; N], + options: ReadablePinOptions, +) -> ReadablePins { + setup_pins(port, pins, false, options.function, options.pull); let data_address = port.data(&pins); + let pins: [ReadablePin; N] = pins.map(|bit| ReadablePin { data_address, bit }); + ReadablePins { data_address, pins } +} +pub fn setup_writable_pins( + port: Port, + pins: [Pin; N], + options: WritablePinOptions, +) -> WritablePins { + setup_pins(port, pins, true, options.function, Pull::Neither); + + let data_address = port.data(&pins); let pins: [WritablePin; N] = pins.map(|pin| WritablePin { data_address, bit: pin, }); - WritablePins { data_address, pins } } diff --git a/src/lib/gpio/ports.rs b/src/lib/gpio/ports.rs index 6c02e81..2c954ca 100644 --- a/src/lib/gpio/ports.rs +++ b/src/lib/gpio/ports.rs @@ -144,7 +144,7 @@ pub struct UsablePort { impl UsablePort { pub fn setup_readable_pins( - &self, + &mut self, pins: [Pin; N], options: ReadablePinOptions, ) -> ReadablePins { @@ -152,7 +152,7 @@ impl UsablePort { } pub fn setup_writable_pins( - &self, + &mut self, pins: [Pin; N], options: WritablePinOptions, ) -> WritablePins { diff --git a/src/main.rs b/src/main.rs index d374c29..1b22b58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,71 @@ #![no_std] #![no_main] +#![feature(default_alloc_error_handler)] -use core::{arch::asm, ptr}; +use core::{ + alloc::{GlobalAlloc, Layout}, + arch::asm, + cell::UnsafeCell, + ptr, +}; +// Bump pointer allocator for *single* core systems +struct BumpPointerAlloc { + head: UnsafeCell, + end: usize, +} + +unsafe impl Sync for BumpPointerAlloc {} + +unsafe impl GlobalAlloc for BumpPointerAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // `interrupt::free` is a critical section that makes our allocator safe + // to use from within interrupts + interrupt::free(|_| { + let head = self.head.get(); + let size = layout.size(); + let align = layout.align(); + let align_mask = !(align - 1); + + // move start up to the next alignment boundary + let start = (*head + align - 1) & align_mask; + + if start + size > self.end { + // a null pointer signal an Out Of Memory condition + ptr::null_mut() + } else { + *head = start + size; + start as *mut u8 + } + }) + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) { + // this allocator never deallocates memory + } +} + +// Declaration of the global memory allocator +// NOTE the user must ensure that the memory region `[0x2000_0100, 0x2000_0200]` +// is not used by other parts of the program +#[global_allocator] +static HEAP: BumpPointerAlloc = BumpPointerAlloc { + head: UnsafeCell::new(0x2000_0100), + end: 0x2000_0200, +}; + +#[macro_use] +extern crate alloc; +use alloc::string::String; +use alloc::{format, vec}; + +use cortex_m::interrupt; use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics use cortex_m_rt::entry; use driver_and_task_library::{ setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, UsableBoard, - WritablePinOptions, H, L, + WritablePinOptions, H, L, Pull, }; const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32; @@ -24,6 +81,18 @@ const UART0_CTL_R: *mut u32 = 0x4000C030 as *mut u32; const GPIO_PORTA_AFSEL_R: *mut u32 = 0x40004420 as *mut u32; const GPIO_PORTA_DEN_R: *mut u32 = 0x4000451C as *mut u32; +// page 219 +/// 16 MHz +const SYSTEM_OSC_CLOCK_SPEED: u32 = 16_000_000; +// the MOSC is variable frequeny (5 MHz to 25 MHz) + +// the XOSC can act as a real time clock as well! + +// The internal system clock (SysClk), is derived from any of the above sources plus two others: the +// output of the main internal PLL and the precision internal oscillator divided by four (4 MHz ± 1%). +// The frequency of the PLL clock reference must be in the range of 5 MHz to 25 MHz (inclusive). +// Table 5-3 on page 220 shows how the various clock sources can be used in a system + /// UART0 Clock Gating Control const SYSCTL_RCGC1_UART0: u32 = 0x00000001; /// port A Clock Gating Control @@ -41,13 +110,14 @@ const UART_FR_RXFE: u32 = 0x00000010; /// Pins 0 and 1 const PINS_0_AND_1: u32 = 0b0000_0011; -fn uart0_init(board: UsableBoard) { +fn uart0_init(board: &mut UsableBoard) { unsafe { // activate UART0 ptr::write_volatile( SYSCTL_RCGC1_R, ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0, ); + // activate port A // ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA); // ^ commented in favor of v @@ -113,16 +183,38 @@ fn uart0_out_string(s: &str) { } } +const RED: [bool; 3] = [H, L, L]; +const YELLOW: [bool; 3] = [H, H, L]; +const GREEN: [bool; 3] = [L, H, L]; + #[entry] fn main() -> ! { - let board = setup_board(); - let port_f = board.setup_gpio_port(Port::F, PortOptions); + let mut board = setup_board(); + let mut port_a = board.setup_gpio_port(Port::A, PortOptions); + let mut port_f = board.setup_gpio_port(Port::F, PortOptions); + + uart0_init(&mut board); + + // WIP: page 682 + port_a.setup_writable_pins( + [Pin::One], + WritablePinOptions { + function: Function::UART, + }, + ); + + uart0_out_string("Hi, this is after uart setup_writable_pins\r\n\r\n"); + // TODO: finish this + // port_a.setup_readable_pins([Pin::Zero], WritablePinOptions { + // function: Function::UART, + // }); + // uart0_out_string("Hi, this is after uart setup_readable_pins\r\n\r\n"); let switches = port_f.setup_readable_pins( [Pin::Zero, Pin::Four], ReadablePinOptions { function: Function::Digital, - pull_up: Some(true), + pull: Pull::Up, }, ); let [_sw1, _sw2] = switches.pins(); @@ -134,45 +226,33 @@ fn main() -> ! { }, ); - let white = [H, H, H]; - let _black = [L, L, L]; + let WHITE = [H, H, H]; + let BLACK = [L, L, L]; - let red = [H, L, L]; - let yellow = [H, H, L]; - let green = [L, H, L]; - let cyan = [L, H, H]; - let blue = [L, L, H]; - let magenta = [H, L, H]; + let CYAN = [L, H, H]; + let BLUE = [L, L, H]; + let MAGENTA = [H, L, H]; - let rainbow = [red, yellow, green, cyan, blue, magenta]; + let rainbow = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA]; - rgb_led.write_all(cyan); - - uart0_init(board); - - rgb_led.write_all(white); - - for _ in 0..2 { - for c in [ - 'H', 'a', 'y', '!', '\r', '\n', 'H', 'e', 'y', '!', '\r', '\n', 'H', 'e', 'y', '!', - '\r', '\n', 'H', 'e', 'y', '!', '\r', '\n', - ] { - uart0_out_char(c as u8); - } - } - uart0_out_string("Those example string!\r\n"); + // TODO: WIP: debugging + // let s = format!("Rainbow: {:?}\r\n", rainbow); + let s = String::from("\r\ntesting a static string!!!\r\n\r\n\r\n"); + // let s = format!("Format"); + // let s: String = rainbow.into(); + uart0_out_string(&s); loop { + uart0_out_string("Hi the program is still running down here!\r\n"); match switches.read_all() { - [L, L] => { - rgb_led.write_all(white); - uart0_out_string("Hey! You're pressing the button down!\r\n"); - } - [L, H] => rgb_led.write_all(blue), - [H, L] => rgb_led.write_all(red), - [H, H] => rgb_led.write_all(green), + [L, L] => rgb_led.write_all(WHITE), + [L, H] => rgb_led.write_all(BLUE), + [H, L] => rgb_led.write_all(RED), + [H, H] => rgb_led.write_all(BLACK), } + // uart0_out_string(&format!("The switches read {:?}", switches.read_all())); + for _ in 0..1000000 { unsafe { asm!("nop");