From 18e9a5d7dee7f1ad4810f8fd0de68e26aed3ae87 Mon Sep 17 00:00:00 2001 From: J / Jacob Babich Date: Fri, 22 Apr 2022 03:11:45 -0400 Subject: [PATCH] starting uart and refactoring --- Cargo.lock | 4 +- examples/switches_to_led.rs | 7 +- src/.DS_Store | Bin 0 -> 6148 bytes src/lib/board.rs | 66 +++++++++++-- src/lib/gpio/pins.rs | 157 ++++++++++++++++--------------- src/lib/gpio/ports.rs | 35 +++---- src/lib/memory.rs | 53 +++-------- src/lib/mod.rs | 3 +- src/lib/registers.rs | 16 ---- src/lib/uart.rs | 183 ++++++++++++++++++++++++++++++++++++ src/lib/utils.rs | 15 +++ src/main.rs | 125 ++++++++++++------------ 12 files changed, 436 insertions(+), 228 deletions(-) create mode 100644 src/.DS_Store delete mode 100644 src/lib/registers.rs create mode 100644 src/lib/uart.rs create mode 100644 src/lib/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 16d81fe..6816670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] diff --git a/examples/switches_to_led.rs b/examples/switches_to_led.rs index 5727bca..75d66fa 100644 --- a/examples/switches_to_led.rs +++ b/examples/switches_to_led.rs @@ -5,19 +5,20 @@ use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch use cortex_m_rt::entry; use driver_and_task_library::{ - setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, WritablePinOptions, H, L, + setup_board, Function, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions, + WritablePinOptions, H, L, }; #[entry] fn main() -> ! { let board = setup_board(); - let port_f = board.setup_gpio_port(Port::F, PortOptions); + let port_f = board.setup_gpio_port(Port::F, GPIOPortOptions); 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(); diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..10f4d43063cf2afdea345ed0e8725c067b6d3ef7 GIT binary patch literal 6148 zcmeH~O=`nH427SXECStlndNM9fZkvT$q90S5(*^{5-7CmIeMRdHg&o#raXc4Mj8v- z-@;=7u>I%T3orrL&|R_fFf(Jm!W9>szfK>w>;3l5idTWBh?%i6VYXk}5)lvq5fA|p z5P<~|$Wt7f=LJ2J9z_I1U>OAb`_SmFy>z6;r-LCz0P33MFs@^kpf)d1d+A7Jg=RH9 zShZS=AzqJmYOCvd=}66XSPdUmcQ&75XqN4;#)M`)L_q{ZU`Ak-`Q+#Sk^bBKKWkAc z0wVCw2-x~?I_&vUb+$gdp4VTi>gz$L#^nq@egc^IQM{#xaliS3+Dk_&D>VHG1O^2W H_)`MkvH%f) literal 0 HcmV?d00001 diff --git a/src/lib/board.rs b/src/lib/board.rs index bf66ce0..e1943df 100644 --- a/src/lib/board.rs +++ b/src/lib/board.rs @@ -1,18 +1,64 @@ -use crate::gpio::ports::{setup_gpio_port, Port, PortOptions, UsablePort}; +//! Data sheet: https://www.ti.com/lit/ds/spms376e/spms376e.pdf -pub struct UsableBoard; -impl UsableBoard { - pub fn setup_gpio_port(&mut self, port: Port, options: PortOptions) -> UsablePort { - setup_gpio_port(port, options) +use core::arch::asm; + +use crate::gpio::ports::{ + setup_port as setup_gpio_port, GPIOPortOptions, Port as GPIOPort, UsablePort as UsableGPIOPort, +}; +use crate::uart::{ + setup_port as setup_uart_port, Port as UARTPort, PortOptions as UARTPortOptions, + UsablePort as UsableUARTPort, +}; + +/// The board +/// +/// Houses memory addresses of registers +#[derive(Clone, Copy)] +pub struct Board; + +impl Board { + /// Page 231 of data sheet + const fn base(&self) -> u32 { + 0x400F_E000 } - // TODO: have a no_op function here if so desired + /// The memory address of the GPIO Run mode clock gating control (RCGCGPIO) register for this port + /// + /// Page 340 of data sheet + pub(crate) const fn gpio_run_mode_clock_gate_control(&self) -> *mut u32 { + const OFFSET: u32 = 0x608; + (self.base() + OFFSET) as *mut u32 + } - // 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 + pub(crate) const fn run_mode_clock_gate_control_1(&self) -> *mut u32 { + const OFFSET: u32 = 0x104; + (self.base() + OFFSET) as *mut u32 + } +} + +/// A setup version of the board that GPIO and UART ports (TODO: say more features when I make those) can be set up on +pub struct UsableBoard { + board: Board, +} + +impl UsableBoard { + fn no_op(&self) { + unsafe { + asm!("nop"); + } + } +} + +impl UsableBoard { + pub fn setup_gpio_port(&mut self, port: GPIOPort, options: GPIOPortOptions) -> UsableGPIOPort { + setup_gpio_port(self.board, port, options) + } + + pub fn setup_uart_port(&mut self, port: UARTPort, options: UARTPortOptions) -> UsableUARTPort { + setup_uart_port(self.board, port, options, &|| self.no_op()) + } } pub fn setup_board() -> UsableBoard { - UsableBoard + UsableBoard { board: Board } } diff --git a/src/lib/gpio/pins.rs b/src/lib/gpio/pins.rs index e4e266f..c7ea1e1 100644 --- a/src/lib/gpio/pins.rs +++ b/src/lib/gpio/pins.rs @@ -1,17 +1,11 @@ -use crate::{memory, H, L}; +use crate::{ + memory, + utils::{pins_to_bits, reverse_array}, + 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, @@ -23,11 +17,6 @@ pub enum Pin { Six = 6, Seven = 7, } - -fn pins_to_bits(pins: &[Pin; N]) -> [u32; N] { - pins.map(|pin| pin as u32) -} - pub enum Function { Analog, Digital, @@ -58,22 +47,21 @@ impl ReadablePins { } pub fn read_all(&self) -> [bool; N] { - unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)) } + unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32)) } } } #[derive(Clone, Copy)] pub struct ReadablePin { data_address: *mut u32, - bit: Pin, + pin: Pin, } impl ReadablePin { pub fn read(&self) -> bool { let current = unsafe { memory::read(self.data_address) }; - current & (1 << self.bit as u32) != 0 + current & (1 << self.pin as u32) != 0 } } - pub struct WritablePinOptions { pub function: Function, } @@ -87,13 +75,13 @@ impl WritablePins { } pub fn read_all(&self) -> [bool; N] { - unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)) } + unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32)) } } pub fn write_all(&mut self, values: [bool; N]) { unsafe { memory::write_bits( self.data_address, - &self.pins.map(|pin| pin.bit as u32), + &self.pins.map(|pin| pin.pin as u32), values, ) } @@ -104,17 +92,17 @@ impl WritablePins { pub fn clear_all(&mut self) { unsafe { - memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32)); } } pub fn set_all(&mut self) { unsafe { - memory::set_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + memory::set_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32)); } } pub fn toggle_all(&mut self) { unsafe { - memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.pin as u32)); } } } @@ -122,26 +110,26 @@ impl WritablePins { #[derive(Clone, Copy)] pub struct WritablePin { data_address: *mut u32, - bit: Pin, + pin: Pin, } impl WritablePin { pub fn read(&self) -> bool { let current = unsafe { memory::read(self.data_address) }; - current & (1 << self.bit as u32) != 0 + current & (1 << self.pin as u32) != 0 } pub fn clear(&mut self) { unsafe { - memory::clear_bits(self.data_address, &[self.bit as u32]); + memory::clear_bits(self.data_address, &[self.pin as u32]); } } pub fn set(&mut self) { unsafe { - memory::set_bits(self.data_address, &[self.bit as u32]); + memory::set_bits(self.data_address, &[self.pin as u32]); } } pub fn toggle(&mut self) { unsafe { - memory::toggle_bits(self.data_address, &[self.bit as u32]); + memory::toggle_bits(self.data_address, &[self.pin as u32]); } } } @@ -149,6 +137,8 @@ impl WritablePin { /// Page 684 of the data sheet for how the lock mechanism works const UNLOCK: u32 = 0x4C4F434B; +/// TODO: read page 656 (10.3 Initialization and Configuration) +/// TODO: read page 657 (Table 10-3 GPIO Pad Configuration Examples) fn setup_pins( port: Port, pins: [Pin; N], @@ -159,18 +149,6 @@ fn setup_pins( // Unlock the pins unsafe { memory::write(port.lock(), UNLOCK); - - memory::set_bits(port.commit(), &pins_to_bits(&pins)); - } - - // Disable analog when it's not selected (and enable analog if it is) - match function { - Function::Analog => unsafe { - memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins)); - }, - _ => unsafe { - memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins)); - }, } // Set to output pins if output (otherwise set to input) @@ -184,27 +162,14 @@ fn setup_pins( } } - 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]; - - let min = (pin as u32) * 4; - let max = min + 3; - let range = min..=max; - - for (i, memory_bit) in range.enumerate() { - memory_bits[i] = memory_bit; - } - + // Disable alternate function when it's not used (and enable it when it is) + if let Function::Analog | Function::Digital = function { unsafe { - memory::write_bits(port.port_control(), &memory_bits, function_values); + memory::clear_bits(port.alternate_function_select(), &pins_to_bits(&pins)); + } + } else { + unsafe { + memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins)); } } @@ -226,16 +191,9 @@ fn setup_pins( } } - // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states - - // 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_to_bits(&pins)); - }, - _ => unsafe { - memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins)); - }, + // TODO / WIP: commit here?! + unsafe { + memory::set_bits(port.commit(), &pins_to_bits(&pins)); } // Enable digital function when it's needed (and disable it when it's not) @@ -246,7 +204,53 @@ fn setup_pins( Function::Analog => unsafe { memory::clear_bits(port.digital_enable(), &pins_to_bits(&pins)); }, - _ => todo!(), + _ => todo!(), // and rewrite to if let when solved + } + + // Enable analog when it's needed (and disable it when it's not) + if let Function::Analog = function { + unsafe { + memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins)); + } + } else { + unsafe { + memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins)); + } + } + + // Table 10-2 on page 650-651 of data sheet + let digital_function = match function { + Function::Analog => None, + Function::Digital => Some([L, L, L, L]), + Function::CAN => Some([H, L, L, L]), + Function::I2C => Some([L, L, H, H]), + Function::PWM => Some([L, H, L, H]), + Function::UART => Some([L, L, L, H]), + }; + if let Some(array) = digital_function { + let port_control_values = reverse_array(array); + + for pin in pins { + let mut memory_bits = [0; 4]; + + let min = (pin as u32) * 4; + let max = min + 3; + let range = min..=max; + + for (i, memory_bit) in range.enumerate() { + memory_bits[i] = memory_bit; + } + + unsafe { + memory::write_bits(port.port_control(), &memory_bits, port_control_values); + } + } + } + // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states + + // TODO / WIP: Re-lock the pins?! + unsafe { + memory::write(port.lock(), 0); } } @@ -258,7 +262,7 @@ pub fn setup_readable_pins( 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 }); + let pins: [ReadablePin; N] = pins.map(|pin| ReadablePin { data_address, pin }); ReadablePins { data_address, pins } } @@ -270,9 +274,6 @@ pub fn setup_writable_pins( 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, - }); + let pins: [WritablePin; N] = pins.map(|pin| WritablePin { data_address, pin }); WritablePins { data_address, pins } } diff --git a/src/lib/gpio/ports.rs b/src/lib/gpio/ports.rs index 2c954ca..4339090 100644 --- a/src/lib/gpio/ports.rs +++ b/src/lib/gpio/ports.rs @@ -1,5 +1,5 @@ use crate::{ - memory, registers, Pin, ReadablePinOptions, ReadablePins, WritablePinOptions, WritablePins, + memory, Board, Pin, ReadablePinOptions, ReadablePins, WritablePinOptions, WritablePins, }; use super::pins::{setup_readable_pins, setup_writable_pins}; @@ -14,13 +14,13 @@ pub enum Port { F, } -pub struct PortOptions; +pub struct GPIOPortOptions; impl Port { /// The starting point of memory addresses corresponding to this GPIO register /// /// Modeled after page 660 of data sheet (GPIO Register Map) - fn base(&self) -> u32 { + const fn base(&self) -> u32 { match self { Port::A => 0x4000_4000, Port::B => 0x4000_5000, @@ -34,7 +34,7 @@ impl Port { /// The memory address of the alternate function select (AFSEL) register for this port /// /// Page 671 of data sheet - pub(super) fn alternate_function_select(&self) -> *mut u32 { + pub(super) const fn alternate_function_select(&self) -> *mut u32 { const OFFSET: u32 = 0x420; (self.base() + OFFSET) as *mut u32 } @@ -42,7 +42,7 @@ impl Port { /// The memory address of the analog mode select (AMSEL) register for this port /// /// Page 687 of data sheet - pub(super) fn analog_mode_select(&self) -> *mut u32 { + pub(super) const fn analog_mode_select(&self) -> *mut u32 { const OFFSET: u32 = 0x52C; (self.base() + OFFSET) as *mut u32 } @@ -50,7 +50,7 @@ impl Port { /// The memory address of the commit (CR) register for this port /// /// Page 685 of data sheet - pub(super) fn commit(&self) -> *mut u32 { + pub(super) const fn commit(&self) -> *mut u32 { const OFFSET: u32 = 0x524; (self.base() + OFFSET) as *mut u32 } @@ -76,7 +76,7 @@ impl Port { /// The memory address of the digital enable (DEN) register for this port /// /// Page 682 of data sheet - pub(super) fn digital_enable(&self) -> *mut u32 { + pub(super) const fn digital_enable(&self) -> *mut u32 { const OFFSET: u32 = 0x51C; (self.base() + OFFSET) as *mut u32 } @@ -84,7 +84,7 @@ impl Port { /// The memory address of the direction (DIR) register for this port /// /// Page 663 of data sheet - pub(super) fn direction(&self) -> *mut u32 { + pub(super) const fn direction(&self) -> *mut u32 { const OFFSET: u32 = 0x400; (self.base() + OFFSET) as *mut u32 } @@ -92,7 +92,7 @@ impl Port { /// The memory address of the lock (LOCK) register /// /// Page 684 of data sheet - pub(super) fn lock(&self) -> *mut u32 { + pub(super) const fn lock(&self) -> *mut u32 { const OFFSET: u32 = 0x520; (self.base() + OFFSET) as *mut u32 } @@ -100,21 +100,21 @@ impl Port { /// The memory address of the port control (PCTL) register for this port /// /// Page 688 of data sheet - pub(super) fn port_control(&self) -> *mut u32 { + pub(super) const fn port_control(&self) -> *mut u32 { const OFFSET: u32 = 0x52C; (self.base() + OFFSET) as *mut u32 } /// The memory address of the pull-down resistor select (PDR) register for this port /// Page 679 of data sheet - pub(super) fn pull_down_select(&self) -> *mut u32 { + pub(super) const fn pull_down_select(&self) -> *mut u32 { const OFFSET: u32 = 0x514; (self.base() + OFFSET) as *mut u32 } /// The memory address of the pull-up resistor select (PUR) register for this port /// Page 677 of data sheet - pub(super) fn pull_up_select(&self) -> *mut u32 { + pub(super) const fn pull_up_select(&self) -> *mut u32 { const OFFSET: u32 = 0x510; (self.base() + OFFSET) as *mut u32 } @@ -125,8 +125,8 @@ impl Port { } impl Port { - /// The corresponding bit for this port in system's run-mode clock gate control (RCGC) register - fn run_mode_clock_gate_control(&self) -> u32 { + /// The corresponding bit for this port in the system's GPIO Run mode clock gating control (RCGCGPIO) register + const fn run_mode_clock_gate_control(&self) -> u32 { match self { Port::A => 0, Port::B => 1, @@ -160,11 +160,12 @@ impl UsablePort { } } -pub fn setup_gpio_port(port: Port, _options: PortOptions) -> UsablePort { +// TODO: remove unused port setup options +pub fn setup_port(board: Board, port: Port, _options: GPIOPortOptions) -> UsablePort { unsafe { memory::set_bits( - registers::system::RCGCGPIO, - &[port.run_mode_clock_gate_control() as u32], + board.gpio_run_mode_clock_gate_control(), + &[port.run_mode_clock_gate_control()], ); } diff --git a/src/lib/memory.rs b/src/lib/memory.rs index 530fb8e..ee69179 100644 --- a/src/lib/memory.rs +++ b/src/lib/memory.rs @@ -2,9 +2,7 @@ use core::ptr; -use crate::L; - -pub unsafe fn read(address: *mut u32) -> u32 { +pub unsafe fn read(address: *const u32) -> u32 { ptr::read_volatile(address) } pub unsafe fn write(address: *mut u32, new: u32) { @@ -15,29 +13,20 @@ pub unsafe fn update u32>(address: *mut u32, updater: Update write(address, updater(read(address))); } -pub unsafe fn read_bits(address: *mut u32, bits: &[u32; N]) -> [bool; N] { +pub unsafe fn read_bits(address: *const u32, bits: &[u32; N]) -> [bool; N] { let current = read(address); - let mut result = [L; N]; - // TODO: look up accumulate or reduce or something - for (i, bit) in bits.iter().enumerate() { - result[i] = (current & (1 << bit)) != 0; - } - - result + bits.map(|bit| current & (1 << bit) != 0) } pub unsafe fn write_bits(address: *mut u32, bits: &[u32; N], values: [bool; N]) { update(address, |current| { - let mut new = current; - // TODO: look up accumulate or reduce or something - for (bit, set) in bits.iter().zip(values) { + bits.iter().zip(values).fold(current, |result, (bit, set)| { if set { - new |= 1 << bit; + result | (1 << bit) } else { - new &= !(1 << bit); + result & !(1 << bit) } - } - new + }) }) } @@ -51,37 +40,17 @@ pub unsafe fn update_bits [bool; N], const N: usize>( pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) { update(address, |current| { - let mut new = current; - - // TODO: look up accumulate or reduce or something - for bit in bits { - new |= 1 << bit; - } - - new + bits.iter().fold(current, |result, bit| result | (1 << bit)) }) } pub unsafe fn clear_bits(address: *mut u32, bits: &[u32]) { update(address, |current| { - let mut new = current; - - // TODO: look up accumulate or reduce or something - for bit in bits { - new &= !(1 << bit); - } - - new + bits.iter() + .fold(current, |result, bit| result & !(1 << bit)) }) } pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) { update(address, |current| { - let mut new = current; - - // TODO: look up accumulate or reduce or something - for bit in bits { - new ^= 1 << bit; - } - - new + bits.iter().fold(current, |result, bit| result ^ (1 << bit)) }) } diff --git a/src/lib/mod.rs b/src/lib/mod.rs index b34f09c..75a54f8 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -3,7 +3,8 @@ mod board; mod gpio; mod memory; -mod registers; +mod uart; +mod utils; pub use board::*; pub use gpio::pins::*; diff --git a/src/lib/registers.rs b/src/lib/registers.rs deleted file mode 100644 index 4a56908..0000000 --- a/src/lib/registers.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Memory addresses of registers -//! Data sheet: https://www.ti.com/lit/ds/spms376e/spms376e.pdf - -// TODO: check page 92-94 for more features ("Memory Map" table)! - -// TODO: check page 1230 onward for PWM - -/// Page 231 of data sheet -pub mod system { - const BASE: u32 = 0x400F_E000; - - // TODO: page 340 - pub const RCGCGPIO: *mut u32 = (BASE + 0x608) as *mut u32; -} - -// TODO: delete this file diff --git a/src/lib/uart.rs b/src/lib/uart.rs new file mode 100644 index 0000000..58cb866 --- /dev/null +++ b/src/lib/uart.rs @@ -0,0 +1,183 @@ +use crate::{memory, Board}; + +#[derive(Clone, Copy)] +pub enum Port { + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, +} +pub struct PortOptions { + pub baud_rate: u32, // TODO: right type? +} + +impl Port { + /// The starting point of memory addresses corresponding to this GPIO register + /// + /// Modeled after page 904 of data sheet (UART Register Map) + const fn base(&self) -> u32 { + match self { + Port::Zero => 0x4000_C000, + Port::One => 0x4000_D000, + Port::Two => 0x4000_E000, + Port::Three => 0x4000_F000, + Port::Four => 0x4001_0000, + Port::Five => 0x4001_1000, + Port::Six => 0x4001_2000, + Port::Seven => 0x4001_3000, + } + } + + /// The memory address of the control (CTL) register for this port + /// + /// Page 918 of data sheet + pub(super) const fn control(&self) -> *mut u32 { + const OFFSET: u32 = 0x030; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the data (DR) register for this port + /// + /// Page 906 of data sheet + pub(super) const fn data(&self) -> *mut u32 { + const OFFSET: u32 = 0x000; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the flag (FR) register for this port + /// + /// Page 911 of data sheet + pub(super) const fn flag(&self) -> *mut u32 { + const OFFSET: u32 = 0x018; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the TODO + /// + /// Page TODO of data sheet + pub(super) const fn fractional_baud_rate_divisor(&self) -> *mut u32 { + const OFFSET: u32 = 0x018; // TODO + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the TODO + /// + /// Page TODO of data sheet + pub(super) const fn integer_baud_rate_divisor(&self) -> *mut u32 { + const OFFSET: u32 = 0x018; // TODO + (self.base() + OFFSET) as *mut u32 + } +} + +impl Port { + /// The enable (EN) bit in the control register + const fn enable_bit(&self) -> u32 { + 0 + } + + /// 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 { + 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(), + _ => 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 { + match self { + Port::Zero => 0, + Port::One => 1, + Port::Two => 2, + _ => todo!(), + } + } +} + +pub struct UsablePort { + port: Port, +} + +impl UsablePort { + pub fn do_something() { + todo!(); + } +} + +pub fn setup_port(board: Board, port: Port, options: PortOptions, no_op: &dyn Fn()) -> UsablePort { + // Activate the associated peripheral + unsafe { + memory::set_bits( + board.run_mode_clock_gate_control_1(), + &[port.run_mode_clock_gate_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(); + } + + // Disable this UART port while setting it up + unsafe { + memory::clear_bits(port.control(), &[port.enable_bit()]); + } + + // Page 896: baud rate generation + + // 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 + // 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; + + + // 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) + let clock_divider = 16; + + let baud_rate_divisor = (system_clock as f32) / ((clock_divider * options.baud_rate) as f32); + + let baud_rate_divisor_integer = baud_rate_divisor as u32; + let baud_rate_divisor_fraction = baud_rate_divisor - (baud_rate_divisor_integer as f32); + + // TODO: + // if baud_rate_divisor_integer.to_bits() > 22 { + // panic!(); + // } + + let baud_rate_divisor_fraction = ((baud_rate_divisor_fraction * 64.0) + 0.5) as u8; + + + // 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); + } + + // TODO: CTL LCHR register + todo!(); + + // Enable this UART port + unsafe { + memory::set_bits(port.control(), &[port.enable_bit()]); + } + + UsablePort { port } +} diff --git a/src/lib/utils.rs b/src/lib/utils.rs new file mode 100644 index 0000000..32398b2 --- /dev/null +++ b/src/lib/utils.rs @@ -0,0 +1,15 @@ +use crate::Pin; + +pub fn pins_to_bits(pins: &[Pin; N]) -> [u32; N] { + pins.map(|pin| pin as u32) +} + +pub 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 +} diff --git a/src/main.rs b/src/main.rs index d55e9a5..8cead1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,8 @@ static HEAP: BumpPointerAlloc = BumpPointerAlloc { end: 0x2000_0200, }; -#[macro_use] +// TODO: remove or fix +// #[macro_use] extern crate alloc; use alloc::string::String; @@ -63,39 +64,31 @@ use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch use cortex_m_rt::entry; use driver_and_task_library::{ - setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, UsableBoard, - WritablePinOptions, H, L, Pull, + setup_board, Function, GPIOPortOptions, Pin, Port, Pull, ReadablePinOptions, + WritablePinOptions, H, L, }; const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32; -const SYSCTL_RCGC2_R: *mut u32 = 0x400FE108 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; -// 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 -const SYSCTL_RCGC2_GPIOA: u32 = 0x00000001; /// UART Enable const UART_CTL_UARTEN: u32 = 0x00000001; /// 8 bit word length @@ -109,18 +102,21 @@ const UART_FR_RXFE: u32 = 0x00000010; /// Pins 0 and 1 const PINS_0_AND_1: u32 = 0b0000_0011; -fn uart0_init(board: &mut UsableBoard) { +fn uart0_init() { unsafe { // activate UART0 ptr::write_volatile( SYSCTL_RCGC1_R, ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0, ); + // write_color(MAGENTA); - // activate port A - // ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA); - // ^ commented in favor of v - board.setup_gpio_port(Port::A, PortOptions); + // 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( @@ -128,7 +124,6 @@ fn uart0_init(board: &mut UsableBoard) { ptr::read_volatile(UART0_CTL_R) & !UART_CTL_UARTEN, ); - // ignore: // IBRD = int(50,000,000 / (16 * 115,200)) = int(27.1267) // 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); @@ -140,8 +135,7 @@ fn uart0_init(board: &mut UsableBoard) { // 8 bit word length (no parity bits, one stop bit, FIFOs) // ptr::write_volatile(UART0_LCRH_R, UART_LCRH_WLEN_8|UART_LCRH_FEN); - // 8 bit word length (no parity bits, one stop bit, no 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( @@ -162,7 +156,7 @@ fn uart0_init(board: &mut UsableBoard) { } } -fn uart0_out_char(c: u8) { +fn uart0_out_char_blocking(c: u8) { loop { let fr = unsafe { ptr::read_volatile(UART0_FR_R) }; @@ -176,12 +170,24 @@ fn uart0_out_char(c: u8) { } } -fn uart0_out_string(s: &str) { +fn uart0_out_string_blocking(s: &str) { for c in s.bytes() { - uart0_out_char(c); + 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]; @@ -195,25 +201,8 @@ const MAGENTA: [bool; 3] = [H, L, H]; #[entry] fn main() -> ! { 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 mut port_a = board.setup_gpio_port(Port::A, GPIOPortOptions); + let mut port_f = board.setup_gpio_port(Port::F, GPIOPortOptions); let switches = port_f.setup_readable_pins( [Pin::Zero, Pin::Four], @@ -222,8 +211,6 @@ fn main() -> ! { pull: Pull::Up, }, ); - let [_sw1, _sw2] = switches.pins(); - let mut rgb_led = port_f.setup_writable_pins( [Pin::One, Pin::Three, Pin::Two], WritablePinOptions { @@ -231,18 +218,33 @@ fn main() -> ! { }, ); + // TODO: finish this + uart0_init(); + // WIP: page 682 + port_a.setup_writable_pins( + [Pin::One], + WritablePinOptions { + function: Function::UART, + }, + ); + 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 = 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); + uart0_out_string_blocking(&s); loop { - uart0_out_string("Hi the program is still running down here!\r\n"); + // 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,10 +254,15 @@ fn main() -> ! { // uart0_out_string(&format!("The switches read {:?}", switches.read_all())); - for _ in 0..1000000 { - unsafe { - asm!("nop"); - } - } + // 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"); } }