beginning of refactoring
This commit is contained in:
2
memory.x
2
memory.x
@@ -1,8 +1,6 @@
|
|||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
/* NOTE 1 K = 1 KiBi = 1024 bytes */
|
/* 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
|
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||||
RAM : ORIGIN = 0x20000000, LENGTH = 32K
|
RAM : ORIGIN = 0x20000000, LENGTH = 32K
|
||||||
}
|
}
|
||||||
|
16
src/lib/board.rs
Normal file
16
src/lib/board.rs
Normal file
@@ -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
|
||||||
|
}
|
2
src/lib/gpio/mod.rs
Normal file
2
src/lib/gpio/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod pins;
|
||||||
|
pub mod ports;
|
304
src/lib/gpio/pins.rs
Normal file
304
src/lib/gpio/pins.rs
Normal file
@@ -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<bool>,
|
||||||
|
}
|
||||||
|
pub struct ReadablePins<const N: usize> {
|
||||||
|
data_address: *mut u32,
|
||||||
|
pins: [ReadablePin; N],
|
||||||
|
}
|
||||||
|
impl<const N: usize> ReadablePins<N> {
|
||||||
|
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<const N: usize> {
|
||||||
|
data_address: *mut u32,
|
||||||
|
pins: [WritablePin; N],
|
||||||
|
}
|
||||||
|
impl<const N: usize> WritablePins<N> {
|
||||||
|
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<Updater: Fn([bool; N]) -> [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<const N: usize>(
|
||||||
|
port: Port,
|
||||||
|
pins: [Pin; N],
|
||||||
|
options: ReadablePinOptions,
|
||||||
|
) -> ReadablePins<N> {
|
||||||
|
// 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<const N: usize>(
|
||||||
|
port: Port,
|
||||||
|
pins: [Pin; N],
|
||||||
|
options: WritablePinOptions,
|
||||||
|
) -> WritablePins<N> {
|
||||||
|
// 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 }
|
||||||
|
}
|
162
src/lib/gpio/ports.rs
Normal file
162
src/lib/gpio/ports.rs
Normal file
@@ -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<const N: usize>(
|
||||||
|
&self,
|
||||||
|
pins: [Pin; N],
|
||||||
|
options: ReadablePinOptions,
|
||||||
|
) -> ReadablePins<N> {
|
||||||
|
setup_readable_pins(self.port, pins, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_writable_pins<const N: usize>(
|
||||||
|
&self,
|
||||||
|
pins: [Pin; N],
|
||||||
|
options: WritablePinOptions,
|
||||||
|
) -> WritablePins<N> {
|
||||||
|
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 }
|
||||||
|
}
|
@@ -32,7 +32,7 @@ pub unsafe fn write_bits<const N: usize>(address: *mut u32, bits: &[u32; N], val
|
|||||||
// TODO: look up accumulate or reduce or something
|
// TODO: look up accumulate or reduce or something
|
||||||
for (bit, set) in bits.iter().zip(values) {
|
for (bit, set) in bits.iter().zip(values) {
|
||||||
if set {
|
if set {
|
||||||
new |= (1 << bit);
|
new |= 1 << bit;
|
||||||
} else {
|
} else {
|
||||||
new &= !(1 << bit);
|
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
|
// TODO: look up accumulate or reduce or something
|
||||||
for bit in bits {
|
for bit in bits {
|
||||||
new |= (1 << bit);
|
new |= 1 << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
new
|
new
|
||||||
@@ -79,7 +79,7 @@ pub unsafe fn toggle_bits(address: *mut u32, bits: &[u32]) {
|
|||||||
|
|
||||||
// TODO: look up accumulate or reduce or something
|
// TODO: look up accumulate or reduce or something
|
||||||
for bit in bits {
|
for bit in bits {
|
||||||
new ^= (1 << bit);
|
new ^= 1 << bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
new
|
new
|
||||||
|
458
src/lib/mod.rs
458
src/lib/mod.rs
@@ -1,459 +1,13 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
mod board;
|
||||||
|
mod gpio;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod registers;
|
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 H: bool = true;
|
||||||
pub const L: bool = false;
|
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<const N: usize>(
|
|
||||||
&self,
|
|
||||||
bits: &[Bit; N],
|
|
||||||
options: ReadablePinSetup,
|
|
||||||
) -> ReadablePins<N> {
|
|
||||||
// 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<const N: usize>(
|
|
||||||
&self,
|
|
||||||
bits: &[Bit; N],
|
|
||||||
options: WritablePinSetup,
|
|
||||||
) -> WritablePins<N> {
|
|
||||||
// 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<bool>,
|
|
||||||
}
|
|
||||||
pub struct ReadablePins<const N: usize> {
|
|
||||||
data_address: *mut u32,
|
|
||||||
pins: [ReadablePin; N],
|
|
||||||
}
|
|
||||||
impl<const N: usize> ReadablePins<N> {
|
|
||||||
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<const N: usize> {
|
|
||||||
data_address: *mut u32,
|
|
||||||
pins: [WritablePin; N],
|
|
||||||
}
|
|
||||||
impl<const N: usize> WritablePins<N> {
|
|
||||||
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<Updater: Fn([bool; N]) -> [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
|
|
||||||
}
|
|
||||||
|
@@ -5,98 +5,6 @@
|
|||||||
|
|
||||||
// TODO: check page 1230 onward for PWM
|
// 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
|
/// Page 231 of data sheet
|
||||||
pub mod system {
|
pub mod system {
|
||||||
const BASE: u32 = 0x400F_E000;
|
const BASE: u32 = 0x400F_E000;
|
||||||
|
19
src/main.rs
19
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 cortex_m_rt::entry;
|
||||||
use test_cortex_m4_rust::{
|
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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let board = setup_board();
|
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 {
|
let switches = port_f.setup_readable_pins(
|
||||||
function: Function::Digital,
|
[Pin::Zero, Pin::Four],
|
||||||
pull_up: Some(true),
|
ReadablePinOptions {
|
||||||
});
|
function: Function::Digital,
|
||||||
|
pull_up: Some(true),
|
||||||
|
},
|
||||||
|
);
|
||||||
let [sw1, sw2] = switches.pins();
|
let [sw1, sw2] = switches.pins();
|
||||||
|
|
||||||
let mut rgb_led = port_f.setup_writable_pins(
|
let mut rgb_led = port_f.setup_writable_pins(
|
||||||
&[Bit::One, Bit::Three, Bit::Two],
|
[Pin::One, Pin::Three, Pin::Two],
|
||||||
WritablePinSetup {
|
WritablePinOptions {
|
||||||
function: Function::Digital,
|
function: Function::Digital,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user