From 062441b5e26b92f744e52252b46f1ed38f6785cb Mon Sep 17 00:00:00 2001 From: J / Jacob Babich Date: Fri, 29 Apr 2022 23:24:13 -0400 Subject: [PATCH] update --- Cargo.lock | 199 +-------------------------- Cargo.toml | 4 +- README.md | 1 - examples/switches_to_led.rs | 2 +- src/lib/board.rs | 26 ++-- src/lib/gpio/pins.rs | 2 +- src/lib/gpio/ports.rs | 7 +- src/lib/memory.rs | 18 +-- src/lib/mod.rs | 123 ++++++++++++++++- src/lib/uart.rs | 189 ++++++++++++++++++++++---- src/main--ideas.rs | 59 -------- src/main.rs | 259 ++++++------------------------------ 12 files changed, 353 insertions(+), 536 deletions(-) delete mode 100644 README.md delete mode 100644 src/main--ideas.rs diff --git a/Cargo.lock b/Cargo.lock index 6816670..6fceaeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,67 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aligned" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a785a543aea40f5e4e2e93bb2655d31bc21bb391fff65697150973e383f16bb" -dependencies = [ - "as-slice", -] - -[[package]] -name = "as-slice" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" -dependencies = [ - "generic-array 0.12.4", - "generic-array 0.13.3", - "generic-array 0.14.5", - "stable_deref_trait", -] - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "cortex-m" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9075300b07c6a56263b9b582c214d0ff037b00d45ec9fde1cc711490c56f1bb9" -dependencies = [ - "aligned", - "bare-metal", - "bitfield", - "cortex-m 0.7.4", - "volatile-register", -] - -[[package]] -name = "cortex-m" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ff967e867ca14eba0c34ac25cd71ea98c678e741e3915d923999bb2fe7c826" -dependencies = [ - "bare-metal", - "bitfield", - "embedded-hal", - "volatile-register", -] - [[package]] name = "cortex-m-rt" version = "0.6.15" @@ -84,84 +23,13 @@ dependencies = [ "syn", ] -[[package]] -name = "cortex-m-semihosting" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc" -dependencies = [ - "cortex-m 0.7.4", -] - [[package]] name = "driver-and-task-library" version = "4.14.0" dependencies = [ - "cortex-m 0.6.7", "cortex-m-rt", - "cortex-m-semihosting", - "panic-halt", ] -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "panic-halt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" - [[package]] name = "proc-macro2" version = "1.0.37" @@ -186,82 +54,19 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "syn" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" -dependencies = [ - "vcell", -] diff --git a/Cargo.toml b/Cargo.toml index b30d210..1c6f223 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,7 @@ name = "driver-and-task-library" version = "4.14.0" [dependencies] -cortex-m = "0.6.0" cortex-m-rt = "0.6.10" -cortex-m-semihosting = "0.3.3" -panic-halt = "0.2.0" [lib] path = "src/lib/mod.rs" @@ -22,6 +19,7 @@ test = false bench = false [profile.release] +# These comments are from the starter project (not written by me). I left them in since they explain it: codegen-units = 1 # better optimizations debug = true # symbols are nice and they don't increase the size on Flash lto = true # better optimizations diff --git a/README.md b/README.md deleted file mode 100644 index 536601c..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO: Write README diff --git a/examples/switches_to_led.rs b/examples/switches_to_led.rs index 75d66fa..147d866 100644 --- a/examples/switches_to_led.rs +++ b/examples/switches_to_led.rs @@ -12,7 +12,7 @@ use driver_and_task_library::{ #[entry] fn main() -> ! { let board = setup_board(); - let port_f = board.setup_gpio_port(Port::F, GPIOPortOptions); + let port_f = board.setup_gpio_port(Port::F); let switches = port_f.setup_readable_pins( [Pin::Zero, Pin::Four], diff --git a/src/lib/board.rs b/src/lib/board.rs index e1943df..398913c 100644 --- a/src/lib/board.rs +++ b/src/lib/board.rs @@ -3,7 +3,7 @@ use core::arch::asm; use crate::gpio::ports::{ - setup_port as setup_gpio_port, GPIOPortOptions, Port as GPIOPort, UsablePort as UsableGPIOPort, + setup_port as setup_gpio_port, Port as GPIOPort, UsablePort as UsableGPIOPort, }; use crate::uart::{ setup_port as setup_uart_port, Port as UARTPort, PortOptions as UARTPortOptions, @@ -22,15 +22,18 @@ impl Board { 0x400F_E000 } - /// The memory address of the GPIO Run mode clock gating control (RCGCGPIO) register for this port + /// The memory address of the GPIO Run mode clock gating control (RCGCGPIO) register for GPIO ports /// /// Page 340 of data sheet - pub(crate) const fn gpio_run_mode_clock_gate_control(&self) -> *mut u32 { + pub(crate) const fn gpio_run_mode_clock_gating_control(&self) -> *mut u32 { const OFFSET: u32 = 0x608; (self.base() + OFFSET) as *mut u32 } - pub(crate) const fn run_mode_clock_gate_control_1(&self) -> *mut u32 { + /// The memory address of the TODO + /// + /// Page TODO of data sheet + pub(crate) const fn run_mode_clock_gating_control_1(&self) -> *mut u32 { const OFFSET: u32 = 0x104; (self.base() + OFFSET) as *mut u32 } @@ -42,23 +45,30 @@ pub struct UsableBoard { } impl UsableBoard { - fn no_op(&self) { + pub(crate) fn no_op(&self) { unsafe { asm!("nop"); } } + + pub(crate) fn no_ops(&self, n: u32) { + for _ in 0..n { + self.no_op(); + } + } } impl UsableBoard { - pub fn setup_gpio_port(&mut self, port: GPIOPort, options: GPIOPortOptions) -> UsableGPIOPort { - setup_gpio_port(self.board, port, options) + pub fn setup_gpio_port(&mut self, port: GPIOPort) -> UsableGPIOPort { + setup_gpio_port(self.board, port) } pub fn setup_uart_port(&mut self, port: UARTPort, options: UARTPortOptions) -> UsableUARTPort { - setup_uart_port(self.board, port, options, &|| self.no_op()) + setup_uart_port(self.board, port, options, &|n| self.no_ops(n)) } } +/// Start using the driver and task library by setting up the TM4C123GXL board pub fn setup_board() -> UsableBoard { UsableBoard { board: Board } } diff --git a/src/lib/gpio/pins.rs b/src/lib/gpio/pins.rs index c7ea1e1..2ff9f02 100644 --- a/src/lib/gpio/pins.rs +++ b/src/lib/gpio/pins.rs @@ -86,7 +86,7 @@ impl WritablePins { ) } } - pub fn update_all [bool; N]>(&mut self, updater: Updater) { + pub fn update_all(&mut self, updater: &dyn Fn([bool; N]) -> [bool; N]) { self.write_all(updater(self.read_all())); } diff --git a/src/lib/gpio/ports.rs b/src/lib/gpio/ports.rs index 4339090..6026a63 100644 --- a/src/lib/gpio/ports.rs +++ b/src/lib/gpio/ports.rs @@ -14,7 +14,7 @@ pub enum Port { F, } -pub struct GPIOPortOptions; +pub struct PortOptions; impl Port { /// The starting point of memory addresses corresponding to this GPIO register @@ -160,11 +160,10 @@ impl UsablePort { } } -// TODO: remove unused port setup options -pub fn setup_port(board: Board, port: Port, _options: GPIOPortOptions) -> UsablePort { +pub fn setup_port(board: Board, port: Port) -> UsablePort { unsafe { memory::set_bits( - board.gpio_run_mode_clock_gate_control(), + board.gpio_run_mode_clock_gating_control(), &[port.run_mode_clock_gate_control()], ); } diff --git a/src/lib/memory.rs b/src/lib/memory.rs index ee69179..b8a8752 100644 --- a/src/lib/memory.rs +++ b/src/lib/memory.rs @@ -9,7 +9,7 @@ pub unsafe fn write(address: *mut u32, new: u32) { ptr::write_volatile(address, new); } -pub unsafe fn update u32>(address: *mut u32, updater: Updater) { +pub unsafe fn update(address: *mut u32, updater: &dyn Fn(u32) -> u32) { write(address, updater(read(address))); } @@ -19,7 +19,7 @@ pub unsafe fn read_bits(address: *const u32, bits: &[u32; N]) -> bits.map(|bit| current & (1 << bit) != 0) } pub unsafe fn write_bits(address: *mut u32, bits: &[u32; N], values: [bool; N]) { - update(address, |current| { + update(address, &|current| { bits.iter().zip(values).fold(current, |result, (bit, set)| { if set { result | (1 << bit) @@ -30,27 +30,19 @@ pub unsafe fn write_bits(address: *mut u32, bits: &[u32; N], val }) } -pub unsafe fn update_bits [bool; N], const N: usize>( - address: *mut u32, - bits: &[u32; N], - updater: Updater, -) { - write_bits(address, bits, updater(read_bits(address, bits))) -} - pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) { - update(address, |current| { + update(address, &|current| { bits.iter().fold(current, |result, bit| result | (1 << bit)) }) } pub unsafe fn clear_bits(address: *mut u32, bits: &[u32]) { - update(address, |current| { + update(address, &|current| { bits.iter() .fold(current, |result, bit| result & !(1 << bit)) }) } pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) { - update(address, |current| { + update(address, &|current| { bits.iter().fold(current, |result, bit| result ^ (1 << bit)) }) } diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 75a54f8..f2fb76a 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -1,4 +1,5 @@ #![no_std] +#![feature(alloc_error_handler)] mod board; mod gpio; @@ -8,7 +9,127 @@ mod utils; pub use board::*; pub use gpio::pins::*; -pub use gpio::ports::*; +pub use gpio::ports::{Port as GPIOPort, PortOptions as GPIOPortOptions}; +pub use uart::{Port as UARTPort, PortOptions as UARTPortOptions, WordLength}; pub const H: bool = true; pub const L: bool = false; + +extern crate alloc; +use alloc::string::ToString; +use core::alloc::{GlobalAlloc, Layout}; +use core::panic::PanicInfo; +use core::ptr; + +const BLACK: [bool; 3] = [L, L, L]; + +const RED: [bool; 3] = [H, L, L]; +const YELLOW: [bool; 3] = [H, H, L]; +const CYAN: [bool; 3] = [L, H, H]; + +#[panic_handler] +fn panic(panic_info: &PanicInfo) -> ! { + let mut board = setup_board(); + + let mut port_f = board.setup_gpio_port(GPIOPort::F); + + let mut rgb_led = port_f.setup_writable_pins( + [Pin::One, Pin::Three, Pin::Two], + WritablePinOptions { + function: Function::Digital, + }, + ); + + // Set the LED to red in case setting up UART causes the system to hang + // and the loop where we flash red / cyan isn't reached + // (but there's no reason that should happen...) + rgb_led.write_all(RED); + + let mut port_a = board.setup_gpio_port(GPIOPort::A); + let [_uart_0_rx] = port_a + .setup_readable_pins( + [Pin::Zero], + ReadablePinOptions { + function: Function::UART, + pull: Pull::Neither, + }, + ) + .pins(); + let [mut uart_0_tx] = port_a + .setup_writable_pins( + [Pin::One], + WritablePinOptions { + function: Function::UART, + }, + ) + .pins(); + let mut uart_0 = board.setup_uart_port( + UARTPort::Zero, + UARTPortOptions { + baud_rate: 115_200, + fifos: true, + word_length: WordLength::Eight, + }, + ); + + // https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797 + uart_0.write_line(&mut uart_0_tx, "\x1b[31m"); + uart_0.write_line(&mut uart_0_tx, &panic_info.to_string()); + uart_0.write_line(&mut uart_0_tx, "\x1b[0m"); + + let pattern = [RED, BLACK, CYAN, BLACK]; + + loop { + for color in pattern { + rgb_led.write_all(color); + board.no_ops(1_000_000); + } + } +} + +struct BumpPointerAlloc; +static mut HEAP: [u8; 0x1000] = [0; 0x1000]; +static mut USED: usize = 0; + +#[global_allocator] +static ALLOCATOR: BumpPointerAlloc = BumpPointerAlloc; + +unsafe impl GlobalAlloc for BumpPointerAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let size = layout.size(); + + if USED + size > HEAP.len() { + ptr::null_mut() + } else { + let pointer = &mut HEAP[USED] as *mut u8; + USED += size; + + pointer + } + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) {} +} + +#[alloc_error_handler] +fn alloc_error(_cause: Layout) -> ! { + let mut board = setup_board(); + + let mut port_f = board.setup_gpio_port(GPIOPort::F); + + let mut rgb_led = port_f.setup_writable_pins( + [Pin::One, Pin::Three, Pin::Two], + WritablePinOptions { + function: Function::Digital, + }, + ); + + let pattern = [YELLOW, BLACK, RED, BLACK]; + + loop { + for color in pattern { + rgb_led.write_all(color); + board.no_ops(1_000_000); + } + } +} diff --git a/src/lib/uart.rs b/src/lib/uart.rs index 58cb866..a615496 100644 --- a/src/lib/uart.rs +++ b/src/lib/uart.rs @@ -1,4 +1,6 @@ -use crate::{memory, Board}; +use alloc::string::String; + +use crate::{memory, Board, ReadablePin, WritablePin, H, L}; #[derive(Clone, Copy)] pub enum Port { @@ -11,8 +13,19 @@ pub enum Port { Six = 6, Seven = 7, } + +#[derive(Clone, Copy)] +pub enum WordLength { + Five, + Six, + Seven, + Eight, +} + pub struct PortOptions { - pub baud_rate: u32, // TODO: right type? + pub baud_rate: u32, + pub fifos: bool, + pub word_length: WordLength, } impl Port { @@ -60,7 +73,7 @@ impl Port { /// /// Page TODO of data sheet pub(super) const fn fractional_baud_rate_divisor(&self) -> *mut u32 { - const OFFSET: u32 = 0x018; // TODO + const OFFSET: u32 = 0x028; // TODO (self.base() + OFFSET) as *mut u32 } @@ -68,9 +81,28 @@ impl Port { /// /// Page TODO of data sheet pub(super) const fn integer_baud_rate_divisor(&self) -> *mut u32 { - const OFFSET: u32 = 0x018; // TODO + const OFFSET: u32 = 0x024; // TODO (self.base() + OFFSET) as *mut u32 } + + /// The memory address of the line control (LCRH) register for this port + /// + /// Page 916 of data sheet + pub(super) const fn line_control(&self) -> *mut u32 { + const OFFSET: u32 = 0x02C; + (self.base() + OFFSET) as *mut u32 + } +} + +impl Port { + /// The receive FIFO empty (RXFE) bit in the flag register + const fn receive_fifo_empty(&self) -> u32 { + 4 + } + /// The transmit FIFO full (TXFF) bit in the flag register + const fn transmit_fifo_full(&self) -> u32 { + 5 + } } impl Port { @@ -79,17 +111,29 @@ impl Port { 0 } + /// The enable FIFOs (FEN) bit in the line control register + const fn enable_fifos_bit(&self) -> u32 { + 4 + } + + /// The word length (WLEN) bits in the line control register + const fn word_length_bits(&self) -> [u32; 2] { + [6, 5] + } +} + +impl Port { /// The system's Run mode clock gating control (RCGC) register address containing this port - fn run_mode_clock_gate_control_address(&self, board: Board) -> *mut u32 { + const fn run_mode_clock_gating_control_address(&self, board: &Board) -> *mut u32 { match self { - Port::Zero => board.run_mode_clock_gate_control_1(), - Port::One => board.run_mode_clock_gate_control_1(), - Port::Two => board.run_mode_clock_gate_control_1(), + Port::Zero => board.run_mode_clock_gating_control_1(), + Port::One => board.run_mode_clock_gating_control_1(), + Port::Two => board.run_mode_clock_gating_control_1(), _ => todo!(), } } /// The corresponding bit for this port in the system's Run mode clock gating control (RCGC) register - fn run_mode_clock_gate_control_bit(&self) -> u32 { + const fn run_mode_clock_gating_control_bit(&self) -> u32 { match self { Port::Zero => 0, Port::One => 1, @@ -104,25 +148,102 @@ pub struct UsablePort { } impl UsablePort { - pub fn do_something() { - todo!(); + // TODO: add comments + pub fn read_byte(&self, _receive_pin: &ReadablePin, blocking: bool) -> Option { + loop { + let [receive_fifo_empty] = + unsafe { memory::read_bits(self.port.flag(), &[self.port.receive_fifo_empty()]) }; + + if !receive_fifo_empty { + let byte = unsafe { memory::read(self.port.data()) } as u8; + return Some(byte); + } + + if !blocking { + return None; + } + } + } + pub fn write_byte( + &mut self, + _transmit_pin: &mut WritablePin, + byte: u8, + blocking: bool, + ) -> bool { + loop { + let [transmit_fifo_full] = + unsafe { memory::read_bits(self.port.flag(), &[self.port.transmit_fifo_full()]) }; + + if !transmit_fifo_full { + unsafe { memory::write(self.port.data(), byte as u32) }; + return true; + } + + if !blocking { + return false; + } + } + } + + pub fn write_string(&mut self, _transmit_pin: &mut WritablePin, string: &str) { + for byte in string.bytes() { + self.write_byte(_transmit_pin, byte, true); + } + } + + pub fn write_line(&mut self, _transmit_pin: &mut WritablePin, string: &str) { + self.write_string(_transmit_pin, string); + self.write_string(_transmit_pin, "\r\n"); + } + // TODO: validate the passed transmit or receive pin belongs to this UART port + + pub fn read_line( + &mut self, + _transmit_pin: &mut WritablePin, + _receive_pin: &ReadablePin, + ) -> String { + let mut s = String::new(); + + loop { + if let Some(c) = self.read_byte(_receive_pin, true) { + // Enter + if c == b'\r' { + self.write_string(_transmit_pin, "\r\n"); + return s; + } + // Backspace + else if c == b'\x7F' { + if !s.is_empty() { + // https://stackoverflow.com/a/53976873 + self.write_string(_transmit_pin, "\x1B[1D\x1B[1P"); + s.pop(); + } + } else { + self.write_byte(_transmit_pin, c, true); + s.push(c as char); + } + } + } } } -pub fn setup_port(board: Board, port: Port, options: PortOptions, no_op: &dyn Fn()) -> UsablePort { +pub fn setup_port( + board: Board, + port: Port, + options: PortOptions, + no_ops: &dyn Fn(u32), +) -> UsablePort { // Activate the associated peripheral unsafe { memory::set_bits( - board.run_mode_clock_gate_control_1(), - &[port.run_mode_clock_gate_control_bit()], + port.run_mode_clock_gating_control_address(&board), + &[port.run_mode_clock_gating_control_bit()], ); } // Page 904: There must be a delay of 3 system clocks after the UART module clock is enabled before any UART module registers are accessed. - // But for some reason, 7 (not 3) no-ops are needed - for _ in 0..7 { - no_op(); - } + // But in actuality, 7 (not 3) no-ops are needed for some reason + no_ops(7); // Disable this UART port while setting it up unsafe { @@ -145,8 +266,7 @@ pub fn setup_port(board: Board, port: Port, options: PortOptions, no_op: &dyn Fn // TODO: migrate all of the above comments to a github issue // TODO: how do you determine what's being used as the system clock?! - let system_clock = SYSTEM_OSC_CLOCK_SPEED; - + let system_clock = SYSTEM_OSC_CLOCK_SPEED; // TODO: The UART generates an internal baud-rate reference clock at 8x or 16x the baud-rate (referred to // as Baud8 and Baud16, depending on the setting of the HSE bit (bit 5) in UARTCTL) @@ -158,21 +278,38 @@ pub fn setup_port(board: Board, port: Port, options: PortOptions, no_op: &dyn Fn let baud_rate_divisor_fraction = baud_rate_divisor - (baud_rate_divisor_integer as f32); // TODO: - // if baud_rate_divisor_integer.to_bits() > 22 { + // if baud_rate_divisor_integer.to_bits().length > 22 { // panic!(); // } - let baud_rate_divisor_fraction = ((baud_rate_divisor_fraction * 64.0) + 0.5) as u8; + let baud_rate_divisor_fraction = ((baud_rate_divisor_fraction * 64.0) + 0.5) as u32; - // TODO: verify and comment unsafe { memory::write(port.integer_baud_rate_divisor(), baud_rate_divisor_integer); - memory::write(port.fractional_baud_rate_divisor(), baud_rate_divisor_fraction as u32); + memory::write( + port.fractional_baud_rate_divisor(), + baud_rate_divisor_fraction, + ); } - // TODO: CTL LCHR register - todo!(); + // Set the word length + // Page 916 of data sheet + let word_length = match options.word_length { + WordLength::Five => [L, L], + WordLength::Six => [L, H], + WordLength::Seven => [H, L], + WordLength::Eight => [H, H], + }; + unsafe { + memory::write_bits(port.line_control(), &port.word_length_bits(), word_length); + } + + // Enable or disable FIFOs + let fifos = if options.fifos { [H] } else { [L] }; + unsafe { + memory::write_bits(port.line_control(), &[port.enable_fifos_bit()], fifos); + } // Enable this UART port unsafe { diff --git a/src/main--ideas.rs b/src/main--ideas.rs deleted file mode 100644 index 5684987..0000000 --- a/src/main--ideas.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] -#![no_main] - -use panic_halt as _; - -use cortex_m_rt::entry; - -use my_library::{Bit, Color, setup_board}; - -const H: bool = true; -const L: bool = false; - -#[entry] -fn main() -> ! { - let board = setup_board(); - - let port_f = board.setup_port(Port::F); - - let switches = port_f.setup_readable_pins([Bit::Zero, Bit::Four], PinSetup { - alternate_function: false, - analog: false, - pullup: true, - pctl: false, - }); - - let rgb_led = port_f.setup_writable_pins([Bit::One, Bit::Three, Bit::Two], PinSetup { - alternate_function: false, - analog: false, - pctl: false, - }); - - // Integrate PWM for arbitrary color support - let rgb_led_driver = rgb_led.driver(); - - // Maybe? - let every_5_seconds = board.time_trigger(5); - - // Example of adding tasks - board.add_task( - some_kind_of_task, - 10, // priority maybe? - every_5_seconds, // trigger every 5 seconds - ); - - loop { - match switches.read_all() { - [L, L] => rgb_led_driver.set_color(Color::Green), - [L, H] => rgb_led_driver.set_color(Color::Blue), - [H, L] => rgb_led_driver.set_color(Color::Red), - [H, H] => rgb_led_driver.set_color(Color::Black), - } - } -} - - -fn some_kind_of_task() { - // ... -} - diff --git a/src/main.rs b/src/main.rs index 8cead1b..81cea3d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,209 +1,31 @@ #![no_std] #![no_main] -#![feature(default_alloc_error_handler)] -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, -}; - -// TODO: remove or fix -// #[macro_use] extern crate alloc; -use alloc::string::String; - -use cortex_m::interrupt; -use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics - +use alloc::format; use cortex_m_rt::entry; use driver_and_task_library::{ - setup_board, Function, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions, - WritablePinOptions, H, L, + setup_board, Function, GPIOPort, Pin, Pull, ReadablePinOptions, UARTPort, + UARTPortOptions, WordLength, WritablePinOptions, H, L, }; -const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32; - -/// UART0 data register -const UART0_DR_R: *mut u32 = 0x4000C000 as *mut u32; -/// UART0 flag register -const UART0_FR_R: *mut u32 = 0x4000C018 as *mut u32; -/// UART0 integer baud rate register -const UART0_IBRD_R: *mut u32 = 0x4000C024 as *mut u32; -/// UART0 fractional baud rate register -const UART0_FBRD_R: *mut u32 = 0x4000C028 as *mut u32; -/// UART0 line control register -const UART0_LCRH_R: *mut u32 = 0x4000C02C as *mut u32; -/// UART0 control register -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; - - -/// UART0 Clock Gating Control -const SYSCTL_RCGC1_UART0: u32 = 0x00000001; -/// UART Enable -const UART_CTL_UARTEN: u32 = 0x00000001; -/// 8 bit word length -const UART_LCRH_WLEN_8: u32 = 0x00000060; -/// UART Enable FIFOs -const UART_LCRH_FEN: u32 = 0x00000010; -/// UART Transmit FIFO Full -const UART_FR_TXFF: u32 = 0x00000020; -/// UART Receive FIFO Empty -const UART_FR_RXFE: u32 = 0x00000010; -/// Pins 0 and 1 -const PINS_0_AND_1: u32 = 0b0000_0011; - -fn uart0_init() { - unsafe { - // activate UART0 - ptr::write_volatile( - SYSCTL_RCGC1_R, - ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0, - ); - // write_color(MAGENTA); - - // For some reason, 7 no-ops are needed to stall the CPU while UART is enabled - for _ in 0..7 { - asm!("nop"); - } - - // TODO / WIP: done up to here - - // disable UART while setting it up - ptr::write_volatile( - UART0_CTL_R, - ptr::read_volatile(UART0_CTL_R) & !UART_CTL_UARTEN, - ); - - // IBRD = int(16,000,000 / (16 * 115,200)) = int(8.680) - // ptr::write_volatile(UART0_IBRD_R, 8); - ptr::write_volatile(UART0_IBRD_R, 8); - - // ignore: // FBRD = int(0.1267 * 64 + 0.5) = 8 - // FBRD = round(0.5104 * 64 ) = 33 --- that ain't the number you wrote but ok - // ptr::write_volatile(UART0_FBRD_R, 44); - ptr::write_volatile(UART0_FBRD_R, 44); - - // 8 bit word length (no parity bits, one stop bit, FIFOs) - // ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8|UART_LCRH_FEN); - ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8 | UART_LCRH_FEN); - - // enable UART since it's been set up - ptr::write_volatile( - UART0_CTL_R, - ptr::read_volatile(UART0_CTL_R) | UART_CTL_UARTEN, - ); - - // enable alt funct on PA1-0 - ptr::write_volatile( - GPIO_PORTA_AFSEL_R, - ptr::read_volatile(GPIO_PORTA_AFSEL_R) | PINS_0_AND_1, - ); - // enable digital I/O on PA1-0 - ptr::write_volatile( - GPIO_PORTA_DEN_R, - ptr::read_volatile(GPIO_PORTA_AFSEL_R) | PINS_0_AND_1, - ); - } -} - -fn uart0_out_char_blocking(c: u8) { - loop { - let fr = unsafe { ptr::read_volatile(UART0_FR_R) }; - - if (fr & UART_FR_TXFF) == 0 { - break; - } - } - - unsafe { - ptr::write_volatile(UART0_DR_R, c as u32); - } -} - -fn uart0_out_string_blocking(s: &str) { - for c in s.bytes() { - uart0_out_char_blocking(c); - } -} - -fn uart0_in_char_blocking() -> u8 { - loop { - let fr = unsafe { ptr::read_volatile(UART0_FR_R) }; - - if (fr & UART_FR_RXFE) == 0 { - break; - } - } - - unsafe { ptr::read_volatile(UART0_DR_R) as u8 } -} - const WHITE: [bool; 3] = [H, H, H]; const BLACK: [bool; 3] = [L, L, L]; const RED: [bool; 3] = [H, L, L]; -const YELLOW: [bool; 3] = [H, H, L]; -const GREEN: [bool; 3] = [L, H, L]; -const CYAN: [bool; 3] = [L, H, H]; +const _YELLOW: [bool; 3] = [H, H, L]; +const _GREEN: [bool; 3] = [L, H, L]; +const _CYAN: [bool; 3] = [L, H, H]; const BLUE: [bool; 3] = [L, L, H]; -const MAGENTA: [bool; 3] = [H, L, H]; +const _MAGENTA: [bool; 3] = [H, L, H]; + +static _RAINBOW: [[bool; 3]; 6] = [RED, _YELLOW, _GREEN, _CYAN, BLUE, _MAGENTA]; #[entry] fn main() -> ! { let mut board = setup_board(); - let mut port_a = board.setup_gpio_port(Port::A, GPIOPortOptions); - let mut port_f = board.setup_gpio_port(Port::F, GPIOPortOptions); + let mut port_f = board.setup_gpio_port(GPIOPort::F); let switches = port_f.setup_readable_pins( [Pin::Zero, Pin::Four], ReadablePinOptions { @@ -218,33 +40,35 @@ fn main() -> ! { }, ); - // TODO: finish this - uart0_init(); - // WIP: page 682 - port_a.setup_writable_pins( - [Pin::One], - WritablePinOptions { - function: Function::UART, + let mut port_a = board.setup_gpio_port(GPIOPort::A); + let [uart_0_rx] = port_a + .setup_readable_pins( + [Pin::Zero], + ReadablePinOptions { + function: Function::UART, + pull: Pull::Neither, + }, + ).pins(); + let [mut uart_0_tx] = port_a + .setup_writable_pins( + [Pin::One], + WritablePinOptions { + function: Function::UART, + }, + ).pins(); + let mut uart_0 = board.setup_uart_port( + UARTPort::Zero, + UARTPortOptions { + baud_rate: 115_200, + fifos: true, + word_length: WordLength::Eight, }, ); - uart0_out_string_blocking("Hi, this is after!! uart setup_writable_pins\r\n\r\n"); - port_a.setup_readable_pins( - [Pin::Zero], - ReadablePinOptions { - function: Function::UART, - pull: Pull::Neither, - }, - ); - uart0_out_string_blocking("Hi, this is after uart setup_readable_pins\r\n\r\n"); - let rainbow = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA]; - - // TODO: WIP: debugging - let s = String::from("\r\ntesting a static string!!!\r\n\r\n\r\n"); - uart0_out_string_blocking(&s); + uart_0.write_line(&mut uart_0_tx, ""); + uart_0.write_line(&mut uart_0_tx, "Program start!"); loop { - // uart0_out_string_blocking("Hi still running down here!\r\n"); match switches.read_all() { [L, L] => rgb_led.write_all(WHITE), [L, H] => rgb_led.write_all(BLUE), @@ -252,17 +76,8 @@ fn main() -> ! { [H, H] => rgb_led.write_all(BLACK), } - // uart0_out_string(&format!("The switches read {:?}", switches.read_all())); - - // for _ in 0..1000000 { - // unsafe { - // asm!("nop"); - // } - // } - - let new_char = uart0_in_char_blocking(); - uart0_out_string_blocking("New character received: "); - uart0_out_char_blocking(new_char); - uart0_out_string_blocking("\r\n"); + uart_0.write_string(&mut uart_0_tx, "What's your name? "); + let input = uart_0.read_line(&mut uart_0_tx, &uart_0_rx); + uart_0.write_line(&mut uart_0_tx, &format!("Good afternoon {:?}!", &input)); } }