diff --git a/memory.x b/memory.x index b259ddb..e6cf238 100644 --- a/memory.x +++ b/memory.x @@ -1,8 +1,6 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - /* TODO Adjust these memory regions to match your device memory layout */ - /* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */ FLASH : ORIGIN = 0x00000000, LENGTH = 256K RAM : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/src/lib/board.rs b/src/lib/board.rs new file mode 100644 index 0000000..41f699c --- /dev/null +++ b/src/lib/board.rs @@ -0,0 +1,16 @@ +use crate::gpio::ports::{Port, PortOptions, UsablePort, setup_gpio_port}; + +pub struct UsableBoard; +impl UsableBoard { + pub fn setup_gpio_port(&self, port: Port, options: PortOptions) -> UsablePort { + setup_gpio_port(port, options) + } + + // 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 fn setup_board() -> UsableBoard { + UsableBoard +} diff --git a/src/lib/gpio/mod.rs b/src/lib/gpio/mod.rs new file mode 100644 index 0000000..9874084 --- /dev/null +++ b/src/lib/gpio/mod.rs @@ -0,0 +1,2 @@ +pub mod pins; +pub mod ports; diff --git a/src/lib/gpio/pins.rs b/src/lib/gpio/pins.rs new file mode 100644 index 0000000..688becb --- /dev/null +++ b/src/lib/gpio/pins.rs @@ -0,0 +1,304 @@ +use crate::{memory, L}; + +use super::ports::Port; + +#[derive(Clone, Copy)] +pub enum Pin { + Zero = 0, + One = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, +} + +pub enum Function { + Analog, + Digital, + CAN, + I2C, + PWM, + UART, +} + +/// Page 1351 of data sheet +pub struct ReadablePinOptions { + pub function: Function, + pub pull_up: Option, +} +pub struct ReadablePins { + data_address: *mut u32, + pins: [ReadablePin; N], +} +impl ReadablePins { + pub fn pins(&self) -> [ReadablePin; N] { + self.pins + } + + pub fn read_all(&self) -> [bool; N] { + unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)) } + } +} +#[derive(Clone, Copy)] +pub struct ReadablePin { + data_address: *mut u32, + bit: Pin, +} +impl ReadablePin { + pub fn read(&self) -> bool { + let current = unsafe { memory::read(self.data_address) }; + current & (1 << self.bit as u32) != 0 + } +} + +pub struct WritablePinOptions { + pub function: Function, +} +pub struct WritablePins { + data_address: *mut u32, + pins: [WritablePin; N], +} +impl WritablePins { + pub fn pins(&self) -> [WritablePin; N] { + self.pins + } + + pub fn read_all(&self) -> [bool; N] { + unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit 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), + values, + ) + } + } + pub fn update_all [bool; N]>(&mut self, updater: Updater) { + self.write_all(updater(self.read_all())); + } + + pub fn clear_all(&mut self) { + unsafe { + memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + } + } + pub fn set_all(&mut self) { + unsafe { + memory::set_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + } + } + pub fn toggle_all(&mut self) { + unsafe { + memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); + } + } +} + +#[derive(Clone, Copy)] +pub struct WritablePin { + data_address: *mut u32, + bit: Pin, +} +impl WritablePin { + pub fn read(&self) -> bool { + let current = unsafe { memory::read(self.data_address) }; + current & (1 << self.bit as u32) != 0 + } + pub fn clear(&mut self) { + unsafe { + memory::clear_bits(self.data_address, &[self.bit as u32]); + } + } + pub fn set(&mut self) { + unsafe { + memory::set_bits(self.data_address, &[self.bit as u32]); + } + } + pub fn toggle(&mut self) { + unsafe { + memory::toggle_bits(self.data_address, &[self.bit as u32]); + } + } +} + +/// 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( + port: Port, + pins: [Pin; N], + options: ReadablePinOptions, +) -> ReadablePins { + // 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::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!(), + }; + unsafe { + memory::write_bits(port.port_control(), &memory_bits, values); + } + } + + // 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(); + + 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)); + } + + 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; + } + + 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); + } + } + + // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states + + // TODO: finish + + match options.function { + Function::Analog | Function::Digital => unsafe { + memory::clear_bits( + port.alternate_function_select(), + &pins.map(|bit| bit as u32), + ); + }, + _ => unsafe { + memory::set_bits( + port.alternate_function_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(); + + let pins: [WritablePin; N] = pins.map(|bit| WritablePin { data_address, bit }); + + WritablePins { data_address, pins } +} diff --git a/src/lib/gpio/ports.rs b/src/lib/gpio/ports.rs new file mode 100644 index 0000000..ae37894 --- /dev/null +++ b/src/lib/gpio/ports.rs @@ -0,0 +1,162 @@ +use crate::{ + memory, Pin, ReadablePinOptions, ReadablePins, registers, WritablePinOptions, WritablePins, +}; + +use super::pins::{setup_readable_pins, setup_writable_pins}; + +#[derive(Clone, Copy)] +pub enum Port { + A, + B, + C, + D, + E, + F, +} + +pub struct PortOptions; + +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 { + match self { + Port::A => 0x4000_4000, + Port::B => 0x4000_5000, + Port::C => 0x4000_6000, + Port::D => 0x4000_7000, + Port::E => 0x4002_4000, + Port::F => 0x4002_5000, + } + } + + /// 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 { + const OFFSET: u32 = 0x420; + (self.base() + OFFSET) as *mut u32 + } + + /// 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 { + const OFFSET: u32 = 0x52C; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the commit (CR) register for this port + /// + /// Page 685 of data sheet + pub(super) fn commit(&self) -> *mut u32 { + const OFFSET: u32 = 0x524; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the data (DATA) register for this port + /// + /// Page 662 of data sheet + pub(super) fn data(&self) -> *mut u32 { + const OFFSET: u32 = 0x3FC; + (self.base() + OFFSET) as *mut u32 + } + + /// 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 { + const OFFSET: u32 = 0x51C; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the direction (DIR) register for this port + /// + /// Page 663 of data sheet + pub(super) fn direction(&self) -> *mut u32 { + const OFFSET: u32 = 0x400; + (self.base() + OFFSET) as *mut u32 + } + + /// The memory address of the lock (LOCK) register + /// + /// Page 684 of data sheet + pub(super) fn lock(&self) -> *mut u32 { + const OFFSET: u32 = 0x520; + (self.base() + OFFSET) as *mut u32 + } + + /// 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 { + 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 { + 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 { + const OFFSET: u32 = 0x510; + (self.base() + OFFSET) as *mut u32 + } + + // TODO: examine page 690 (ADC) for applicability + // Note to self: page 1351 of data sheet for PWM + // Apparently also for ADC! +} + +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 { + match self { + Port::A => 0, + Port::B => 1, + Port::C => 2, + Port::D => 3, + Port::E => 4, + Port::F => 5, + } + } +} + +pub struct UsablePort { + port: Port, +} + +impl UsablePort { + pub fn setup_readable_pins( + &self, + pins: [Pin; N], + options: ReadablePinOptions, + ) -> ReadablePins { + setup_readable_pins(self.port, pins, options) + } + + pub fn setup_writable_pins( + &self, + pins: [Pin; N], + options: WritablePinOptions, + ) -> WritablePins { + setup_writable_pins(self.port, pins, options) + } +} + +pub fn setup_gpio_port(port: Port, options: PortOptions) -> UsablePort { + unsafe { + memory::set_bits( + registers::system::RCGCGPIO, + &[port.run_mode_clock_gate_control() as u32], + ); + } + + UsablePort { port } +} diff --git a/src/lib/memory.rs b/src/lib/memory.rs index 8a9cdf7..530fb8e 100644 --- a/src/lib/memory.rs +++ b/src/lib/memory.rs @@ -32,7 +32,7 @@ pub unsafe fn write_bits(address: *mut u32, bits: &[u32; N], val // TODO: look up accumulate or reduce or something for (bit, set) in bits.iter().zip(values) { if set { - new |= (1 << bit); + new |= 1 << bit; } else { new &= !(1 << bit); } @@ -55,7 +55,7 @@ pub unsafe fn set_bits(address: *mut u32, bits: &[u32]) { // TODO: look up accumulate or reduce or something for bit in bits { - new |= (1 << bit); + new |= 1 << bit; } new @@ -79,7 +79,7 @@ pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) { // TODO: look up accumulate or reduce or something for bit in bits { - new ^= (1 << bit); + new ^= 1 << bit; } new diff --git a/src/lib/mod.rs b/src/lib/mod.rs index 969e2e8..5f51e96 100644 --- a/src/lib/mod.rs +++ b/src/lib/mod.rs @@ -1,459 +1,13 @@ #![no_std] +mod board; +mod gpio; mod memory; mod registers; +pub use board::setup_board; +pub use gpio::pins::{Function, Pin, ReadablePin, ReadablePinOptions, ReadablePins, WritablePin, WritablePinOptions, WritablePins}; +pub use gpio::ports::{Port, PortOptions, UsablePort}; + pub const H: bool = true; pub const L: bool = false; - -pub struct Board; -// TODO: check page 704 for timers -// TODO: impl Drop trait so that tasks all run before the main function ends? - -impl Board { - pub fn setup_gpio_port(&self, port: Port, options: PortSetup) -> PortIO { - let port_io = PortIO { port }; - - unsafe { - memory::set_bits( - registers::system::RCGCGPIO, - &[port_io.run_mode_clock_gate_control() as u32], - ); - } - - port_io - } -} - -// Page 684 of the data sheet for how the lock mechanism works -const UNLOCK: u32 = 0x4C4F434B; - -pub enum Port { - A, - B, - C, - D, - E, - F, -} - -pub struct PortSetup; - -pub struct PortIO { - port: Port, -} - -// TODO: refactor to just be self.base() + offset all the time - no matching -impl PortIO { - /// The memory address of the alternate function select (AFSEL) register for this port - fn alternate_function_select(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::afsel::PORT_A, - Port::F => registers::gpio::afsel::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the analog mode select (AMSEL) register for this port - fn analog_mode_select(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::amsel::PORT_A, - Port::F => registers::gpio::amsel::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the commit (CR register for this port - fn commit(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::cr::PORT_A, - Port::F => registers::gpio::cr::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the digital enable (DEN) register for this port - fn digital_enable(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::den::PORT_A, - Port::F => registers::gpio::den::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the data (DATA) register for this port - fn data(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::data::PORT_A, - Port::F => registers::gpio::data::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the direction (DIR) register for this port - fn direction(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::dir::PORT_A, - Port::F => registers::gpio::dir::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the lock (LOCK) register - fn lock(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::lock::PORT_A, - Port::F => registers::gpio::lock::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the port control (PCTL) register for this port - fn port_control(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::pctl::PORT_A, - Port::F => registers::gpio::pctl::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the pull-down resistor select (PDR) register for this port - fn pull_down_select(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::pdr::PORT_A, - Port::F => registers::gpio::pdr::PORT_F, - _ => todo!(), - } - } - - /// The memory address of the pull-up resistor select (PUR) register for this port - fn pull_up_select(&self) -> *mut u32 { - match self.port { - Port::A => registers::gpio::pur::PORT_A, - Port::F => registers::gpio::pur::PORT_F, - _ => todo!(), - } - } - - // Note to self: page 1351 of data sheet for PWM - // Apparently also for ADC! -} - -impl PortIO { - /// The corresponding bit for this port in system's run-mode clock gate control (RCGC) register - fn run_mode_clock_gate_control(&self) -> Bit { - match self.port { - Port::A => Bit::Zero, - Port::B => Bit::One, - Port::C => Bit::Two, - Port::D => Bit::Three, - Port::E => Bit::Four, - Port::F => Bit::Five, - } - } -} - -impl PortIO { - // TODO: refactor into private setup_pins function - pub fn setup_readable_pins( - &self, - bits: &[Bit; N], - options: ReadablePinSetup, - ) -> ReadablePins { - // Unlock the pins - unsafe { - memory::write(self.lock(), UNLOCK); - - memory::set_bits(self.commit(), &bits.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(self.analog_mode_select(), &bits.map(|bit| bit as u32)); - }, - _ => unsafe { - memory::clear_bits(self.analog_mode_select(), &bits.map(|bit| bit as u32)); - }, - } - - unsafe { - memory::clear_bits(self.direction(), &bits.map(|bit| bit as u32)); - } - - - - for bit in bits { - let mut memory_bits = [0; 4]; - - let min = (*bit as u32) * 4; - let max = min + 3; - 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!(), - }; - unsafe { - memory::write_bits(self.port_control(), &memory_bits, values); - } - } - - // Configure pull-up and pull-down resistors - match options.pull_up { - Some(true) => { - unsafe { - memory::set_bits(self.pull_up_select(), &bits.map(|bit| bit as u32)); - } - }, - Some(false) => { - unsafe { - memory::set_bits(self.pull_down_select(), &bits.map(|bit| bit as u32)); - } - }, - None => { - unsafe { - memory::clear_bits(self.pull_up_select(), &bits.map(|bit| bit as u32)); - } - unsafe { - memory::clear_bits(self.pull_down_select(), &bits.map(|bit| bit as u32)); - } - }, - } - - match options.function { - Function::Digital => unsafe { - memory::set_bits(self.digital_enable(), &bits.map(|bit| bit as u32)); - }, - Function::Analog => unsafe { - memory::clear_bits(self.digital_enable(), &bits.map(|bit| bit as u32)); - }, - _ => todo!(), - } - - let data_address = self.data(); - - let pins: [ReadablePin; N] = bits.map(|bit| ReadablePin { data_address, bit }); - - ReadablePins { data_address, pins } - } - - pub fn setup_writable_pins( - &self, - bits: &[Bit; N], - options: WritablePinSetup, - ) -> WritablePins { - // Unlock the pins - unsafe { - memory::write(self.lock(), UNLOCK); - - memory::set_bits(self.commit(), &bits.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(self.analog_mode_select(), &bits.map(|bit| bit as u32)); - }, - _ => unsafe { - memory::clear_bits(self.analog_mode_select(), &bits.map(|bit| bit as u32)); - }, - } - - unsafe { - memory::set_bits(self.direction(), &bits.map(|bit| bit as u32)); - } - - for bit in bits { - let mut memory_bits = [0; 4]; - - let min = (*bit as u32) * 4; - let max = min + 3; - 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!(), - }; - unsafe { - memory::write_bits(self.port_control(), &memory_bits, values); - } - } - - // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states - - // TODO: finish - - match options.function { - Function::Analog | Function::Digital => { - unsafe { - memory::clear_bits(self.alternate_function_select(), &bits.map(|bit| bit as u32)); - } - }, - _ => { - unsafe { - memory::set_bits(self.alternate_function_select(), &bits.map(|bit| bit as u32)); - } - }, - } - - match options.function { - Function::Digital => unsafe { - memory::set_bits(self.digital_enable(), &bits.map(|bit| bit as u32)); - }, - Function::Analog => unsafe { - memory::clear_bits(self.digital_enable(), &bits.map(|bit| bit as u32)); - }, - _ => todo!(), - } - - let data_address = self.data(); - - let pins: [WritablePin; N] = bits.map(|bit| WritablePin { data_address, bit }); - - WritablePins { data_address, pins } - } -} - -#[derive(Clone, Copy)] -pub enum Bit { - Zero = 0, - One = 1, - Two = 2, - Three = 3, - Four = 4, - Five = 5, - Six = 6, - Seven = 7, -} - -/// Page 1351 of data sheet -pub enum Function { - Analog, - Digital, - CAN, - I2C, - PWM, - UART, -} - -pub struct ReadablePinSetup { - pub function: Function, - pub pull_up: Option, -} -pub struct ReadablePins { - data_address: *mut u32, - pins: [ReadablePin; N], -} -impl ReadablePins { - pub fn pins(&self) -> [ReadablePin; N] { - self.pins - } - - pub fn read_all(&self) -> [bool; N] { - unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)) } - } -} -#[derive(Clone, Copy)] -pub struct ReadablePin { - data_address: *mut u32, - bit: Bit, -} -impl ReadablePin { - pub fn read(&self) -> bool { - let current = unsafe { memory::read(self.data_address) }; - current & (1 << self.bit as u32) != 0 - } -} - -pub struct WritablePinSetup { - pub function: Function, -} -pub struct WritablePins { - data_address: *mut u32, - pins: [WritablePin; N], -} -impl WritablePins { - pub fn pins(&self) -> [WritablePin; N] { - self.pins - } - - pub fn read_all(&self) -> [bool; N] { - unsafe { memory::read_bits(self.data_address, &self.pins.map(|pin| pin.bit 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), - values, - ) - } - } - pub fn update_all [bool; N]>(&mut self, updater: Updater) { - self.write_all(updater(self.read_all())); - } - - pub fn clear_all(&mut self) { - unsafe { - memory::clear_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); - } - } - pub fn set_all(&mut self) { - unsafe { - memory::set_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); - } - } - pub fn toggle_all(&mut self) { - unsafe { - memory::toggle_bits(self.data_address, &self.pins.map(|pin| pin.bit as u32)); - } - } -} - -#[derive(Clone, Copy)] -pub struct WritablePin { - data_address: *mut u32, - bit: Bit, -} -impl WritablePin { - pub fn read(&self) -> bool { - let current = unsafe { memory::read(self.data_address) }; - current & (1 << self.bit as u32) != 0 - } - pub fn clear(&mut self) { - unsafe { - memory::clear_bits(self.data_address, &[self.bit as u32]); - } - } - pub fn set(&mut self) { - unsafe { - memory::set_bits(self.data_address, &[self.bit as u32]); - } - } - pub fn toggle(&mut self) { - unsafe { - memory::toggle_bits(self.data_address, &[self.bit as u32]); - } - } -} - -pub fn setup_board() -> Board { - Board -} diff --git a/src/lib/registers.rs b/src/lib/registers.rs index 0eaa1fe..f26b3cf 100644 --- a/src/lib/registers.rs +++ b/src/lib/registers.rs @@ -5,98 +5,6 @@ // TODO: check page 1230 onward for PWM -/// Modeled after page 660 of data sheet (GPIO Register Map) -pub mod gpio { - mod base { - pub const PORT_A: u32 = 0x4000_4000; - pub const PORT_F: u32 = 0x4002_5000; - } - - /// Page 671 of data sheet - pub mod afsel { - const OFFSET: u32 = 0x420; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 687 of data sheet - pub mod amsel { - const OFFSET: u32 = 0x52C; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 685 of data sheet - pub mod cr { - const OFFSET: u32 = 0x524; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 662 of data sheet - pub mod data { - const OFFSET: u32 = 0x3FC; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 682 of data sheet - pub mod den { - const OFFSET: u32 = 0x51C; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 663 of data sheet - pub mod dir { - const OFFSET: u32 = 0x400; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 684 of data sheet - pub mod lock { - const OFFSET: u32 = 0x520; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 688 of data sheet - pub mod pctl { - const OFFSET: u32 = 0x52C; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 679 of data sheet - pub mod pdr { - const OFFSET: u32 = 0x514; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - /// Page 677 of data sheet - pub mod pur { - const OFFSET: u32 = 0x510; - - pub const PORT_A: *mut u32 = (super::base::PORT_A + OFFSET) as *mut u32; - pub const PORT_F: *mut u32 = (super::base::PORT_F + OFFSET) as *mut u32; - } - - // TODO: examine page 670 for when (if) I do interrupts -} - -// TODO: examine page 690 (ADC) for applicability - /// Page 231 of data sheet pub mod system { const BASE: u32 = 0x400F_E000; diff --git a/src/main.rs b/src/main.rs index 248e8b4..a11c777 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,23 +5,26 @@ use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch use cortex_m_rt::entry; use test_cortex_m4_rust::{ - setup_board, Bit, Function, Port, PortSetup, ReadablePinSetup, WritablePinSetup, H, L, + setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, WritablePinOptions, H, L, }; #[entry] fn main() -> ! { let board = setup_board(); - let port_f = board.setup_gpio_port(Port::F, PortSetup); + let port_f = board.setup_gpio_port(Port::F, PortOptions); - let switches = port_f.setup_readable_pins(&[Bit::Zero, Bit::Four], ReadablePinSetup { - function: Function::Digital, - pull_up: Some(true), - }); + let switches = port_f.setup_readable_pins( + [Pin::Zero, Pin::Four], + ReadablePinOptions { + function: Function::Digital, + pull_up: Some(true), + }, + ); let [sw1, sw2] = switches.pins(); let mut rgb_led = port_f.setup_writable_pins( - &[Bit::One, Bit::Three, Bit::Two], - WritablePinSetup { + [Pin::One, Pin::Three, Pin::Two], + WritablePinOptions { function: Function::Digital, }, );