This commit is contained in:
J / Jacob Babich
2022-04-17 20:08:48 -04:00
parent db033c7ee6
commit d875364deb
4 changed files with 215 additions and 163 deletions

View File

@@ -2,10 +2,12 @@ use crate::gpio::ports::{setup_gpio_port, Port, PortOptions, UsablePort};
pub struct UsableBoard; pub struct UsableBoard;
impl UsableBoard { impl UsableBoard {
pub fn setup_gpio_port(&self, port: Port, options: PortOptions) -> UsablePort { pub fn setup_gpio_port(&mut self, port: Port, options: PortOptions) -> UsablePort {
setup_gpio_port(port, options) setup_gpio_port(port, options)
} }
// TODO: have a no_op function here if so desired
// TODO: check page 704 for timers // TODO: check page 704 for timers
// TODO: impl Drop trait so that tasks all run before the main function ends? // TODO: impl Drop trait so that tasks all run before the main function ends?
// TODO: examine page 670 for when (if) I do interrupts // TODO: examine page 670 for when (if) I do interrupts

View File

@@ -1,7 +1,17 @@
use crate::{memory, L}; use crate::{memory, H, L};
use super::ports::Port; use super::ports::Port;
fn reverse_array<const N: usize, T: Default + Copy>(array: [T; N]) -> [T; N] {
let mut result: [T; N] = [<T>::default(); N];
for (out_index, in_index) in (0..N).rev().enumerate() {
result[out_index] = array[in_index];
}
result
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Pin { pub enum Pin {
Zero = 0, Zero = 0,
@@ -14,6 +24,10 @@ pub enum Pin {
Seven = 7, Seven = 7,
} }
fn pins_to_bits<const N: usize>(pins: &[Pin; N]) -> [u32; N] {
pins.map(|pin| pin as u32)
}
pub enum Function { pub enum Function {
Analog, Analog,
Digital, Digital,
@@ -23,10 +37,16 @@ pub enum Function {
UART, UART,
} }
pub enum Pull {
Down,
Up,
Neither,
}
/// Page 1351 of data sheet /// Page 1351 of data sheet
pub struct ReadablePinOptions { pub struct ReadablePinOptions {
pub function: Function, pub function: Function,
pub pull_up: Option<bool>, pub pull: Pull,
} }
pub struct ReadablePins<const N: usize> { pub struct ReadablePins<const N: usize> {
data_address: *mut u32, data_address: *mut u32,
@@ -128,121 +148,49 @@ impl WritablePin {
/// Page 684 of the data sheet for how the lock mechanism works /// Page 684 of the data sheet for how the lock mechanism works
const UNLOCK: u32 = 0x4C4F434B; const UNLOCK: u32 = 0x4C4F434B;
fn setup_pins() { fn setup_pins<const N: usize>(
todo!();
}
pub fn setup_readable_pins<const N: usize>(
port: Port, port: Port,
pins: [Pin; N], pins: [Pin; N],
options: ReadablePinOptions, writable: bool,
) -> ReadablePins<N> { function: Function,
pull: Pull,
) {
// Unlock the pins // Unlock the pins
unsafe { unsafe {
memory::write(port.lock(), UNLOCK); memory::write(port.lock(), UNLOCK);
memory::set_bits(port.commit(), &pins.map(|bit| bit as u32)); memory::set_bits(port.commit(), &pins_to_bits(&pins));
} }
// Disable analog when it's not selected (and enable analog if it is) // Disable analog when it's not selected (and enable analog if it is)
match options.function { match function {
Function::Analog => unsafe { Function::Analog => unsafe {
memory::set_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); memory::set_bits(port.analog_mode_select(), &pins_to_bits(&pins));
}, },
_ => unsafe { _ => unsafe {
memory::clear_bits(port.analog_mode_select(), &pins.map(|bit| bit as u32)); memory::clear_bits(port.analog_mode_select(), &pins_to_bits(&pins));
}, },
} }
unsafe { // Set to output pins if output (otherwise set to input)
memory::clear_bits(port.direction(), &pins.map(|bit| bit as u32)); if writable {
}
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 { unsafe {
memory::write_bits(port.port_control(), &memory_bits, values); memory::set_bits(port.direction(), &pins_to_bits(&pins));
}
} else {
unsafe {
memory::clear_bits(port.direction(), &pins_to_bits(&pins));
} }
} }
// Configure pull-up and pull-down resistors let function_values = reverse_array(match function {
match options.pull_up { Function::Analog => todo!(),
Some(true) => unsafe { Function::Digital => [L, L, L, L],
memory::set_bits(port.pull_up_select(), &pins.map(|bit| bit as u32)); Function::CAN => [H, L, L, L],
}, Function::I2C => [L, L, H, H],
Some(false) => unsafe { Function::PWM => [L, H, L, H],
memory::set_bits(port.pull_down_select(), &pins.map(|bit| bit as u32)); Function::UART => [L, L, L, H],
}, });
None => {
unsafe {
memory::clear_bits(port.pull_up_select(), &pins.map(|bit| bit as u32));
}
unsafe {
memory::clear_bits(port.pull_down_select(), &pins.map(|bit| bit as u32));
}
}
}
match options.function {
Function::Digital => unsafe {
memory::set_bits(port.digital_enable(), &pins.map(|bit| bit as u32));
},
Function::Analog => unsafe {
memory::clear_bits(port.digital_enable(), &pins.map(|bit| bit as u32));
},
_ => todo!(),
}
let data_address = port.data(&pins);
let pins: [ReadablePin; N] = pins.map(|bit| ReadablePin { data_address, bit });
ReadablePins { data_address, pins }
}
pub fn setup_writable_pins<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 { for pin in pins {
let mut memory_bits = [0; 4]; let mut memory_bits = [0; 4];
@@ -254,54 +202,76 @@ pub fn setup_writable_pins<const N: usize>(
memory_bits[i] = memory_bit; 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 { unsafe {
memory::write_bits(port.port_control(), &memory_bits, values); memory::write_bits(port.port_control(), &memory_bits, function_values);
}
}
// Configure pull-up and pull-down resistors
match pull {
Pull::Down => unsafe {
memory::set_bits(port.pull_down_select(), &pins_to_bits(&pins));
},
Pull::Up => unsafe {
memory::set_bits(port.pull_up_select(), &pins_to_bits(&pins));
},
Pull::Neither => {
unsafe {
memory::clear_bits(port.pull_up_select(), &pins_to_bits(&pins));
}
unsafe {
memory::clear_bits(port.pull_down_select(), &pins_to_bits(&pins));
}
} }
} }
// TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states // TODO: check page 671 or 682 (+ more prob) for a table showing initial pin states
// TODO: finish // Disable alternate function when it's not used (and enable it when it is)
match function {
match options.function {
Function::Analog | Function::Digital => unsafe { Function::Analog | Function::Digital => unsafe {
memory::clear_bits( memory::clear_bits(port.alternate_function_select(), &pins_to_bits(&pins));
port.alternate_function_select(),
&pins.map(|bit| bit as u32),
);
}, },
_ => unsafe { _ => unsafe {
memory::set_bits( memory::set_bits(port.alternate_function_select(), &pins_to_bits(&pins));
port.alternate_function_select(),
&pins.map(|bit| bit as u32),
);
}, },
} }
match options.function { // Enable digital function when it's needed (and disable it when it's not)
Function::Digital => unsafe { match function {
memory::set_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); Function::Digital | Function::UART => unsafe {
memory::set_bits(port.digital_enable(), &pins_to_bits(&pins));
}, },
Function::Analog => unsafe { Function::Analog => unsafe {
memory::clear_bits(port.digital_enable(), &pins.map(|bit| bit as u32)); memory::clear_bits(port.digital_enable(), &pins_to_bits(&pins));
}, },
_ => todo!(), _ => todo!(),
} }
}
pub fn setup_readable_pins<const N: usize>(
port: Port,
pins: [Pin; N],
options: ReadablePinOptions,
) -> ReadablePins<N> {
setup_pins(port, pins, false, options.function, options.pull);
let data_address = port.data(&pins); let data_address = port.data(&pins);
let pins: [ReadablePin; N] = pins.map(|bit| ReadablePin { data_address, bit });
ReadablePins { data_address, pins }
}
pub fn setup_writable_pins<const N: usize>(
port: Port,
pins: [Pin; N],
options: WritablePinOptions,
) -> WritablePins<N> {
setup_pins(port, pins, true, options.function, Pull::Neither);
let data_address = port.data(&pins);
let pins: [WritablePin; N] = pins.map(|pin| WritablePin { let pins: [WritablePin; N] = pins.map(|pin| WritablePin {
data_address, data_address,
bit: pin, bit: pin,
}); });
WritablePins { data_address, pins } WritablePins { data_address, pins }
} }

View File

@@ -144,7 +144,7 @@ pub struct UsablePort {
impl UsablePort { impl UsablePort {
pub fn setup_readable_pins<const N: usize>( pub fn setup_readable_pins<const N: usize>(
&self, &mut self,
pins: [Pin; N], pins: [Pin; N],
options: ReadablePinOptions, options: ReadablePinOptions,
) -> ReadablePins<N> { ) -> ReadablePins<N> {
@@ -152,7 +152,7 @@ impl UsablePort {
} }
pub fn setup_writable_pins<const N: usize>( pub fn setup_writable_pins<const N: usize>(
&self, &mut self,
pins: [Pin; N], pins: [Pin; N],
options: WritablePinOptions, options: WritablePinOptions,
) -> WritablePins<N> { ) -> WritablePins<N> {

View File

@@ -1,14 +1,71 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(default_alloc_error_handler)]
use core::{arch::asm, ptr}; use core::{
alloc::{GlobalAlloc, Layout},
arch::asm,
cell::UnsafeCell,
ptr,
};
// Bump pointer allocator for *single* core systems
struct BumpPointerAlloc {
head: UnsafeCell<usize>,
end: usize,
}
unsafe impl Sync for BumpPointerAlloc {}
unsafe impl GlobalAlloc for BumpPointerAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// `interrupt::free` is a critical section that makes our allocator safe
// to use from within interrupts
interrupt::free(|_| {
let head = self.head.get();
let size = layout.size();
let align = layout.align();
let align_mask = !(align - 1);
// move start up to the next alignment boundary
let start = (*head + align - 1) & align_mask;
if start + size > self.end {
// a null pointer signal an Out Of Memory condition
ptr::null_mut()
} else {
*head = start + size;
start as *mut u8
}
})
}
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
// this allocator never deallocates memory
}
}
// Declaration of the global memory allocator
// NOTE the user must ensure that the memory region `[0x2000_0100, 0x2000_0200]`
// is not used by other parts of the program
#[global_allocator]
static HEAP: BumpPointerAlloc = BumpPointerAlloc {
head: UnsafeCell::new(0x2000_0100),
end: 0x2000_0200,
};
#[macro_use]
extern crate alloc;
use alloc::string::String;
use alloc::{format, vec};
use cortex_m::interrupt;
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
use cortex_m_rt::entry; use cortex_m_rt::entry;
use driver_and_task_library::{ use driver_and_task_library::{
setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, UsableBoard, setup_board, Function, Pin, Port, PortOptions, ReadablePinOptions, UsableBoard,
WritablePinOptions, H, L, WritablePinOptions, H, L, Pull,
}; };
const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32; const SYSCTL_RCGC1_R: *mut u32 = 0x400FE104 as *mut u32;
@@ -24,6 +81,18 @@ const UART0_CTL_R: *mut u32 = 0x4000C030 as *mut u32;
const GPIO_PORTA_AFSEL_R: *mut u32 = 0x40004420 as *mut u32; const GPIO_PORTA_AFSEL_R: *mut u32 = 0x40004420 as *mut u32;
const GPIO_PORTA_DEN_R: *mut u32 = 0x4000451C 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 /// UART0 Clock Gating Control
const SYSCTL_RCGC1_UART0: u32 = 0x00000001; const SYSCTL_RCGC1_UART0: u32 = 0x00000001;
/// port A Clock Gating Control /// port A Clock Gating Control
@@ -41,13 +110,14 @@ const UART_FR_RXFE: u32 = 0x00000010;
/// Pins 0 and 1 /// Pins 0 and 1
const PINS_0_AND_1: u32 = 0b0000_0011; const PINS_0_AND_1: u32 = 0b0000_0011;
fn uart0_init(board: UsableBoard) { fn uart0_init(board: &mut UsableBoard) {
unsafe { unsafe {
// activate UART0 // activate UART0
ptr::write_volatile( ptr::write_volatile(
SYSCTL_RCGC1_R, SYSCTL_RCGC1_R,
ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0, ptr::read_volatile(SYSCTL_RCGC1_R) | SYSCTL_RCGC1_UART0,
); );
// activate port A // activate port A
// ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA); // ptr::write_volatile(SYSCTL_RCGC2_R, ptr::read_volatile(SYSCTL_RCGC2_R) | SYSCTL_RCGC2_GPIOA);
// ^ commented in favor of v // ^ commented in favor of v
@@ -113,16 +183,38 @@ fn uart0_out_string(s: &str) {
} }
} }
const RED: [bool; 3] = [H, L, L];
const YELLOW: [bool; 3] = [H, H, L];
const GREEN: [bool; 3] = [L, H, L];
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let board = setup_board(); let mut board = setup_board();
let port_f = board.setup_gpio_port(Port::F, PortOptions); let mut port_a = board.setup_gpio_port(Port::A, PortOptions);
let mut port_f = board.setup_gpio_port(Port::F, PortOptions);
uart0_init(&mut board);
// WIP: page 682
port_a.setup_writable_pins(
[Pin::One],
WritablePinOptions {
function: Function::UART,
},
);
uart0_out_string("Hi, this is after uart setup_writable_pins\r\n\r\n");
// TODO: finish this
// port_a.setup_readable_pins([Pin::Zero], WritablePinOptions {
// function: Function::UART,
// });
// uart0_out_string("Hi, this is after uart setup_readable_pins\r\n\r\n");
let switches = port_f.setup_readable_pins( let switches = port_f.setup_readable_pins(
[Pin::Zero, Pin::Four], [Pin::Zero, Pin::Four],
ReadablePinOptions { ReadablePinOptions {
function: Function::Digital, function: Function::Digital,
pull_up: Some(true), pull: Pull::Up,
}, },
); );
let [_sw1, _sw2] = switches.pins(); let [_sw1, _sw2] = switches.pins();
@@ -134,45 +226,33 @@ fn main() -> ! {
}, },
); );
let white = [H, H, H]; let WHITE = [H, H, H];
let _black = [L, L, L]; let BLACK = [L, L, L];
let red = [H, L, L]; let CYAN = [L, H, H];
let yellow = [H, H, L]; let BLUE = [L, L, H];
let green = [L, H, L]; let MAGENTA = [H, L, H];
let cyan = [L, H, H];
let blue = [L, L, H];
let magenta = [H, L, H];
let rainbow = [red, yellow, green, cyan, blue, magenta]; let rainbow = [RED, YELLOW, GREEN, CYAN, BLUE, MAGENTA];
rgb_led.write_all(cyan); // TODO: WIP: debugging
// let s = format!("Rainbow: {:?}\r\n", rainbow);
uart0_init(board); let s = String::from("\r\ntesting a static string!!!\r\n\r\n\r\n");
// let s = format!("Format");
rgb_led.write_all(white); // let s: String = rainbow.into();
uart0_out_string(&s);
for _ in 0..2 {
for c in [
'H', 'a', 'y', '!', '\r', '\n', 'H', 'e', 'y', '!', '\r', '\n', 'H', 'e', 'y', '!',
'\r', '\n', 'H', 'e', 'y', '!', '\r', '\n',
] {
uart0_out_char(c as u8);
}
}
uart0_out_string("Those example string!\r\n");
loop { loop {
uart0_out_string("Hi the program is still running down here!\r\n");
match switches.read_all() { match switches.read_all() {
[L, L] => { [L, L] => rgb_led.write_all(WHITE),
rgb_led.write_all(white); [L, H] => rgb_led.write_all(BLUE),
uart0_out_string("Hey! You're pressing the button down!\r\n"); [H, L] => rgb_led.write_all(RED),
} [H, H] => rgb_led.write_all(BLACK),
[L, H] => rgb_led.write_all(blue),
[H, L] => rgb_led.write_all(red),
[H, H] => rgb_led.write_all(green),
} }
// uart0_out_string(&format!("The switches read {:?}", switches.read_all()));
for _ in 0..1000000 { for _ in 0..1000000 {
unsafe { unsafe {
asm!("nop"); asm!("nop");